Skip to content

Support immediate binding option - #335

Open
DrXiao wants to merge 2 commits into
sysprog21:masterfrom
DrXiao:support-immediate-binding
Open

Support immediate binding option#335
DrXiao wants to merge 2 commits into
sysprog21:masterfrom
DrXiao:support-immediate-binding

Conversation

@DrXiao

@DrXiao DrXiao commented Sep 9, 2026

Copy link
Copy Markdown
Collaborator

Since the immediate binding has already been implemented for the x86-64 and AArch64 architectures, the proposed changes extend its use by introducing a new "-z" command-line option, allowing the Arm32 and RV32 targets to also generate dynamically linked executables with immediate binding.

For the two 64-bit targets, immediate binding is always used under the dynamic linking mode as is.

The update usage:

# Support the "-z" option
$ qemu-arm -L /usr/arm-linux-gnueabihf/ out/shecc-stage2.elf
Usage: shecc [-o output] [+m] [--dot] [--dump-ir] [--no-libc] [--dynlink] [-z <lazy | now>] [-E] <input.c>
[Error]: Missing source file

# The build system can use the new 'BINDING' variable to determine whether to use immediate binding.
$ make ARCH=arm DYNLINK=1 BINDING=now

TODO:

  • Update the GitHub Actions workflow to validate builds when using immediate binding.

Summary by cubic

Adds a -z option to control dynamic binding: lazy (default) or now (immediate). This lets Arm32 and RV32 targets use immediate binding, which was previously hardcoded for x86-64 and AArch64. The Makefile gains a BINDING variable so builds can pass -z now via make DYNLINK=1 BINDING=now.

Written for commit 0d1e98b. Summary will update on new commits.

Review in cubic

Since the original codebase already implemented the immediate binding
flag for the x86-64 and AArch64 architectures, this commit introduces a
"-z" option so that the Arm32 and RV32 targets can also use immediate
binding.

When the command-line arguments contain "-z now", the compiler sets its
internal flag (imm_binding) to true and generates the
Elf32_Dyn/Elf64_Dyn objects to enable exectuables to perform immediate
binding at runtime.

For 64-bit targets, immediate binding is always used under the dynamic
linking mode as is.
Since the compiler supports the "-z" option for lazy or immediate
binding, a new "BINDING" variable has benn added to the Makefile so that
users can choose which binding mode to use.

For example, users can build dynamically linked compilers with immediate
binding as follows:
$ make DYNLINK=1 BINDING=now

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 issues found across 7 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="Makefile">

<violation number="1" location="Makefile:62">
P2: When a `BINDING=now` build runs `make check`, the test suite still exercises lazy binding. The `check-stage0`/`check-stage2`/`check-abi-*` targets forward only `$(DYNLINK)` to the test drivers, and `tests/driver.sh` compiles its test programs with a plain `--dynlink` (no `-z now`), so on arm/riscv those programs default to lazy binding. With this change `BINDING` becomes a build knob that stage1/stage2 honor, but the tests built by `make check` never verify the immediate-binding path this PR adds. Forward `$(BINDING)` (or a corresponding `-z` flag) to the driver invocations so immediate binding can actually be validated, matching the PR's TODO about CI validation.</violation>
</file>

<file name="src/main.c">

<violation number="1" location="src/main.c:120">
P2: The `-z` handler reads `argv[i + 1]` but never advances `i`, so its value `lazy`/`now` is not consumed and is treated as a positional input on the next loop iteration. Unlike the neighboring `-o` case (which does `i++`), this leaves `argv[i+1]` to hit the trailing `else ... in = argv[i]` branch. As a result, `shecc in.c -z now` first sets `in = "in.c"` and then overwrites it with `"now"`, so the compiler tries to open a file named `now` and fails; and `shecc -z now` with no real input never triggers the "Missing source file" error because `in` is set to `"now"`. Add `i++;` after the value is consumed, matching the `-o` handling.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread Makefile
STAGE0_FLAGS += --dynlink
STAGE1_FLAGS += --dynlink
STAGE0_FLAGS += --dynlink -z $(BINDING)
STAGE1_FLAGS += --dynlink -z $(BINDING)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: When a BINDING=now build runs make check, the test suite still exercises lazy binding. The check-stage0/check-stage2/check-abi-* targets forward only $(DYNLINK) to the test drivers, and tests/driver.sh compiles its test programs with a plain --dynlink (no -z now), so on arm/riscv those programs default to lazy binding. With this change BINDING becomes a build knob that stage1/stage2 honor, but the tests built by make check never verify the immediate-binding path this PR adds. Forward $(BINDING) (or a corresponding -z flag) to the driver invocations so immediate binding can actually be validated, matching the PR's TODO about CI validation.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At Makefile, line 62:

<comment>When a `BINDING=now` build runs `make check`, the test suite still exercises lazy binding. The `check-stage0`/`check-stage2`/`check-abi-*` targets forward only `$(DYNLINK)` to the test drivers, and `tests/driver.sh` compiles its test programs with a plain `--dynlink` (no `-z now`), so on arm/riscv those programs default to lazy binding. With this change `BINDING` becomes a build knob that stage1/stage2 honor, but the tests built by `make check` never verify the immediate-binding path this PR adds. Forward `$(BINDING)` (or a corresponding `-z` flag) to the driver invocations so immediate binding can actually be validated, matching the PR's TODO about CI validation.</comment>

<file context>
@@ -53,12 +53,13 @@ BUILTIN_LIBC_HEADER := c.h
-    STAGE0_FLAGS += --dynlink
-    STAGE1_FLAGS += --dynlink
+    STAGE0_FLAGS += --dynlink -z $(BINDING)
+    STAGE1_FLAGS += --dynlink -z $(BINDING)
 endif
 
</file context>

Comment thread src/main.c
Comment on lines +120 to +130
else if (!strcmp(argv[i], "-z")) {
if (i + 1 >= argc)
usage_error("-z requires \"lazy\" or \"now\"");

if (!strcmp(argv[i + 1], "lazy"))
imm_binding = false;
else if (!strcmp(argv[i + 1], "now"))
imm_binding = true;
else
usage_error("-z requires \"lazy\" or \"now\"");
} else if (!strcmp(argv[i], "-E"))

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: The -z handler reads argv[i + 1] but never advances i, so its value lazy/now is not consumed and is treated as a positional input on the next loop iteration. Unlike the neighboring -o case (which does i++), this leaves argv[i+1] to hit the trailing else ... in = argv[i] branch. As a result, shecc in.c -z now first sets in = "in.c" and then overwrites it with "now", so the compiler tries to open a file named now and fails; and shecc -z now with no real input never triggers the "Missing source file" error because in is set to "now". Add i++; after the value is consumed, matching the -o handling.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/main.c, line 120:

<comment>The `-z` handler reads `argv[i + 1]` but never advances `i`, so its value `lazy`/`now` is not consumed and is treated as a positional input on the next loop iteration. Unlike the neighboring `-o` case (which does `i++`), this leaves `argv[i+1]` to hit the trailing `else ... in = argv[i]` branch. As a result, `shecc in.c -z now` first sets `in = "in.c"` and then overwrites it with `"now"`, so the compiler tries to open a file named `now` and fails; and `shecc -z now` with no real input never triggers the "Missing source file" error because `in` is set to `"now"`. Add `i++;` after the value is consumed, matching the `-o` handling.</comment>

<file context>
@@ -117,7 +117,17 @@ int main(int argc, char *argv[])
         else if (!strcmp(argv[i], "--dynlink"))
             dynlink = true;
-        else if (!strcmp(argv[i], "-E"))
+        else if (!strcmp(argv[i], "-z")) {
+            if (i + 1 >= argc)
+                usage_error("-z requires \"lazy\" or \"now\"");
</file context>
Suggested change
else if (!strcmp(argv[i], "-z")) {
if (i + 1 >= argc)
usage_error("-z requires \"lazy\" or \"now\"");
if (!strcmp(argv[i + 1], "lazy"))
imm_binding = false;
else if (!strcmp(argv[i + 1], "now"))
imm_binding = true;
else
usage_error("-z requires \"lazy\" or \"now\"");
} else if (!strcmp(argv[i], "-E"))
else if (!strcmp(argv[i], "-z")) {
if (i + 1 >= argc)
usage_error("-z requires \"lazy\" or \"now\"");
if (!strcmp(argv[i + 1], "lazy"))
imm_binding = false;
else if (!strcmp(argv[i + 1], "now"))
imm_binding = true;
else
usage_error("-z requires \"lazy\" or \"now\"");
i++;
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant