Made the Cortex-A12, A15 and A17 examples link with an LLVM toolchain (#596)

Those three sample scripts compiled crt0.S and reset.S but named neither on the
link line, and omitted -nostartfiles, so the toolchain was also free to link its
own startup. Under GNU that produced a working image; under an LLVM toolchain
picolibc's crt0 was pulled in and wanted __data_start, __data_source,
__data_size, __bss_size, __stack, __tls_base and __arm32_tls_tcb_offset, none of
which the linker script defines.

Defining picolibc's contract in the shared linker script was tried first and
abandoned: it reaches into ABI constants that cannot be verified here, and it is
unnecessary, because the in-tree crt0.S is already a complete startup for this
script. It sets up the stack and zeroes BSS between __bss_start__ and
__bss_end__, and .data carries no AT() so there is nothing to copy.

So the three scripts now pass -nostartfiles and name crt0.o and reset.o, which
is what the four sibling A profile cores already do and what these scripts were
evidently compiling those files for.

Both the old and the new GNU images contain the in-tree startup, __vectors from
reset.S and _mainCRTStartup from crt0.S, so the startup was already being used
through implicit startup file resolution rather than an explicit operand. How
that resolution happened without the objects being named is not accounted for
here, which is itself the argument for naming them: the same implicit behaviour
does not hold across toolchains, and that is why the LLVM link failed.

Add a readme to each of the three example directories. Their
tx_initialize_low_level.S is the generic ARMv7-A skeleton, 300 lines and
identical across all three, with no interrupt controller programming, no timer
and no vector table installation, where the A5, A7, A8 and A9 examples have all
three and ship the matching Versatile Express support files. These three
therefore demonstrate that the port builds; they will not receive a timer tick.
Nothing in the tree said so, which invites the assumption that they are
equivalent.

Verified with both toolchains for all three cores. GNU links at 41,276 bytes of
text, down from 41,768 because the unused toolchain startup is no longer
included, and Arm Toolchain for Embedded links at 37,982 where it previously
could not link at all. The resulting image is structurally sound: entry at
_start, __vectors at address zero, and a BSS range in RAM. It has not been
executed. scripts/check_clang.sh now links eleven of eleven example builds.

Assisted-by: Claude Code (Opus 5) <noreply@anthropic.com>
This commit is contained in:
Frédéric Desbiens
2026-08-10 17:41:23 -04:00
committed by GitHub
parent a8aebc5206
commit 08eff8061c
7 changed files with 94 additions and 10 deletions
@@ -61,5 +61,5 @@ esac
"${CC}" ${TARGET_FLAGS} -c -g -mcpu=cortex-a12 crt0.S
"${CC}" ${TARGET_FLAGS} -c -g -mcpu=cortex-a12 tx_initialize_low_level.S
"${CC}" ${TARGET_FLAGS} -c -g -mcpu=cortex-a12 -I../../../../common/inc -I../inc sample_threadx.c
"${CC}" ${TARGET_FLAGS} -g -mcpu=cortex-a12 -T sample_threadx.ld ${SYSCALL_LIB} -o sample_threadx.out -Wl,-Map=sample_threadx.map tx_initialize_low_level.o sample_threadx.o tx.a
"${CC}" ${TARGET_FLAGS} -g -nostartfiles -mcpu=cortex-a12 -T sample_threadx.ld ${SYSCALL_LIB} -o sample_threadx.out -Wl,-Map=sample_threadx.map crt0.o reset.o tx_initialize_low_level.o sample_threadx.o tx.a
@@ -0,0 +1,30 @@
# Cortex-A12 GNU example build
This example demonstrates that ThreadX **builds and links** for the Cortex-A12.
It is not a runnable image.
`tx_initialize_low_level.S` here is the generic ARMv7-A skeleton: it provides
the interrupt handler shell but programs no interrupt controller and no timer,
and it does not install a vector table. ThreadX will therefore not receive a
timer tick on this example, so threads that rely on time slicing or on
`tx_thread_sleep()` will not run as intended.
For a model targeted example with a GIC, a private timer and a vector table
installed, see the Cortex-A5, A7, A8 or A9 example builds. Those carry the
matching support files (`MP_GIC`, `MP_PrivateTimer`, `v7.s`) and target the
Versatile Express fixed virtual platforms.
## Building
```sh
./build_threadx.sh # the ThreadX library, tx.a
./build_threadx_sample.sh # the sample image
```
Set `TOOLCHAIN=atfe` to build with Arm Toolchain for Embedded instead of the
GNU toolchain:
```sh
TOOLCHAIN=atfe ATFE_CLANG=/path/to/clang ./build_threadx.sh
TOOLCHAIN=atfe ATFE_CLANG=/path/to/clang ./build_threadx_sample.sh
```
@@ -61,5 +61,5 @@ esac
"${CC}" ${TARGET_FLAGS} -c -g -mcpu=cortex-a15 crt0.S
"${CC}" ${TARGET_FLAGS} -c -g -mcpu=cortex-a15 tx_initialize_low_level.S
"${CC}" ${TARGET_FLAGS} -c -g -mcpu=cortex-a15 -I../../../../common/inc -I../inc sample_threadx.c
"${CC}" ${TARGET_FLAGS} -g -mcpu=cortex-a15 -T sample_threadx.ld ${SYSCALL_LIB} -o sample_threadx.out -Wl,-Map=sample_threadx.map tx_initialize_low_level.o sample_threadx.o tx.a
"${CC}" ${TARGET_FLAGS} -g -nostartfiles -mcpu=cortex-a15 -T sample_threadx.ld ${SYSCALL_LIB} -o sample_threadx.out -Wl,-Map=sample_threadx.map crt0.o reset.o tx_initialize_low_level.o sample_threadx.o tx.a
@@ -0,0 +1,30 @@
# Cortex-A15 GNU example build
This example demonstrates that ThreadX **builds and links** for the Cortex-A15.
It is not a runnable image.
`tx_initialize_low_level.S` here is the generic ARMv7-A skeleton: it provides
the interrupt handler shell but programs no interrupt controller and no timer,
and it does not install a vector table. ThreadX will therefore not receive a
timer tick on this example, so threads that rely on time slicing or on
`tx_thread_sleep()` will not run as intended.
For a model targeted example with a GIC, a private timer and a vector table
installed, see the Cortex-A5, A7, A8 or A9 example builds. Those carry the
matching support files (`MP_GIC`, `MP_PrivateTimer`, `v7.s`) and target the
Versatile Express fixed virtual platforms.
## Building
```sh
./build_threadx.sh # the ThreadX library, tx.a
./build_threadx_sample.sh # the sample image
```
Set `TOOLCHAIN=atfe` to build with Arm Toolchain for Embedded instead of the
GNU toolchain:
```sh
TOOLCHAIN=atfe ATFE_CLANG=/path/to/clang ./build_threadx.sh
TOOLCHAIN=atfe ATFE_CLANG=/path/to/clang ./build_threadx_sample.sh
```
@@ -61,5 +61,5 @@ esac
"${CC}" ${TARGET_FLAGS} -c -g -mcpu=cortex-a17 crt0.S
"${CC}" ${TARGET_FLAGS} -c -g -mcpu=cortex-a17 tx_initialize_low_level.S
"${CC}" ${TARGET_FLAGS} -c -g -mcpu=cortex-a17 -I../../../../common/inc -I../inc sample_threadx.c
"${CC}" ${TARGET_FLAGS} -g -mcpu=cortex-a17 -T sample_threadx.ld ${SYSCALL_LIB} -o sample_threadx.out -Wl,-Map=sample_threadx.map tx_initialize_low_level.o sample_threadx.o tx.a
"${CC}" ${TARGET_FLAGS} -g -nostartfiles -mcpu=cortex-a17 -T sample_threadx.ld ${SYSCALL_LIB} -o sample_threadx.out -Wl,-Map=sample_threadx.map crt0.o reset.o tx_initialize_low_level.o sample_threadx.o tx.a
@@ -0,0 +1,30 @@
# Cortex-A17 GNU example build
This example demonstrates that ThreadX **builds and links** for the Cortex-A17.
It is not a runnable image.
`tx_initialize_low_level.S` here is the generic ARMv7-A skeleton: it provides
the interrupt handler shell but programs no interrupt controller and no timer,
and it does not install a vector table. ThreadX will therefore not receive a
timer tick on this example, so threads that rely on time slicing or on
`tx_thread_sleep()` will not run as intended.
For a model targeted example with a GIC, a private timer and a vector table
installed, see the Cortex-A5, A7, A8 or A9 example builds. Those carry the
matching support files (`MP_GIC`, `MP_PrivateTimer`, `v7.s`) and target the
Versatile Express fixed virtual platforms.
## Building
```sh
./build_threadx.sh # the ThreadX library, tx.a
./build_threadx_sample.sh # the sample image
```
Set `TOOLCHAIN=atfe` to build with Arm Toolchain for Embedded instead of the
GNU toolchain:
```sh
TOOLCHAIN=atfe ATFE_CLANG=/path/to/clang ./build_threadx.sh
TOOLCHAIN=atfe ATFE_CLANG=/path/to/clang ./build_threadx_sample.sh
```
+1 -7
View File
@@ -150,13 +150,7 @@ C_CORES="cortex_m0 cortex_m4 cortex_m23 cortex_m33 cortex_m55 cortex_a7 cortex_a
# These fail with the GNU toolchain too, so they are not LLVM problems:
# arm9 arm11 need newlib multilib variants for those CPUs, which are
# cortex_r4 cortex_r5 not present in every GNU toolchain packaging.
#
# This one is specific to LLVM:
# cortex_a12 a15 a17 their link line omits -nostartfiles, so the toolchain's
# own crt0 is linked, and it needs picolibc's
# __data_start, __data_source, __data_size and __bss_size,
# which the example's linker script does not define.
EXAMPLES_EXPECTED_TO_FAIL="arm9 arm11 cortex_r4 cortex_r5 cortex_a12 cortex_a15 cortex_a17"
EXAMPLES_EXPECTED_TO_FAIL="arm9 arm11 cortex_r4 cortex_r5"
failures=0
skipped=""