-
Notifications
You must be signed in to change notification settings - Fork 170
Support immediate binding option #335
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
35b21a9
0bf54df
ba1aa7d
c4fbf69
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -21,7 +21,7 @@ jobs: | |||||
| # Bootstrap each target and run the consolidated behavioral suite against | ||||||
| # the stage 0 and stage 2 compilers. | ||||||
| host-x86: | ||||||
| name: ${{ matrix.architecture }}/${{ matrix.link_mode }} (${{ matrix.compiler }}) | ||||||
| name: ${{ matrix.architecture }}/${{ matrix.link_mode }}/${{ matrix.link_mode == 'dynamic' && (matrix.binding_mode == 'immediate' && 'immediate' || 'default') || 'none' }} (${{ matrix.compiler }}) | ||||||
| runs-on: ubuntu-24.04 | ||||||
| timeout-minutes: 30 | ||||||
| strategy: | ||||||
|
|
@@ -32,10 +32,28 @@ jobs: | |||||
| compiler: [gcc, clang] | ||||||
| architecture: [arm, arm64, riscv, x64] | ||||||
| link_mode: [static, dynamic] | ||||||
| include: | ||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. An |
||||||
| - compiler: gcc | ||||||
| architecture: arm | ||||||
| link_mode: dynamic | ||||||
| binding_mode: immediate | ||||||
| - compiler: clang | ||||||
| architecture: arm | ||||||
| link_mode: dynamic | ||||||
| binding_mode: immediate | ||||||
| - compiler: gcc | ||||||
| architecture: riscv | ||||||
| link_mode: dynamic | ||||||
| binding_mode: immediate | ||||||
| - compiler: clang | ||||||
| architecture: riscv | ||||||
| link_mode: dynamic | ||||||
| binding_mode: immediate | ||||||
| env: | ||||||
| CC: ${{ matrix.compiler }} | ||||||
| ARCH: ${{ matrix.architecture }} | ||||||
| DYNLINK: ${{ matrix.link_mode == 'dynamic' && '1' || '0' }} | ||||||
| BINDING: ${{ matrix.binding_mode == 'immediate' && 'now' || 'lazy' }} | ||||||
| steps: | ||||||
| - name: Checkout code | ||||||
| uses: actions/checkout@v7 | ||||||
|
|
@@ -49,14 +67,14 @@ jobs: | |||||
| # environment: the build session the tree records assigns ARCH outright, | ||||||
| # and a makefile assignment wins over the environment. | ||||||
| - name: Build artifacts | ||||||
| run: make ARCH="$ARCH" DYNLINK="$DYNLINK" | ||||||
| run: make ARCH="$ARCH" DYNLINK="$DYNLINK" BINDING="$BINDING" | ||||||
| - name: Unit tests | ||||||
| run: make check ARCH="$ARCH" DYNLINK="$DYNLINK" | ||||||
| run: make check ARCH="$ARCH" DYNLINK="$DYNLINK" BINDING="$BINDING" | ||||||
| - name: Upload the test logs | ||||||
| if: failure() | ||||||
| uses: actions/upload-artifact@v7 | ||||||
| with: | ||||||
| name: logs-${{ matrix.compiler }}-${{ matrix.architecture }}-${{ matrix.link_mode }} | ||||||
| name: logs-${{ matrix.compiler }}-${{ matrix.architecture }}-${{ matrix.link_mode }}-${{ matrix.link_mode == 'dynamic' && (matrix.binding_mode == 'immediate' && 'immediate' || 'default') || 'none' }} | ||||||
| path: | | ||||||
| out/*.log | ||||||
| if-no-files-found: ignore | ||||||
|
|
@@ -68,7 +86,7 @@ jobs: | |||||
| # sanitizer step of host-x86 used to do. Building "sanitizer" first, in a | ||||||
| # job that builds nothing else, is what puts the instrumentation in. | ||||||
| sanitizer: | ||||||
| name: Sanitizers ${{ matrix.architecture }}/${{ matrix.link_mode }} | ||||||
| name: Sanitizers ${{ matrix.architecture }}/${{ matrix.link_mode }}/${{ matrix.link_mode == 'dynamic' && (matrix.binding_mode == 'immediate' && 'immediate' || 'default') || 'none' }} | ||||||
| runs-on: ubuntu-24.04 | ||||||
| timeout-minutes: 30 | ||||||
| strategy: | ||||||
|
|
@@ -82,9 +100,17 @@ jobs: | |||||
| # why first. | ||||||
| architecture: [arm, arm64, riscv, x64] | ||||||
| link_mode: [static, dynamic] | ||||||
| include: | ||||||
| - architecture: arm | ||||||
| link_mode: dynamic | ||||||
| binding_mode: immediate | ||||||
| - architecture: riscv | ||||||
| link_mode: dynamic | ||||||
| binding_mode: immediate | ||||||
| env: | ||||||
| ARCH: ${{ matrix.architecture }} | ||||||
| DYNLINK: ${{ matrix.link_mode == 'dynamic' && '1' || '0' }} | ||||||
| BINDING: ${{ matrix.binding_mode == 'immediate' && 'now' || 'lazy' }} | ||||||
| steps: | ||||||
| - name: Checkout code | ||||||
| uses: actions/checkout@v7 | ||||||
|
|
@@ -95,9 +121,9 @@ jobs: | |||||
| link-mode: ${{ matrix.link_mode }} | ||||||
| github-token: ${{ github.token }} | ||||||
| - name: Build the stage 0 compiler with sanitizers | ||||||
| run: make sanitizer ARCH="$ARCH" DYNLINK="$DYNLINK" | ||||||
| run: make sanitizer ARCH="$ARCH" DYNLINK="$DYNLINK" BINDING="$BINDING" | ||||||
| - name: Sanitizer-enabled stage 0 tests | ||||||
| run: make check-sanitizer ARCH="$ARCH" DYNLINK="$DYNLINK" | ||||||
| run: make check-sanitizer ARCH="$ARCH" DYNLINK="$DYNLINK" BINDING="$BINDING" | ||||||
|
|
||||||
| # Preprocess shecc with itself, then compile the result: the stage 1 source | ||||||
| # is the largest input the preprocessor gets, and the only one that exercises | ||||||
|
|
@@ -135,17 +161,22 @@ jobs: | |||||
| # AArch64 that is the only place the real loader is exercised: QEMU-user maps | ||||||
| # the image itself, and on an x86-64 host it always presents 4 KiB pages. | ||||||
| host-arm: | ||||||
| name: ${{ matrix.architecture }}/${{ matrix.link_mode }} on Arm64 | ||||||
| name: ${{ matrix.architecture }}/${{ matrix.link_mode }}/${{ matrix.link_mode == 'dynamic' && (matrix.binding_mode == 'immediate' && 'immediate' || 'default') || 'none' }} on Arm64 | ||||||
| runs-on: ubuntu-24.04-arm | ||||||
| timeout-minutes: 30 | ||||||
| strategy: | ||||||
| fail-fast: false | ||||||
| matrix: | ||||||
| architecture: [arm, arm64] | ||||||
| link_mode: [static, dynamic] | ||||||
| include: | ||||||
| - architecture: arm | ||||||
| link_mode: dynamic | ||||||
| binding_mode: immedaite | ||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
| env: | ||||||
| ARCH: ${{ matrix.architecture }} | ||||||
| DYNLINK: ${{ matrix.link_mode == 'dynamic' && '1' || '0' }} | ||||||
| BINDING: ${{ matrix.binding_mode == 'immediate' && 'now' || 'lazy' }} | ||||||
| steps: | ||||||
| - name: Checkout code | ||||||
| uses: actions/checkout@v7 | ||||||
|
|
@@ -156,14 +187,14 @@ jobs: | |||||
| link-mode: ${{ matrix.link_mode }} | ||||||
| github-token: ${{ github.token }} | ||||||
| - name: Build artifacts | ||||||
| run: make ARCH="$ARCH" DYNLINK="$DYNLINK" | ||||||
| run: make ARCH="$ARCH" DYNLINK="$DYNLINK" BINDING="$BINDING" | ||||||
| - name: Unit tests | ||||||
| run: make check ARCH="$ARCH" DYNLINK="$DYNLINK" | ||||||
| run: make check ARCH="$ARCH" DYNLINK="$DYNLINK" BINDING="$BINDING" | ||||||
| - name: Upload the test logs | ||||||
| if: failure() | ||||||
| uses: actions/upload-artifact@v7 | ||||||
| with: | ||||||
| name: logs-arm64-host-${{ matrix.architecture }}-${{ matrix.link_mode }} | ||||||
| name: logs-arm64-host-${{ matrix.architecture }}-${{ matrix.link_mode }}-${{ matrix.link_mode == 'dynamic' && (matrix.binding_mode == 'immediate' && 'immediate' || 'default') || 'none' }} | ||||||
| path: | | ||||||
| out/*.log | ||||||
| out/tests/*.log | ||||||
|
|
@@ -174,15 +205,19 @@ jobs: | |||||
| # build that produces the object files, and that job has already made them | ||||||
| # without instrumentation. | ||||||
| host-arm-sanitizer: | ||||||
| name: Sanitizers arm/${{ matrix.link_mode }} on Arm64 | ||||||
| name: Sanitizers arm/${{ matrix.link_mode }}/${{ matrix.link_mode == 'dynamic' && (matrix.binding_mode == 'immediate' && 'immediate' || 'default') || 'none' }} on Arm64 | ||||||
| runs-on: ubuntu-24.04-arm | ||||||
| timeout-minutes: 30 | ||||||
| strategy: | ||||||
| fail-fast: false | ||||||
| matrix: | ||||||
| link_mode: [static, dynamic] | ||||||
| include: | ||||||
| - link_mode: dynamic | ||||||
| binding_mode: immediate | ||||||
| env: | ||||||
| DYNLINK: ${{ matrix.link_mode == 'dynamic' && '1' || '0' }} | ||||||
| BINDING: ${{ matrix.binding_mode == 'immediate' && 'now' || 'lazy' }} | ||||||
| steps: | ||||||
| - name: Checkout code | ||||||
| uses: actions/checkout@v7 | ||||||
|
|
@@ -193,9 +228,9 @@ jobs: | |||||
| link-mode: ${{ matrix.link_mode }} | ||||||
| github-token: ${{ github.token }} | ||||||
| - name: Build the stage 0 compiler with sanitizers | ||||||
| run: make sanitizer ARCH=arm DYNLINK="$DYNLINK" | ||||||
| run: make sanitizer ARCH=arm DYNLINK="$DYNLINK" BINDING="$BINDING" | ||||||
| - name: Sanitizer-enabled stage 0 tests | ||||||
| run: make check-sanitizer ARCH=arm DYNLINK="$DYNLINK" | ||||||
| run: make check-sanitizer ARCH=arm DYNLINK="$DYNLINK" BINDING="$BINDING" | ||||||
|
|
||||||
| coding-style: | ||||||
| name: Coding style | ||||||
|
|
||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -84,12 +84,13 @@ TRANSLATION_DEFS = "\#define SHECC_TRANSLATION_DATE \"$(TRANSLATION_DATE)\"\n\#d | |
| STAGE0_FLAGS ?= --dump-ir | ||
| STAGE1_FLAGS ?= | ||
| DYNLINK ?= 0 | ||
| BINDING ?= lazy | ||
|
|
||
| COMMENTFLOW ?= commentflow | ||
| SHFMT ?= shfmt | ||
| ifeq ($(DYNLINK),1) | ||
| STAGE0_FLAGS += --dynlink | ||
| STAGE1_FLAGS += --dynlink | ||
| STAGE0_FLAGS += --dynlink -z $(BINDING) | ||
| STAGE1_FLAGS += --dynlink -z $(BINDING) | ||
|
cubic-dev-ai[bot] marked this conversation as resolved.
|
||
| endif | ||
|
|
||
| SRCS := $(wildcard $(patsubst %,%/main.c, $(SRCDIR))) | ||
|
|
@@ -236,11 +237,11 @@ uninstall-hooks: | |
|
|
||
| check-stage0: $(OUT)/$(STAGE0) tests/driver.sh | ||
| $(VECHO) " TEST STAGE 0\n" | ||
| tests/driver.sh 0 $(DYNLINK) | ||
| tests/driver.sh 0 $(DYNLINK) $(BINDING) | ||
|
|
||
| check-stage2: $(OUT)/$(STAGE2) tests/driver.sh | ||
| $(VECHO) " TEST STAGE 2\n" | ||
| tests/driver.sh 2 $(DYNLINK) | ||
| tests/driver.sh 2 $(DYNLINK) $(BINDING) | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
|
|
||
| check-sanitizer: $(OUT)/$(STAGE0)-sanitizer tests/driver.sh | ||
| $(VECHO) " TEST STAGE 0 (with sanitizers)\n" | ||
|
|
@@ -249,10 +250,10 @@ check-sanitizer: $(OUT)/$(STAGE0)-sanitizer tests/driver.sh | |
| $(Q)rm $(OUT)/shecc | ||
|
|
||
| check-abi-stage0: $(OUT)/$(STAGE0) | ||
| tests/$(ARCH)-abi.sh 0 $(DYNLINK); | ||
| tests/$(ARCH)-abi.sh 0 $(DYNLINK) $(BINDING); | ||
|
|
||
| check-abi-stage2: $(OUT)/$(STAGE2) | ||
| tests/$(ARCH)-abi.sh 2 $(DYNLINK); | ||
| tests/$(ARCH)-abi.sh 2 $(DYNLINK) $(BINDING); | ||
|
|
||
| # Both prerequisites are order-only, and both exist because "make -j" would | ||
| # otherwise let a compile start beside the thing it reads. Selecting a target | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1112,14 +1112,17 @@ void elf_generate_dynamic_sections(void) | |
| elf_write_dyn(dynamic_sections.elf_dynamic, 0x1, 0x1); | ||
| if (libdl_name) | ||
| elf_write_dyn(dynamic_sections.elf_dynamic, 0x1, libdl_name); | ||
| #if DYN_BIND_NOW == 1 | ||
|
|
||
| /* Resolve every PLT entry at load time. This target's PLT[0] does not | ||
| * arrange the GOT[1]/GOT[2] hand-off the lazy resolver needs, so the loader | ||
| * writes the final addresses straight into the GOT instead. | ||
| */ | ||
| elf_write_dyn(dynamic_sections.elf_dynamic, 0x18, 0x0); /* DT_BIND_NOW */ | ||
| elf_write_dyn(dynamic_sections.elf_dynamic, 0x1e, 0x8); /* DF_BIND_NOW */ | ||
| #endif | ||
| if (imm_binding) { | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The comment above this branch still states the old compile-time rule. On Arm32 and RV32 the PLT does arrange the
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @jserv I would like to ask about the x64 and Arm64 implementations before improving this pull request. In the Since I wasn't involved in the review of the related pull requests, could you clarify why these targets are forced to use immediate binding?
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
By the way, the x64 and Arm64 are supported, but the documentation hasn't been updated to explain the implementation considerations. I can help update the documentation in a separate pull request.
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I was standardizing the behavior across all backends. Feel free to consolidate the linkage logic as well. |
||
| elf_write_dyn(dynamic_sections.elf_dynamic, 0x18, | ||
| 0x0); /* DT_BIND_NOW */ | ||
| elf_write_dyn(dynamic_sections.elf_dynamic, 0x1e, | ||
| 0x8); /* DF_BIND_NOW */ | ||
| } | ||
| elf_write_dyn(dynamic_sections.elf_dynamic, 0x0, 0x0); | ||
| } | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -121,7 +121,18 @@ int main(int argc, char *argv[]) | |
| libc = false; | ||
| 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\""); | ||
|
|
||
| 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++; | ||
| } else if (!strcmp(argv[i], "-E")) | ||
|
cubic-dev-ai[bot] marked this conversation as resolved.
|
||
| expand_only = true; | ||
| else if (!strcmp(argv[i], "-I")) { | ||
| if (i + 1 >= argc) | ||
|
|
@@ -145,11 +156,22 @@ int main(int argc, char *argv[]) | |
| in = argv[i]; | ||
| } | ||
|
|
||
| if (dynlink) { | ||
| switch (ELF_MACHINE) { | ||
| /* The following 64-bit targets have no lazy-resolution path, so | ||
| * immediate binding must be used. | ||
| */ | ||
| case ELF_MACHINE_X86_64: | ||
| case ELF_MACHINE_AARCH64: | ||
| imm_binding = true; | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. An explicit |
||
| } | ||
| } | ||
|
|
||
| if (!in) { | ||
| printf( | ||
| "Usage: shecc [-I directory] [-o output] [+m] [--dot] [--dump-ir] " | ||
| "[--warn-string-literals] [--std=c99] [--no-libc] " | ||
| "[--dynlink] [-E] <input.c>\n"); | ||
| "[--dynlink] [-z <lazy | now>] [-E] <input.c>\n"); | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The usage string gains |
||
| usage_error("Missing source file"); | ||
| } | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -106,7 +106,7 @@ case "$1" in | |||||
| esac | ||||||
|
|
||||||
| if [ $# -ge 2 ] && [ "$2" = "1" ]; then | ||||||
| readonly SHECC_CFLAGS="--dynlink" | ||||||
| readonly SHECC_CFLAGS="--dynlink ${3:-lazy}" | ||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
| readonly LINK_MODE="dynamic" | ||||||
| else | ||||||
| readonly SHECC_CFLAGS="" | ||||||
|
|
||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Naming:
<arch>/static/none.<arch>/dynamic/<default or immediate>The default binding mode for each architecture is as follows: