Support immediate binding option - #335
Conversation
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
There was a problem hiding this comment.
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
| STAGE0_FLAGS += --dynlink | ||
| STAGE1_FLAGS += --dynlink | ||
| STAGE0_FLAGS += --dynlink -z $(BINDING) | ||
| STAGE1_FLAGS += --dynlink -z $(BINDING) |
There was a problem hiding this comment.
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>
| 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")) |
There was a problem hiding this comment.
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>
| 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++; | |
| } |
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:
TODO:
Summary by cubic
Adds a
-zoption to control dynamic binding:lazy(default) ornow(immediate). This lets Arm32 and RV32 targets use immediate binding, which was previously hardcoded for x86-64 and AArch64. The Makefile gains aBINDINGvariable so builds can pass-z nowviamake DYNLINK=1 BINDING=now.Written for commit 0d1e98b. Summary will update on new commits.