Fixed the AArch64 samples, none of which had ever linked with GCC - #673
Merged
Merged
Conversation
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>
This was referenced Aug 28, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Every AArch64
gnuexample build fails at the sample link — all 27 of them, 13 underports/and 14 underports_smp/:Cause
build_threadx_sample.shlinks with-nostartfiles, which is right for a port carrying its own reset path — and which also dropscrti.oandcrtn.o, the objects that define_initand_fini.sample_threadx/startup.S:690calls__libc_init_arrayby design, and newlib's implementation of it calls_init.The linker script already has
.initand.finioutput sections; nothing was contributing to them.The AArch32 scripts are unaffected — they use
--specs=nosys.specsand never reach__libc_init_array. That is why only AArch64 is broken.Fix
Link
crti.oandcrtn.oexplicitly, bracketing the object list. Their position is load-bearing, not stylistic:crti.omust precede every other.initcontribution andcrtn.omust follow all of them, which is how the prologue and epilogue of_initend 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 tonosys.specs, and dropping-nostartfiles. None is right:PROVIDEwould point_initat whatever section follows and fall through into it,nosys.specswould take away the semihosting thatstartup.Sexplicitly initialises, and-nostartfilesis correct for this port. Linking the two objects back is the minimal change that keeps every existing property.The
atfebranch sets both to empty, deliberately. picolibc's__libc_init_arraydoes not call_init, those 27 images link today, and addingcrti.owould change a working link for no reason. That is also whycheck_clang.shis green on these and does not carry them on itsEXAMPLES_EXPECTED_TO_FAILlist: 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 theports/andports_smp/copies, then regenerated withupdate.sh --port-sets tx,tx_smp --copy-common-files --copy-port-files --copy-example --patch-files. The 27 generated copies are in this PR becauseports_arch_checkcompares them.Verification
aarch64-none-elf-gcc14.3.rel1check_clang.sh(ATfE 22.1.0), all five stagescheck_ports.shincluding the reproducibility check_initand_finidisassemble to exactly what they should — thecrtiprologue, thecrtnepilogue, and aret: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, andcheck_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.