Skip to content

Fixed the AArch64 samples, none of which had ever linked with GCC - #673

Merged
fdesbiens merged 1 commit into
eclipse-threadx:devfrom
fdesbiens:fix/aarch64-init-fini
Aug 28, 2026
Merged

Fixed the AArch64 samples, none of which had ever linked with GCC#673
fdesbiens merged 1 commit into
eclipse-threadx:devfrom
fdesbiens:fix/aarch64-init-fini

Conversation

@fdesbiens

Copy link
Copy Markdown
Contributor

Every AArch64 gnu example build fails at the sample link — all 27 of them, 13 under ports/ and 14 under ports_smp/:

libg.a(libc_a-init.o): in function `__libc_init_array':
    undefined reference to `_init'
    relocation truncated to fit: R_AARCH64_CALL26 against undefined symbol `_init'
libg.a(libc_a-fini.o): in function `__libc_fini_array':
    undefined reference to `_fini'

Cause

build_threadx_sample.sh links with -nostartfiles, which is right for a port carrying its own reset path — and which also drops crti.o and crtn.o, the objects that define _init and _fini. sample_threadx/startup.S:690 calls __libc_init_array by design, and newlib's implementation of it calls _init.

The linker script already has .init and .fini output sections; nothing was contributing to them.

The AArch32 scripts are unaffected — they use --specs=nosys.specs and never reach __libc_init_array. That is why only AArch64 is broken.

Fix

Link crti.o and crtn.o explicitly, bracketing the object list. Their position is load-bearing, not stylistic: crti.o must precede every other .init contribution and crtn.o must follow all of them, which is how the prologue and epilogue of _init end up in the right order. Both paths come from the compiler's own -print-file-name, so nothing here hard-codes a toolchain layout.

The three candidates in the plan for this were PROVIDE(_init = .) in the linker script, switching to nosys.specs, and dropping -nostartfiles. None is right: PROVIDE would point _init at whatever section follows and fall through into it, nosys.specs would take away the semihosting that startup.S explicitly initialises, and -nostartfiles is correct for this port. Linking the two objects back is the minimal change that keeps every existing property.

The atfe branch sets both to empty, deliberately. picolibc's __libc_init_array does not call _init, those 27 images link today, and adding crti.o would change a working link for no reason. That is also why check_clang.sh is green on these and does not carry them on its EXAMPLES_EXPECTED_TO_FAIL list: the LLVM path never reached the gap, so nothing has ever linked them and failed.

Where

Fixed in ports_arch/ARMv8-A/threadx/ports/gnu/example_build/build_threadx_sample.sh, the single source for both the ports/ and ports_smp/ copies, then regenerated with update.sh --port-sets tx,tx_smp --copy-common-files --copy-port-files --copy-example --patch-files. The 27 generated copies are in this PR because ports_arch_check compares them.

Verification

before after
AArch64 samples linking with aarch64-none-elf-gcc 14.3.rel1 0 of 27 27 of 27
check_clang.sh (ATfE 22.1.0), all five stages green green
check_ports.sh including the reproducibility check green green

_init and _fini disassemble to exactly what they should — the crti prologue, the crtn epilogue, and a ret:

0000000080001f84 <_init>:
    stp x29, x30, [sp, #-16]!    ... (crti.o)
    ldp x19, x20, [sp], #16      ... (crtn.o)
    ret

Regression tests

None. These are link-only example images that no host test executes. What guards them is check_clang.sh's example stage today, and check_gcc.sh's, which is the next change and is the reason this was found — a fifteen-minute probe while sizing a GCC port check turned it up, having gone unnoticed because nothing has ever linked these with GCC.

Every AArch64 gnu example build failed at the sample link, all 27 of them --
13 under ports/ and 14 under ports_smp/:

  libg.a(libc_a-init.o): in function `__libc_init_array':
      undefined reference to `_init'
      relocation truncated to fit: R_AARCH64_CALL26 against undefined
          symbol `_init'
  libg.a(libc_a-fini.o): in function `__libc_fini_array':
      undefined reference to `_fini'

build_threadx_sample.sh links with -nostartfiles, which is correct for a port
carrying its own reset path, and that drops crti.o and crtn.o along with
everything else. startup.S calls __libc_init_array by design, and newlib's
implementation calls _init, which crti.o is what defines. The AArch32 scripts
are unaffected: they use nosys.specs and never reach __libc_init_array.

The fix links crti.o and crtn.o explicitly, bracketing the object list -- the
first must precede every .init contribution and the second must follow all of
them, so their position is load-bearing rather than stylistic. Both paths come
from the compiler's own -print-file-name, so nothing here hard-codes a
toolchain layout.

The atfe branch sets both to empty, deliberately: picolibc's __libc_init_array
does not call _init, those 27 images link today, and adding crti.o would change
a working link for no reason. That is also why check_clang.sh is green on these
and does not list them as expected to fail -- the LLVM path never reached the
gap, so nothing has ever linked them and failed.

Fixed in ports_arch/ARMv8-A/threadx/ports/gnu/example_build, which is the
single source for both the ports/ and ports_smp/ copies, then regenerated with
update.sh --port-sets tx,tx_smp. The 27 generated copies are in this commit
because ports_arch_check compares them.

Verified: all 27 link with arm-gnu-toolchain 14.3.rel1 aarch64-none-elf, where
0 of 27 did before; _init and _fini disassemble to the expected crti prologue
and crtn epilogue over a ret; check_clang.sh with ATfE 22.1.0 is still green on
all five stages, including the 42 script-driven example builds; check_ports.sh
is green including the reproducibility check.

No regression test: these are link-only example images that no host test
executes. What guards them is check_clang.sh's example stage today, and
check_gcc.sh's, which is the next change and is the reason this was found.

Assisted-by: Claude Code (Opus 5) <noreply@anthropic.com>
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