From 635f3455f26250d352bcd421637c966e6bf9f0ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Desbiens?= Date: Wed, 26 Aug 2026 09:54:17 -0400 Subject: [PATCH 1/4] Assembled the module ports, which no check had ever compiled scripts/check_clang.sh globbed ports_module/*/gnu/src, which does not exist -- the module ports keep their assembly in module_manager/src. The [ -d ] guard skipped it in silence, so 116 assembly files across nine Arm module ports were assembled by no check, with either compiler, in the script whose own comments state three times that "a port that is simply absent from the count reads as covered". Stage 1 goes from 724 of 724 to 840 of 840; the feature-macro stage had the same gap and goes from 412 files to 469. Correcting the path exposed five defects, and only one of them was a build failure. The other four assembled cleanly and did the wrong thing, because GAS runs the C preprocessor on .S and not on .s: ports_smp/cortex_a7_smp/gnu/src/tx_thread_smp_unprotect.s, the only .s in a directory of twenty-one .S, ignored all four of its own feature macros. It wrote the caller's LR into the protection structure on every unprotect -- a store guarded by TX_MPCORE_DEBUG_ENABLE -- sent an unconditional SEV, and returned through both BX lr and MOV pc, lr. Its cortex_a5_smp and cortex_a9_smp siblings are .S. ports_module/cortex_m33/.../tx_thread_stack_build.s emitted both arms of an #ifdef TX_SINGLE_MODE_SECURE, so the non-secure LR value overwrote the secure one and the secure build got the wrong frame. ports_module/cortex_m23/.../tx_thread_context_{save,restore}.S carried the POP {r0, lr} that check_clang.sh's own comment describes as the reason the feature-macro stage exists. The 16-bit Thumb POP takes r0-r7 and pc only. The identical fix already sits in ports/cortex_m23/gnu/src; the module copy never got it because nothing scanned it. ports_module/cortex_m23/.../tx_thread_secure_stack_initialize.S used MOV rather than MOVS for an 8-bit immediate, latent behind TX_SINGLE_MODE_SECURE. Both siblings in the same directory already use MOVS. ports_module/cortex_a7/gnu/module_manager/src is the one that failed to assemble, on GCC 14.3 as well as on LLVM: #define SYS_MODE was never expanded, so #SYS_MODE reached the assembler as an undefined symbol. Twenty-nine .s files under gnu trees are renamed to .S. Every one of them is already named .S by the build scripts that compile it, so this repairs those scripts rather than churning them -- ports_module/cortex_a7's build_threadx.bat names all eighteen with a capital S, and works today only on a case-insensitive filesystem. Renaming rather than converting the #defines to GNU assignments is what fixes the #ifdef blocks as well as the constants; the assignments would have fixed two files and left twenty-seven silently ignoring their macros. Files with no preprocessor directives are left as .s: they are not broken, and check_ports.sh gains a check that keeps them that way. Only the gnu trees are checked there -- the IAR, Arm Compiler 5 and Keil assemblers preprocess .s themselves, and about three hundred files in this repository rely on that. Verified with both toolchains on the same tree: 840 of 840 assembled by ATfE 22.1.0 and by arm-gnu-toolchain 14.3.rel1, all five stages of check_clang.sh green, and check_ports.sh green including the reproducibility check. The new check was shown to fail by planting a copy of the file it was written for. No regression test accompanies this. The assembly it covers is executed by no host test, and the check itself going from 724 files to 840 is the coverage AGENTS.md asks for -- together with the new check_ports.sh section, which is what stops the class recurring. Assisted-by: Claude Code (Opus 5) --- ..._low_level.s => tx_initialize_low_level.S} | 0 ..._restore.s => tx_thread_context_restore.S} | 0 ...ontext_save.s => tx_thread_context_save.S} | 0 ...tore.s => tx_thread_fiq_context_restore.S} | 0 ...xt_save.s => tx_thread_fiq_context_save.S} | 0 ...ting_end.s => tx_thread_fiq_nesting_end.S} | 0 ..._start.s => tx_thread_fiq_nesting_start.S} | 0 ...ontrol.s => tx_thread_interrupt_control.S} | 0 ...isable.s => tx_thread_interrupt_disable.S} | 0 ...estore.s => tx_thread_interrupt_restore.S} | 0 ...ting_end.s => tx_thread_irq_nesting_end.S} | 0 ..._start.s => tx_thread_irq_nesting_start.S} | 0 ...thread_schedule.s => tx_thread_schedule.S} | 0 ..._stack_build.s => tx_thread_stack_build.S} | 0 ...tem_return.s => tx_thread_system_return.S} | 0 ...ve.s => tx_thread_vectored_context_save.S} | 0 ...timer_interrupt.s => tx_timer_interrupt.S} | 0 ...> txm_module_manager_thread_stack_build.S} | 0 ...s => txm_module_manager_user_mode_entry.S} | 0 .../src/tx_initialize_low_level.S | 4 +- .../src/tx_thread_context_restore.S | 11 +++- .../src/tx_thread_context_save.S | 11 +++- .../src/tx_thread_secure_stack_initialize.S | 4 +- ..._restore.s => tx_thread_context_restore.S} | 0 ...ontext_save.s => tx_thread_context_save.S} | 0 ...ontrol.s => tx_thread_interrupt_control.S} | 0 ...isable.s => tx_thread_interrupt_disable.S} | 0 ...estore.s => tx_thread_interrupt_restore.S} | 0 ..._stack_build.s => tx_thread_stack_build.S} | 0 ...tem_return.s => tx_thread_system_return.S} | 0 ...> txm_module_manager_thread_stack_build.S} | 0 ..._low_level.s => tx_initialize_low_level.S} | 0 ..._unprotect.s => tx_thread_smp_unprotect.S} | 0 scripts/check_clang.sh | 14 ++++- scripts/check_ports.sh | 56 ++++++++++++++++++- 35 files changed, 94 insertions(+), 6 deletions(-) rename ports_module/cortex_a7/gnu/example_build/{tx_initialize_low_level.s => tx_initialize_low_level.S} (100%) rename ports_module/cortex_a7/gnu/module_manager/src/{tx_thread_context_restore.s => tx_thread_context_restore.S} (100%) rename ports_module/cortex_a7/gnu/module_manager/src/{tx_thread_context_save.s => tx_thread_context_save.S} (100%) rename ports_module/cortex_a7/gnu/module_manager/src/{tx_thread_fiq_context_restore.s => tx_thread_fiq_context_restore.S} (100%) rename ports_module/cortex_a7/gnu/module_manager/src/{tx_thread_fiq_context_save.s => tx_thread_fiq_context_save.S} (100%) rename ports_module/cortex_a7/gnu/module_manager/src/{tx_thread_fiq_nesting_end.s => tx_thread_fiq_nesting_end.S} (100%) rename ports_module/cortex_a7/gnu/module_manager/src/{tx_thread_fiq_nesting_start.s => tx_thread_fiq_nesting_start.S} (100%) rename ports_module/cortex_a7/gnu/module_manager/src/{tx_thread_interrupt_control.s => tx_thread_interrupt_control.S} (100%) rename ports_module/cortex_a7/gnu/module_manager/src/{tx_thread_interrupt_disable.s => tx_thread_interrupt_disable.S} (100%) rename ports_module/cortex_a7/gnu/module_manager/src/{tx_thread_interrupt_restore.s => tx_thread_interrupt_restore.S} (100%) rename ports_module/cortex_a7/gnu/module_manager/src/{tx_thread_irq_nesting_end.s => tx_thread_irq_nesting_end.S} (100%) rename ports_module/cortex_a7/gnu/module_manager/src/{tx_thread_irq_nesting_start.s => tx_thread_irq_nesting_start.S} (100%) rename ports_module/cortex_a7/gnu/module_manager/src/{tx_thread_schedule.s => tx_thread_schedule.S} (100%) rename ports_module/cortex_a7/gnu/module_manager/src/{tx_thread_stack_build.s => tx_thread_stack_build.S} (100%) rename ports_module/cortex_a7/gnu/module_manager/src/{tx_thread_system_return.s => tx_thread_system_return.S} (100%) rename ports_module/cortex_a7/gnu/module_manager/src/{tx_thread_vectored_context_save.s => tx_thread_vectored_context_save.S} (100%) rename ports_module/cortex_a7/gnu/module_manager/src/{tx_timer_interrupt.s => tx_timer_interrupt.S} (100%) rename ports_module/cortex_a7/gnu/module_manager/src/{txm_module_manager_thread_stack_build.s => txm_module_manager_thread_stack_build.S} (100%) rename ports_module/cortex_a7/gnu/module_manager/src/{txm_module_manager_user_mode_entry.s => txm_module_manager_user_mode_entry.S} (100%) rename ports_module/cortex_m33/gnu/module_manager/src/{tx_thread_context_restore.s => tx_thread_context_restore.S} (100%) rename ports_module/cortex_m33/gnu/module_manager/src/{tx_thread_context_save.s => tx_thread_context_save.S} (100%) rename ports_module/cortex_m33/gnu/module_manager/src/{tx_thread_interrupt_control.s => tx_thread_interrupt_control.S} (100%) rename ports_module/cortex_m33/gnu/module_manager/src/{tx_thread_interrupt_disable.s => tx_thread_interrupt_disable.S} (100%) rename ports_module/cortex_m33/gnu/module_manager/src/{tx_thread_interrupt_restore.s => tx_thread_interrupt_restore.S} (100%) rename ports_module/cortex_m33/gnu/module_manager/src/{tx_thread_stack_build.s => tx_thread_stack_build.S} (100%) rename ports_module/cortex_m33/gnu/module_manager/src/{tx_thread_system_return.s => tx_thread_system_return.S} (100%) rename ports_module/cortex_m33/gnu/module_manager/src/{txm_module_manager_thread_stack_build.s => txm_module_manager_thread_stack_build.S} (100%) rename ports_smp/cortex_a5_smp/gnu/example_build/{tx_initialize_low_level.s => tx_initialize_low_level.S} (100%) rename ports_smp/cortex_a7_smp/gnu/src/{tx_thread_smp_unprotect.s => tx_thread_smp_unprotect.S} (100%) diff --git a/ports_module/cortex_a7/gnu/example_build/tx_initialize_low_level.s b/ports_module/cortex_a7/gnu/example_build/tx_initialize_low_level.S similarity index 100% rename from ports_module/cortex_a7/gnu/example_build/tx_initialize_low_level.s rename to ports_module/cortex_a7/gnu/example_build/tx_initialize_low_level.S diff --git a/ports_module/cortex_a7/gnu/module_manager/src/tx_thread_context_restore.s b/ports_module/cortex_a7/gnu/module_manager/src/tx_thread_context_restore.S similarity index 100% rename from ports_module/cortex_a7/gnu/module_manager/src/tx_thread_context_restore.s rename to ports_module/cortex_a7/gnu/module_manager/src/tx_thread_context_restore.S diff --git a/ports_module/cortex_a7/gnu/module_manager/src/tx_thread_context_save.s b/ports_module/cortex_a7/gnu/module_manager/src/tx_thread_context_save.S similarity index 100% rename from ports_module/cortex_a7/gnu/module_manager/src/tx_thread_context_save.s rename to ports_module/cortex_a7/gnu/module_manager/src/tx_thread_context_save.S diff --git a/ports_module/cortex_a7/gnu/module_manager/src/tx_thread_fiq_context_restore.s b/ports_module/cortex_a7/gnu/module_manager/src/tx_thread_fiq_context_restore.S similarity index 100% rename from ports_module/cortex_a7/gnu/module_manager/src/tx_thread_fiq_context_restore.s rename to ports_module/cortex_a7/gnu/module_manager/src/tx_thread_fiq_context_restore.S diff --git a/ports_module/cortex_a7/gnu/module_manager/src/tx_thread_fiq_context_save.s b/ports_module/cortex_a7/gnu/module_manager/src/tx_thread_fiq_context_save.S similarity index 100% rename from ports_module/cortex_a7/gnu/module_manager/src/tx_thread_fiq_context_save.s rename to ports_module/cortex_a7/gnu/module_manager/src/tx_thread_fiq_context_save.S diff --git a/ports_module/cortex_a7/gnu/module_manager/src/tx_thread_fiq_nesting_end.s b/ports_module/cortex_a7/gnu/module_manager/src/tx_thread_fiq_nesting_end.S similarity index 100% rename from ports_module/cortex_a7/gnu/module_manager/src/tx_thread_fiq_nesting_end.s rename to ports_module/cortex_a7/gnu/module_manager/src/tx_thread_fiq_nesting_end.S diff --git a/ports_module/cortex_a7/gnu/module_manager/src/tx_thread_fiq_nesting_start.s b/ports_module/cortex_a7/gnu/module_manager/src/tx_thread_fiq_nesting_start.S similarity index 100% rename from ports_module/cortex_a7/gnu/module_manager/src/tx_thread_fiq_nesting_start.s rename to ports_module/cortex_a7/gnu/module_manager/src/tx_thread_fiq_nesting_start.S diff --git a/ports_module/cortex_a7/gnu/module_manager/src/tx_thread_interrupt_control.s b/ports_module/cortex_a7/gnu/module_manager/src/tx_thread_interrupt_control.S similarity index 100% rename from ports_module/cortex_a7/gnu/module_manager/src/tx_thread_interrupt_control.s rename to ports_module/cortex_a7/gnu/module_manager/src/tx_thread_interrupt_control.S diff --git a/ports_module/cortex_a7/gnu/module_manager/src/tx_thread_interrupt_disable.s b/ports_module/cortex_a7/gnu/module_manager/src/tx_thread_interrupt_disable.S similarity index 100% rename from ports_module/cortex_a7/gnu/module_manager/src/tx_thread_interrupt_disable.s rename to ports_module/cortex_a7/gnu/module_manager/src/tx_thread_interrupt_disable.S diff --git a/ports_module/cortex_a7/gnu/module_manager/src/tx_thread_interrupt_restore.s b/ports_module/cortex_a7/gnu/module_manager/src/tx_thread_interrupt_restore.S similarity index 100% rename from ports_module/cortex_a7/gnu/module_manager/src/tx_thread_interrupt_restore.s rename to ports_module/cortex_a7/gnu/module_manager/src/tx_thread_interrupt_restore.S diff --git a/ports_module/cortex_a7/gnu/module_manager/src/tx_thread_irq_nesting_end.s b/ports_module/cortex_a7/gnu/module_manager/src/tx_thread_irq_nesting_end.S similarity index 100% rename from ports_module/cortex_a7/gnu/module_manager/src/tx_thread_irq_nesting_end.s rename to ports_module/cortex_a7/gnu/module_manager/src/tx_thread_irq_nesting_end.S diff --git a/ports_module/cortex_a7/gnu/module_manager/src/tx_thread_irq_nesting_start.s b/ports_module/cortex_a7/gnu/module_manager/src/tx_thread_irq_nesting_start.S similarity index 100% rename from ports_module/cortex_a7/gnu/module_manager/src/tx_thread_irq_nesting_start.s rename to ports_module/cortex_a7/gnu/module_manager/src/tx_thread_irq_nesting_start.S diff --git a/ports_module/cortex_a7/gnu/module_manager/src/tx_thread_schedule.s b/ports_module/cortex_a7/gnu/module_manager/src/tx_thread_schedule.S similarity index 100% rename from ports_module/cortex_a7/gnu/module_manager/src/tx_thread_schedule.s rename to ports_module/cortex_a7/gnu/module_manager/src/tx_thread_schedule.S diff --git a/ports_module/cortex_a7/gnu/module_manager/src/tx_thread_stack_build.s b/ports_module/cortex_a7/gnu/module_manager/src/tx_thread_stack_build.S similarity index 100% rename from ports_module/cortex_a7/gnu/module_manager/src/tx_thread_stack_build.s rename to ports_module/cortex_a7/gnu/module_manager/src/tx_thread_stack_build.S diff --git a/ports_module/cortex_a7/gnu/module_manager/src/tx_thread_system_return.s b/ports_module/cortex_a7/gnu/module_manager/src/tx_thread_system_return.S similarity index 100% rename from ports_module/cortex_a7/gnu/module_manager/src/tx_thread_system_return.s rename to ports_module/cortex_a7/gnu/module_manager/src/tx_thread_system_return.S diff --git a/ports_module/cortex_a7/gnu/module_manager/src/tx_thread_vectored_context_save.s b/ports_module/cortex_a7/gnu/module_manager/src/tx_thread_vectored_context_save.S similarity index 100% rename from ports_module/cortex_a7/gnu/module_manager/src/tx_thread_vectored_context_save.s rename to ports_module/cortex_a7/gnu/module_manager/src/tx_thread_vectored_context_save.S diff --git a/ports_module/cortex_a7/gnu/module_manager/src/tx_timer_interrupt.s b/ports_module/cortex_a7/gnu/module_manager/src/tx_timer_interrupt.S similarity index 100% rename from ports_module/cortex_a7/gnu/module_manager/src/tx_timer_interrupt.s rename to ports_module/cortex_a7/gnu/module_manager/src/tx_timer_interrupt.S diff --git a/ports_module/cortex_a7/gnu/module_manager/src/txm_module_manager_thread_stack_build.s b/ports_module/cortex_a7/gnu/module_manager/src/txm_module_manager_thread_stack_build.S similarity index 100% rename from ports_module/cortex_a7/gnu/module_manager/src/txm_module_manager_thread_stack_build.s rename to ports_module/cortex_a7/gnu/module_manager/src/txm_module_manager_thread_stack_build.S diff --git a/ports_module/cortex_a7/gnu/module_manager/src/txm_module_manager_user_mode_entry.s b/ports_module/cortex_a7/gnu/module_manager/src/txm_module_manager_user_mode_entry.S similarity index 100% rename from ports_module/cortex_a7/gnu/module_manager/src/txm_module_manager_user_mode_entry.s rename to ports_module/cortex_a7/gnu/module_manager/src/txm_module_manager_user_mode_entry.S diff --git a/ports_module/cortex_m23/gnu/module_manager/src/tx_initialize_low_level.S b/ports_module/cortex_m23/gnu/module_manager/src/tx_initialize_low_level.S index 28c37f367..5e356aeb9 100644 --- a/ports_module/cortex_m23/gnu/module_manager/src/tx_initialize_low_level.S +++ b/ports_module/cortex_m23/gnu/module_manager/src/tx_initialize_low_level.S @@ -9,6 +9,8 @@ * SPDX-License-Identifier: MIT **************************************************************************/ +// Some portions generated by Claude Code (Opus 5). + /**************************************************************************/ /**************************************************************************/ @@ -105,7 +107,7 @@ _tx_initialize_low_level: /* Configure SysTick. */ LDR r0, =0xE000E000 // Build address of NVIC registers - MOV r1, #0 // Build value for SysTick reset + MOVS r1, #0 // Build value for SysTick reset STR r1, [r0, #0x10] // Reset SysTick Control STR r1, [r0, #0x18] // Reset SysTick Counter Value LDR r1, =SYSTICK_CYCLES diff --git a/ports_module/cortex_m23/gnu/module_manager/src/tx_thread_context_restore.S b/ports_module/cortex_m23/gnu/module_manager/src/tx_thread_context_restore.S index 2f9d7165b..f08f68fb0 100644 --- a/ports_module/cortex_m23/gnu/module_manager/src/tx_thread_context_restore.S +++ b/ports_module/cortex_m23/gnu/module_manager/src/tx_thread_context_restore.S @@ -9,6 +9,8 @@ * SPDX-License-Identifier: MIT **************************************************************************/ +// Some portions generated by Claude Code (Opus 5). + /**************************************************************************/ /**************************************************************************/ @@ -69,7 +71,14 @@ _tx_thread_context_restore: /* Call the ISR exit function to indicate an ISR is complete. */ PUSH {r0, lr} // Save return address BL _tx_execution_isr_exit // Call the ISR exit function - POP {r0, lr} // Recover return address + POP {r0, r1} // Recover r0 and the return address + MOV lr, r1 // This core cannot POP into LR: the + // 16-bit Thumb POP takes r0-r7 and + // pc only. MOV to a high register + // is permitted, so restore LR from + // a scratch register. r1 is free -- + // the BL above may clobber r0-r3, + // which is why r0 is saved at all. #endif BX lr diff --git a/ports_module/cortex_m23/gnu/module_manager/src/tx_thread_context_save.S b/ports_module/cortex_m23/gnu/module_manager/src/tx_thread_context_save.S index f51cff714..b43467f7b 100644 --- a/ports_module/cortex_m23/gnu/module_manager/src/tx_thread_context_save.S +++ b/ports_module/cortex_m23/gnu/module_manager/src/tx_thread_context_save.S @@ -9,6 +9,8 @@ * SPDX-License-Identifier: MIT **************************************************************************/ +// Some portions generated by Claude Code (Opus 5). + /**************************************************************************/ /**************************************************************************/ @@ -69,7 +71,14 @@ _tx_thread_context_save: /* Call the ISR enter function to indicate an ISR is starting. */ PUSH {r0, lr} // Save return address BL _tx_execution_isr_enter // Call the ISR enter function - POP {r0, lr} // Recover return address + POP {r0, r1} // Recover r0 and the return address + MOV lr, r1 // This core cannot POP into LR: the + // 16-bit Thumb POP takes r0-r7 and + // pc only. MOV to a high register + // is permitted, so restore LR from + // a scratch register. r1 is free -- + // the BL above may clobber r0-r3, + // which is why r0 is saved at all. #endif BX lr diff --git a/ports_module/cortex_m23/gnu/module_manager/src/tx_thread_secure_stack_initialize.S b/ports_module/cortex_m23/gnu/module_manager/src/tx_thread_secure_stack_initialize.S index ae66a5c58..44cc33962 100644 --- a/ports_module/cortex_m23/gnu/module_manager/src/tx_thread_secure_stack_initialize.S +++ b/ports_module/cortex_m23/gnu/module_manager/src/tx_thread_secure_stack_initialize.S @@ -9,6 +9,8 @@ * SPDX-License-Identifier: MIT **************************************************************************/ +// Some portions generated by Claude Code (Opus 5). + /**************************************************************************/ /**************************************************************************/ @@ -67,7 +69,7 @@ _tx_thread_secure_stack_initialize: SVC 3 CPSID i // Disable interrupts #else - MOV r0, #0xFF // Feature not enabled + MOVS r0, #0xFF // Feature not enabled #endif BX lr .end diff --git a/ports_module/cortex_m33/gnu/module_manager/src/tx_thread_context_restore.s b/ports_module/cortex_m33/gnu/module_manager/src/tx_thread_context_restore.S similarity index 100% rename from ports_module/cortex_m33/gnu/module_manager/src/tx_thread_context_restore.s rename to ports_module/cortex_m33/gnu/module_manager/src/tx_thread_context_restore.S diff --git a/ports_module/cortex_m33/gnu/module_manager/src/tx_thread_context_save.s b/ports_module/cortex_m33/gnu/module_manager/src/tx_thread_context_save.S similarity index 100% rename from ports_module/cortex_m33/gnu/module_manager/src/tx_thread_context_save.s rename to ports_module/cortex_m33/gnu/module_manager/src/tx_thread_context_save.S diff --git a/ports_module/cortex_m33/gnu/module_manager/src/tx_thread_interrupt_control.s b/ports_module/cortex_m33/gnu/module_manager/src/tx_thread_interrupt_control.S similarity index 100% rename from ports_module/cortex_m33/gnu/module_manager/src/tx_thread_interrupt_control.s rename to ports_module/cortex_m33/gnu/module_manager/src/tx_thread_interrupt_control.S diff --git a/ports_module/cortex_m33/gnu/module_manager/src/tx_thread_interrupt_disable.s b/ports_module/cortex_m33/gnu/module_manager/src/tx_thread_interrupt_disable.S similarity index 100% rename from ports_module/cortex_m33/gnu/module_manager/src/tx_thread_interrupt_disable.s rename to ports_module/cortex_m33/gnu/module_manager/src/tx_thread_interrupt_disable.S diff --git a/ports_module/cortex_m33/gnu/module_manager/src/tx_thread_interrupt_restore.s b/ports_module/cortex_m33/gnu/module_manager/src/tx_thread_interrupt_restore.S similarity index 100% rename from ports_module/cortex_m33/gnu/module_manager/src/tx_thread_interrupt_restore.s rename to ports_module/cortex_m33/gnu/module_manager/src/tx_thread_interrupt_restore.S diff --git a/ports_module/cortex_m33/gnu/module_manager/src/tx_thread_stack_build.s b/ports_module/cortex_m33/gnu/module_manager/src/tx_thread_stack_build.S similarity index 100% rename from ports_module/cortex_m33/gnu/module_manager/src/tx_thread_stack_build.s rename to ports_module/cortex_m33/gnu/module_manager/src/tx_thread_stack_build.S diff --git a/ports_module/cortex_m33/gnu/module_manager/src/tx_thread_system_return.s b/ports_module/cortex_m33/gnu/module_manager/src/tx_thread_system_return.S similarity index 100% rename from ports_module/cortex_m33/gnu/module_manager/src/tx_thread_system_return.s rename to ports_module/cortex_m33/gnu/module_manager/src/tx_thread_system_return.S diff --git a/ports_module/cortex_m33/gnu/module_manager/src/txm_module_manager_thread_stack_build.s b/ports_module/cortex_m33/gnu/module_manager/src/txm_module_manager_thread_stack_build.S similarity index 100% rename from ports_module/cortex_m33/gnu/module_manager/src/txm_module_manager_thread_stack_build.s rename to ports_module/cortex_m33/gnu/module_manager/src/txm_module_manager_thread_stack_build.S diff --git a/ports_smp/cortex_a5_smp/gnu/example_build/tx_initialize_low_level.s b/ports_smp/cortex_a5_smp/gnu/example_build/tx_initialize_low_level.S similarity index 100% rename from ports_smp/cortex_a5_smp/gnu/example_build/tx_initialize_low_level.s rename to ports_smp/cortex_a5_smp/gnu/example_build/tx_initialize_low_level.S diff --git a/ports_smp/cortex_a7_smp/gnu/src/tx_thread_smp_unprotect.s b/ports_smp/cortex_a7_smp/gnu/src/tx_thread_smp_unprotect.S similarity index 100% rename from ports_smp/cortex_a7_smp/gnu/src/tx_thread_smp_unprotect.s rename to ports_smp/cortex_a7_smp/gnu/src/tx_thread_smp_unprotect.S diff --git a/scripts/check_clang.sh b/scripts/check_clang.sh index ca646f312..f8ced1dd0 100755 --- a/scripts/check_clang.sh +++ b/scripts/check_clang.sh @@ -211,7 +211,13 @@ say "" say "== Assembly sources of every Arm gnu port ==" total=0 -for dir in ports/*/gnu/src ports_smp/*/gnu/src ports_module/*/gnu/src; do +# The module ports keep their assembly in module_manager/src, not src. This +# glob read ports_module/*/gnu/src until 26 Aug 2026; that directory does not +# exist, the [ -d ] guard below skipped it in silence, and 116 files across +# nine Arm module ports were assembled by no check with either compiler. The +# count went from 724 to 840 when the path was corrected, and three of the new +# files did not assemble. +for dir in ports/*/gnu/src ports_smp/*/gnu/src ports_module/*/gnu/module_manager/src; do [ -d "$dir" ] || continue core="$(echo "$dir" | cut -d/ -f2)" spec="${PORT_TARGET[$core]:-}" @@ -246,7 +252,13 @@ say "== Assembly behind feature macros ==" for macro in $FEATURE_MACROS; do macro_total=0 macro_bad=0 + # The module ports are named here for the same reason as in the stage + # above: they were absent from this list until 26 Aug 2026 and so read as + # covered. Adding them found the Cortex-M23 module manager carrying the + # very POP {r0, lr} this comment describes, six months after the same fix + # landed in its non-module sibling. for src in $(grep -rl "$macro" ports/*/gnu/src/*.S ports_smp/*/gnu/src/*.S \ + ports_module/*/gnu/module_manager/src/*.S \ 2>/dev/null | sort); do core="$(echo "$src" | cut -d/ -f2)" spec="${PORT_TARGET[$core]:-}" diff --git a/scripts/check_ports.sh b/scripts/check_ports.sh index b177a7ef6..1ba13ca03 100755 --- a/scripts/check_ports.sh +++ b/scripts/check_ports.sh @@ -39,6 +39,11 @@ # body in ports/cortex_m4/ac6/inc/tx_port.h, which placed statements # outside any function. See issue 569. # +# 4. Lowercase .s under a gnu tree. GAS preprocesses .S and not .s, so a +# .s file's #ifdef blocks are assembled whichever way the macro is set. +# Twenty-nine files were in that state, including one non-module SMP +# kernel port, and only one of them failed to assemble. +# # The last section reports, without failing, on port families that have no copy # script and so cannot be checked for reproducibility. # @@ -197,7 +202,56 @@ done < <(find ports ports_arch ports_module ports_smp -name "*.h" -type f \ [ "$orphans" -eq 0 ] && say " ok: no port header carries code at file scope" # -------------------------------------------------------------------------- -# 4. Report only: families with no copy script. +# 4. GNU assembly that uses the preprocessor must be named .S, not .s. +# -------------------------------------------------------------------------- +# GAS runs the C preprocessor on .S and not on .s. In a .s file every line +# beginning with # is just a comment, so nothing fails and nothing is +# substituted: a #define constant reaches the assembler as an undefined +# symbol, an #ifdef block is assembled whatever the macro says, and an +# #if/#else pair emits *both* branches. The port silently ignores its own +# feature macros. +# +# Measured 26 Aug 2026, when a corrected glob in check_clang.sh first offered +# the module ports to a compiler. Twenty-nine files were affected, and the +# damage was not only cosmetic: +# +# ports_smp/cortex_a7_smp/gnu/src/tx_thread_smp_unprotect.s -- the only .s +# in a directory of twenty-one .S -- wrote the caller's LR into the +# protection structure on every unprotect, a store guarded by +# TX_MPCORE_DEBUG_ENABLE, and returned through both BX lr and MOV pc, lr. +# +# ports_module/cortex_m33/.../tx_thread_stack_build.s emitted both arms of +# an #ifdef TX_SINGLE_MODE_SECURE, so the second LR value overwrote the +# first and the secure build got the non-secure one. +# +# ports_module/cortex_a7/.../tx_thread_schedule.s did fail to assemble, on +# GCC 14.3 as well as on LLVM, because #define SYS_MODE was never expanded. +# That is the only one of the twenty-nine any compiler complained about. +# +# Only the gnu trees are checked. The IAR, Arm Compiler 5 and Keil assemblers +# preprocess .s themselves, so the same combination is correct there, and +# around three hundred files in this repository depend on it. +say "" +say "== GNU assembly using the preprocessor is named .S ==" + +lowercase=0 +while IFS= read -r f; do + first="$(grep -nE '^[ \t]*#[ \t]*(define|include|if|ifdef|ifndef|else|elif|endif|undef)\b' \ + "$f" | head -1)" + if [ -n "$first" ]; then + fail "$f: preprocessor directive in a .s file, which GAS does not preprocess" + echo " line $first" + echo " Rename the file to .S. Check the callers first: a build script" + echo " that already names it .S is the usual sign of how this happened." + lowercase=$((lowercase + 1)) + fi +done < <(find ports ports_arch ports_module ports_smp -name "*.s" -type f \ + -path "*/gnu/*" 2>/dev/null | sort) + +[ "$lowercase" -eq 0 ] && say " ok: no .s file under a gnu tree uses the preprocessor" + +# -------------------------------------------------------------------------- +# 5. Report only: families with no copy script. # -------------------------------------------------------------------------- # These are maintained by hand, so a fix applied to one toolchain can silently # miss the others. Nothing here fails the run; it is a prompt to look. From 802aab6851c3d0afbea1d276768fc9d99db010f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Desbiens?= Date: Wed, 26 Aug 2026 10:04:17 -0400 Subject: [PATCH 2/4] Fixed the AArch64 samples, none of which had ever linked 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) --- .../gnu/example_build/build_threadx_sample.sh | 24 ++++++++++++++++++- .../gnu/example_build/build_threadx_sample.sh | 24 ++++++++++++++++++- .../gnu/example_build/build_threadx_sample.sh | 24 ++++++++++++++++++- .../gnu/example_build/build_threadx_sample.sh | 24 ++++++++++++++++++- .../gnu/example_build/build_threadx_sample.sh | 24 ++++++++++++++++++- .../gnu/example_build/build_threadx_sample.sh | 24 ++++++++++++++++++- .../gnu/example_build/build_threadx_sample.sh | 24 ++++++++++++++++++- .../gnu/example_build/build_threadx_sample.sh | 24 ++++++++++++++++++- .../gnu/example_build/build_threadx_sample.sh | 24 ++++++++++++++++++- .../gnu/example_build/build_threadx_sample.sh | 24 ++++++++++++++++++- .../gnu/example_build/build_threadx_sample.sh | 24 ++++++++++++++++++- .../gnu/example_build/build_threadx_sample.sh | 24 ++++++++++++++++++- .../gnu/example_build/build_threadx_sample.sh | 24 ++++++++++++++++++- .../gnu/example_build/build_threadx_sample.sh | 24 ++++++++++++++++++- .../gnu/example_build/build_threadx_sample.sh | 24 ++++++++++++++++++- .../gnu/example_build/build_threadx_sample.sh | 24 ++++++++++++++++++- .../gnu/example_build/build_threadx_sample.sh | 24 ++++++++++++++++++- .../gnu/example_build/build_threadx_sample.sh | 24 ++++++++++++++++++- .../gnu/example_build/build_threadx_sample.sh | 24 ++++++++++++++++++- .../gnu/example_build/build_threadx_sample.sh | 24 ++++++++++++++++++- .../gnu/example_build/build_threadx_sample.sh | 24 ++++++++++++++++++- .../gnu/example_build/build_threadx_sample.sh | 24 ++++++++++++++++++- .../gnu/example_build/build_threadx_sample.sh | 24 ++++++++++++++++++- .../gnu/example_build/build_threadx_sample.sh | 24 ++++++++++++++++++- .../gnu/example_build/build_threadx_sample.sh | 24 ++++++++++++++++++- .../gnu/example_build/build_threadx_sample.sh | 24 ++++++++++++++++++- .../gnu/example_build/build_threadx_sample.sh | 24 ++++++++++++++++++- .../gnu/example_build/build_threadx_sample.sh | 24 ++++++++++++++++++- 28 files changed, 644 insertions(+), 28 deletions(-) diff --git a/ports/cortex_a34/gnu/example_build/build_threadx_sample.sh b/ports/cortex_a34/gnu/example_build/build_threadx_sample.sh index fa5b92ec3..94248a888 100755 --- a/ports/cortex_a34/gnu/example_build/build_threadx_sample.sh +++ b/ports/cortex_a34/gnu/example_build/build_threadx_sample.sh @@ -44,6 +44,23 @@ case "${TOOLCHAIN}" in # initialise_monitor_handles that startup.S calls. SYSCALL_LIB="--specs=rdimon.specs" SEMIHOST_STUB="" + # crti.o defines _init and _fini; crtn.o closes them. The link below + # passes -nostartfiles, which is right for a port with its own reset + # path but also drops these two, and startup.S calls + # __libc_init_array, whose newlib implementation calls _init. Without + # them every AArch64 sample failed to link: + # + # 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' + # + # crti.o must precede every other .init contribution and crtn.o must + # follow all of them, which is why they bracket the object list rather + # than sitting with the other flags. The AArch32 scripts need none of + # this: they use nosys.specs and never reach __libc_init_array. + CRT_BEGIN="$("${CC}" -mcpu="${cpu}" -print-file-name=crti.o)" + CRT_END="$("${CC}" -mcpu="${cpu}" -print-file-name=crtn.o)" ;; atfe) CC="${ATFE_CLANG:-clang}" @@ -52,6 +69,11 @@ case "${TOOLCHAIN}" in # picolibc has no initialise_monitor_handles, and neither does the # toolchain's semihosting library, so the weak stub stands in for it. SEMIHOST_STUB="sample_threadx/semihost_stub.S" + # Deliberately empty. picolibc's __libc_init_array does not call _init, + # so these images link today and adding crti.o would change a working + # link for no reason. + CRT_BEGIN="" + CRT_END="" ;; *) echo "Unknown TOOLCHAIN '${TOOLCHAIN}'; expected gnu or atfe" >&2 @@ -80,7 +102,7 @@ done "${CC}" ${TARGET_FLAGS} -g -mcpu="${cpu}" -nostartfiles \ -T sample_threadx/sample_threadx.ld ${SYSCALL_LIB} \ -o sample_threadx.out -Wl,-Map=sample_threadx.map \ - ${objects} tx.a + ${CRT_BEGIN} ${objects} tx.a ${CRT_END} rm -f ${objects} diff --git a/ports/cortex_a35/gnu/example_build/build_threadx_sample.sh b/ports/cortex_a35/gnu/example_build/build_threadx_sample.sh index fa5b92ec3..94248a888 100755 --- a/ports/cortex_a35/gnu/example_build/build_threadx_sample.sh +++ b/ports/cortex_a35/gnu/example_build/build_threadx_sample.sh @@ -44,6 +44,23 @@ case "${TOOLCHAIN}" in # initialise_monitor_handles that startup.S calls. SYSCALL_LIB="--specs=rdimon.specs" SEMIHOST_STUB="" + # crti.o defines _init and _fini; crtn.o closes them. The link below + # passes -nostartfiles, which is right for a port with its own reset + # path but also drops these two, and startup.S calls + # __libc_init_array, whose newlib implementation calls _init. Without + # them every AArch64 sample failed to link: + # + # 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' + # + # crti.o must precede every other .init contribution and crtn.o must + # follow all of them, which is why they bracket the object list rather + # than sitting with the other flags. The AArch32 scripts need none of + # this: they use nosys.specs and never reach __libc_init_array. + CRT_BEGIN="$("${CC}" -mcpu="${cpu}" -print-file-name=crti.o)" + CRT_END="$("${CC}" -mcpu="${cpu}" -print-file-name=crtn.o)" ;; atfe) CC="${ATFE_CLANG:-clang}" @@ -52,6 +69,11 @@ case "${TOOLCHAIN}" in # picolibc has no initialise_monitor_handles, and neither does the # toolchain's semihosting library, so the weak stub stands in for it. SEMIHOST_STUB="sample_threadx/semihost_stub.S" + # Deliberately empty. picolibc's __libc_init_array does not call _init, + # so these images link today and adding crti.o would change a working + # link for no reason. + CRT_BEGIN="" + CRT_END="" ;; *) echo "Unknown TOOLCHAIN '${TOOLCHAIN}'; expected gnu or atfe" >&2 @@ -80,7 +102,7 @@ done "${CC}" ${TARGET_FLAGS} -g -mcpu="${cpu}" -nostartfiles \ -T sample_threadx/sample_threadx.ld ${SYSCALL_LIB} \ -o sample_threadx.out -Wl,-Map=sample_threadx.map \ - ${objects} tx.a + ${CRT_BEGIN} ${objects} tx.a ${CRT_END} rm -f ${objects} diff --git a/ports/cortex_a53/gnu/example_build/build_threadx_sample.sh b/ports/cortex_a53/gnu/example_build/build_threadx_sample.sh index fa5b92ec3..94248a888 100755 --- a/ports/cortex_a53/gnu/example_build/build_threadx_sample.sh +++ b/ports/cortex_a53/gnu/example_build/build_threadx_sample.sh @@ -44,6 +44,23 @@ case "${TOOLCHAIN}" in # initialise_monitor_handles that startup.S calls. SYSCALL_LIB="--specs=rdimon.specs" SEMIHOST_STUB="" + # crti.o defines _init and _fini; crtn.o closes them. The link below + # passes -nostartfiles, which is right for a port with its own reset + # path but also drops these two, and startup.S calls + # __libc_init_array, whose newlib implementation calls _init. Without + # them every AArch64 sample failed to link: + # + # 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' + # + # crti.o must precede every other .init contribution and crtn.o must + # follow all of them, which is why they bracket the object list rather + # than sitting with the other flags. The AArch32 scripts need none of + # this: they use nosys.specs and never reach __libc_init_array. + CRT_BEGIN="$("${CC}" -mcpu="${cpu}" -print-file-name=crti.o)" + CRT_END="$("${CC}" -mcpu="${cpu}" -print-file-name=crtn.o)" ;; atfe) CC="${ATFE_CLANG:-clang}" @@ -52,6 +69,11 @@ case "${TOOLCHAIN}" in # picolibc has no initialise_monitor_handles, and neither does the # toolchain's semihosting library, so the weak stub stands in for it. SEMIHOST_STUB="sample_threadx/semihost_stub.S" + # Deliberately empty. picolibc's __libc_init_array does not call _init, + # so these images link today and adding crti.o would change a working + # link for no reason. + CRT_BEGIN="" + CRT_END="" ;; *) echo "Unknown TOOLCHAIN '${TOOLCHAIN}'; expected gnu or atfe" >&2 @@ -80,7 +102,7 @@ done "${CC}" ${TARGET_FLAGS} -g -mcpu="${cpu}" -nostartfiles \ -T sample_threadx/sample_threadx.ld ${SYSCALL_LIB} \ -o sample_threadx.out -Wl,-Map=sample_threadx.map \ - ${objects} tx.a + ${CRT_BEGIN} ${objects} tx.a ${CRT_END} rm -f ${objects} diff --git a/ports/cortex_a55/gnu/example_build/build_threadx_sample.sh b/ports/cortex_a55/gnu/example_build/build_threadx_sample.sh index fa5b92ec3..94248a888 100755 --- a/ports/cortex_a55/gnu/example_build/build_threadx_sample.sh +++ b/ports/cortex_a55/gnu/example_build/build_threadx_sample.sh @@ -44,6 +44,23 @@ case "${TOOLCHAIN}" in # initialise_monitor_handles that startup.S calls. SYSCALL_LIB="--specs=rdimon.specs" SEMIHOST_STUB="" + # crti.o defines _init and _fini; crtn.o closes them. The link below + # passes -nostartfiles, which is right for a port with its own reset + # path but also drops these two, and startup.S calls + # __libc_init_array, whose newlib implementation calls _init. Without + # them every AArch64 sample failed to link: + # + # 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' + # + # crti.o must precede every other .init contribution and crtn.o must + # follow all of them, which is why they bracket the object list rather + # than sitting with the other flags. The AArch32 scripts need none of + # this: they use nosys.specs and never reach __libc_init_array. + CRT_BEGIN="$("${CC}" -mcpu="${cpu}" -print-file-name=crti.o)" + CRT_END="$("${CC}" -mcpu="${cpu}" -print-file-name=crtn.o)" ;; atfe) CC="${ATFE_CLANG:-clang}" @@ -52,6 +69,11 @@ case "${TOOLCHAIN}" in # picolibc has no initialise_monitor_handles, and neither does the # toolchain's semihosting library, so the weak stub stands in for it. SEMIHOST_STUB="sample_threadx/semihost_stub.S" + # Deliberately empty. picolibc's __libc_init_array does not call _init, + # so these images link today and adding crti.o would change a working + # link for no reason. + CRT_BEGIN="" + CRT_END="" ;; *) echo "Unknown TOOLCHAIN '${TOOLCHAIN}'; expected gnu or atfe" >&2 @@ -80,7 +102,7 @@ done "${CC}" ${TARGET_FLAGS} -g -mcpu="${cpu}" -nostartfiles \ -T sample_threadx/sample_threadx.ld ${SYSCALL_LIB} \ -o sample_threadx.out -Wl,-Map=sample_threadx.map \ - ${objects} tx.a + ${CRT_BEGIN} ${objects} tx.a ${CRT_END} rm -f ${objects} diff --git a/ports/cortex_a57/gnu/example_build/build_threadx_sample.sh b/ports/cortex_a57/gnu/example_build/build_threadx_sample.sh index fa5b92ec3..94248a888 100755 --- a/ports/cortex_a57/gnu/example_build/build_threadx_sample.sh +++ b/ports/cortex_a57/gnu/example_build/build_threadx_sample.sh @@ -44,6 +44,23 @@ case "${TOOLCHAIN}" in # initialise_monitor_handles that startup.S calls. SYSCALL_LIB="--specs=rdimon.specs" SEMIHOST_STUB="" + # crti.o defines _init and _fini; crtn.o closes them. The link below + # passes -nostartfiles, which is right for a port with its own reset + # path but also drops these two, and startup.S calls + # __libc_init_array, whose newlib implementation calls _init. Without + # them every AArch64 sample failed to link: + # + # 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' + # + # crti.o must precede every other .init contribution and crtn.o must + # follow all of them, which is why they bracket the object list rather + # than sitting with the other flags. The AArch32 scripts need none of + # this: they use nosys.specs and never reach __libc_init_array. + CRT_BEGIN="$("${CC}" -mcpu="${cpu}" -print-file-name=crti.o)" + CRT_END="$("${CC}" -mcpu="${cpu}" -print-file-name=crtn.o)" ;; atfe) CC="${ATFE_CLANG:-clang}" @@ -52,6 +69,11 @@ case "${TOOLCHAIN}" in # picolibc has no initialise_monitor_handles, and neither does the # toolchain's semihosting library, so the weak stub stands in for it. SEMIHOST_STUB="sample_threadx/semihost_stub.S" + # Deliberately empty. picolibc's __libc_init_array does not call _init, + # so these images link today and adding crti.o would change a working + # link for no reason. + CRT_BEGIN="" + CRT_END="" ;; *) echo "Unknown TOOLCHAIN '${TOOLCHAIN}'; expected gnu or atfe" >&2 @@ -80,7 +102,7 @@ done "${CC}" ${TARGET_FLAGS} -g -mcpu="${cpu}" -nostartfiles \ -T sample_threadx/sample_threadx.ld ${SYSCALL_LIB} \ -o sample_threadx.out -Wl,-Map=sample_threadx.map \ - ${objects} tx.a + ${CRT_BEGIN} ${objects} tx.a ${CRT_END} rm -f ${objects} diff --git a/ports/cortex_a65/gnu/example_build/build_threadx_sample.sh b/ports/cortex_a65/gnu/example_build/build_threadx_sample.sh index fa5b92ec3..94248a888 100755 --- a/ports/cortex_a65/gnu/example_build/build_threadx_sample.sh +++ b/ports/cortex_a65/gnu/example_build/build_threadx_sample.sh @@ -44,6 +44,23 @@ case "${TOOLCHAIN}" in # initialise_monitor_handles that startup.S calls. SYSCALL_LIB="--specs=rdimon.specs" SEMIHOST_STUB="" + # crti.o defines _init and _fini; crtn.o closes them. The link below + # passes -nostartfiles, which is right for a port with its own reset + # path but also drops these two, and startup.S calls + # __libc_init_array, whose newlib implementation calls _init. Without + # them every AArch64 sample failed to link: + # + # 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' + # + # crti.o must precede every other .init contribution and crtn.o must + # follow all of them, which is why they bracket the object list rather + # than sitting with the other flags. The AArch32 scripts need none of + # this: they use nosys.specs and never reach __libc_init_array. + CRT_BEGIN="$("${CC}" -mcpu="${cpu}" -print-file-name=crti.o)" + CRT_END="$("${CC}" -mcpu="${cpu}" -print-file-name=crtn.o)" ;; atfe) CC="${ATFE_CLANG:-clang}" @@ -52,6 +69,11 @@ case "${TOOLCHAIN}" in # picolibc has no initialise_monitor_handles, and neither does the # toolchain's semihosting library, so the weak stub stands in for it. SEMIHOST_STUB="sample_threadx/semihost_stub.S" + # Deliberately empty. picolibc's __libc_init_array does not call _init, + # so these images link today and adding crti.o would change a working + # link for no reason. + CRT_BEGIN="" + CRT_END="" ;; *) echo "Unknown TOOLCHAIN '${TOOLCHAIN}'; expected gnu or atfe" >&2 @@ -80,7 +102,7 @@ done "${CC}" ${TARGET_FLAGS} -g -mcpu="${cpu}" -nostartfiles \ -T sample_threadx/sample_threadx.ld ${SYSCALL_LIB} \ -o sample_threadx.out -Wl,-Map=sample_threadx.map \ - ${objects} tx.a + ${CRT_BEGIN} ${objects} tx.a ${CRT_END} rm -f ${objects} diff --git a/ports/cortex_a65ae/gnu/example_build/build_threadx_sample.sh b/ports/cortex_a65ae/gnu/example_build/build_threadx_sample.sh index fa5b92ec3..94248a888 100755 --- a/ports/cortex_a65ae/gnu/example_build/build_threadx_sample.sh +++ b/ports/cortex_a65ae/gnu/example_build/build_threadx_sample.sh @@ -44,6 +44,23 @@ case "${TOOLCHAIN}" in # initialise_monitor_handles that startup.S calls. SYSCALL_LIB="--specs=rdimon.specs" SEMIHOST_STUB="" + # crti.o defines _init and _fini; crtn.o closes them. The link below + # passes -nostartfiles, which is right for a port with its own reset + # path but also drops these two, and startup.S calls + # __libc_init_array, whose newlib implementation calls _init. Without + # them every AArch64 sample failed to link: + # + # 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' + # + # crti.o must precede every other .init contribution and crtn.o must + # follow all of them, which is why they bracket the object list rather + # than sitting with the other flags. The AArch32 scripts need none of + # this: they use nosys.specs and never reach __libc_init_array. + CRT_BEGIN="$("${CC}" -mcpu="${cpu}" -print-file-name=crti.o)" + CRT_END="$("${CC}" -mcpu="${cpu}" -print-file-name=crtn.o)" ;; atfe) CC="${ATFE_CLANG:-clang}" @@ -52,6 +69,11 @@ case "${TOOLCHAIN}" in # picolibc has no initialise_monitor_handles, and neither does the # toolchain's semihosting library, so the weak stub stands in for it. SEMIHOST_STUB="sample_threadx/semihost_stub.S" + # Deliberately empty. picolibc's __libc_init_array does not call _init, + # so these images link today and adding crti.o would change a working + # link for no reason. + CRT_BEGIN="" + CRT_END="" ;; *) echo "Unknown TOOLCHAIN '${TOOLCHAIN}'; expected gnu or atfe" >&2 @@ -80,7 +102,7 @@ done "${CC}" ${TARGET_FLAGS} -g -mcpu="${cpu}" -nostartfiles \ -T sample_threadx/sample_threadx.ld ${SYSCALL_LIB} \ -o sample_threadx.out -Wl,-Map=sample_threadx.map \ - ${objects} tx.a + ${CRT_BEGIN} ${objects} tx.a ${CRT_END} rm -f ${objects} diff --git a/ports/cortex_a72/gnu/example_build/build_threadx_sample.sh b/ports/cortex_a72/gnu/example_build/build_threadx_sample.sh index fa5b92ec3..94248a888 100755 --- a/ports/cortex_a72/gnu/example_build/build_threadx_sample.sh +++ b/ports/cortex_a72/gnu/example_build/build_threadx_sample.sh @@ -44,6 +44,23 @@ case "${TOOLCHAIN}" in # initialise_monitor_handles that startup.S calls. SYSCALL_LIB="--specs=rdimon.specs" SEMIHOST_STUB="" + # crti.o defines _init and _fini; crtn.o closes them. The link below + # passes -nostartfiles, which is right for a port with its own reset + # path but also drops these two, and startup.S calls + # __libc_init_array, whose newlib implementation calls _init. Without + # them every AArch64 sample failed to link: + # + # 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' + # + # crti.o must precede every other .init contribution and crtn.o must + # follow all of them, which is why they bracket the object list rather + # than sitting with the other flags. The AArch32 scripts need none of + # this: they use nosys.specs and never reach __libc_init_array. + CRT_BEGIN="$("${CC}" -mcpu="${cpu}" -print-file-name=crti.o)" + CRT_END="$("${CC}" -mcpu="${cpu}" -print-file-name=crtn.o)" ;; atfe) CC="${ATFE_CLANG:-clang}" @@ -52,6 +69,11 @@ case "${TOOLCHAIN}" in # picolibc has no initialise_monitor_handles, and neither does the # toolchain's semihosting library, so the weak stub stands in for it. SEMIHOST_STUB="sample_threadx/semihost_stub.S" + # Deliberately empty. picolibc's __libc_init_array does not call _init, + # so these images link today and adding crti.o would change a working + # link for no reason. + CRT_BEGIN="" + CRT_END="" ;; *) echo "Unknown TOOLCHAIN '${TOOLCHAIN}'; expected gnu or atfe" >&2 @@ -80,7 +102,7 @@ done "${CC}" ${TARGET_FLAGS} -g -mcpu="${cpu}" -nostartfiles \ -T sample_threadx/sample_threadx.ld ${SYSCALL_LIB} \ -o sample_threadx.out -Wl,-Map=sample_threadx.map \ - ${objects} tx.a + ${CRT_BEGIN} ${objects} tx.a ${CRT_END} rm -f ${objects} diff --git a/ports/cortex_a73/gnu/example_build/build_threadx_sample.sh b/ports/cortex_a73/gnu/example_build/build_threadx_sample.sh index fa5b92ec3..94248a888 100755 --- a/ports/cortex_a73/gnu/example_build/build_threadx_sample.sh +++ b/ports/cortex_a73/gnu/example_build/build_threadx_sample.sh @@ -44,6 +44,23 @@ case "${TOOLCHAIN}" in # initialise_monitor_handles that startup.S calls. SYSCALL_LIB="--specs=rdimon.specs" SEMIHOST_STUB="" + # crti.o defines _init and _fini; crtn.o closes them. The link below + # passes -nostartfiles, which is right for a port with its own reset + # path but also drops these two, and startup.S calls + # __libc_init_array, whose newlib implementation calls _init. Without + # them every AArch64 sample failed to link: + # + # 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' + # + # crti.o must precede every other .init contribution and crtn.o must + # follow all of them, which is why they bracket the object list rather + # than sitting with the other flags. The AArch32 scripts need none of + # this: they use nosys.specs and never reach __libc_init_array. + CRT_BEGIN="$("${CC}" -mcpu="${cpu}" -print-file-name=crti.o)" + CRT_END="$("${CC}" -mcpu="${cpu}" -print-file-name=crtn.o)" ;; atfe) CC="${ATFE_CLANG:-clang}" @@ -52,6 +69,11 @@ case "${TOOLCHAIN}" in # picolibc has no initialise_monitor_handles, and neither does the # toolchain's semihosting library, so the weak stub stands in for it. SEMIHOST_STUB="sample_threadx/semihost_stub.S" + # Deliberately empty. picolibc's __libc_init_array does not call _init, + # so these images link today and adding crti.o would change a working + # link for no reason. + CRT_BEGIN="" + CRT_END="" ;; *) echo "Unknown TOOLCHAIN '${TOOLCHAIN}'; expected gnu or atfe" >&2 @@ -80,7 +102,7 @@ done "${CC}" ${TARGET_FLAGS} -g -mcpu="${cpu}" -nostartfiles \ -T sample_threadx/sample_threadx.ld ${SYSCALL_LIB} \ -o sample_threadx.out -Wl,-Map=sample_threadx.map \ - ${objects} tx.a + ${CRT_BEGIN} ${objects} tx.a ${CRT_END} rm -f ${objects} diff --git a/ports/cortex_a75/gnu/example_build/build_threadx_sample.sh b/ports/cortex_a75/gnu/example_build/build_threadx_sample.sh index fa5b92ec3..94248a888 100755 --- a/ports/cortex_a75/gnu/example_build/build_threadx_sample.sh +++ b/ports/cortex_a75/gnu/example_build/build_threadx_sample.sh @@ -44,6 +44,23 @@ case "${TOOLCHAIN}" in # initialise_monitor_handles that startup.S calls. SYSCALL_LIB="--specs=rdimon.specs" SEMIHOST_STUB="" + # crti.o defines _init and _fini; crtn.o closes them. The link below + # passes -nostartfiles, which is right for a port with its own reset + # path but also drops these two, and startup.S calls + # __libc_init_array, whose newlib implementation calls _init. Without + # them every AArch64 sample failed to link: + # + # 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' + # + # crti.o must precede every other .init contribution and crtn.o must + # follow all of them, which is why they bracket the object list rather + # than sitting with the other flags. The AArch32 scripts need none of + # this: they use nosys.specs and never reach __libc_init_array. + CRT_BEGIN="$("${CC}" -mcpu="${cpu}" -print-file-name=crti.o)" + CRT_END="$("${CC}" -mcpu="${cpu}" -print-file-name=crtn.o)" ;; atfe) CC="${ATFE_CLANG:-clang}" @@ -52,6 +69,11 @@ case "${TOOLCHAIN}" in # picolibc has no initialise_monitor_handles, and neither does the # toolchain's semihosting library, so the weak stub stands in for it. SEMIHOST_STUB="sample_threadx/semihost_stub.S" + # Deliberately empty. picolibc's __libc_init_array does not call _init, + # so these images link today and adding crti.o would change a working + # link for no reason. + CRT_BEGIN="" + CRT_END="" ;; *) echo "Unknown TOOLCHAIN '${TOOLCHAIN}'; expected gnu or atfe" >&2 @@ -80,7 +102,7 @@ done "${CC}" ${TARGET_FLAGS} -g -mcpu="${cpu}" -nostartfiles \ -T sample_threadx/sample_threadx.ld ${SYSCALL_LIB} \ -o sample_threadx.out -Wl,-Map=sample_threadx.map \ - ${objects} tx.a + ${CRT_BEGIN} ${objects} tx.a ${CRT_END} rm -f ${objects} diff --git a/ports/cortex_a76/gnu/example_build/build_threadx_sample.sh b/ports/cortex_a76/gnu/example_build/build_threadx_sample.sh index fa5b92ec3..94248a888 100755 --- a/ports/cortex_a76/gnu/example_build/build_threadx_sample.sh +++ b/ports/cortex_a76/gnu/example_build/build_threadx_sample.sh @@ -44,6 +44,23 @@ case "${TOOLCHAIN}" in # initialise_monitor_handles that startup.S calls. SYSCALL_LIB="--specs=rdimon.specs" SEMIHOST_STUB="" + # crti.o defines _init and _fini; crtn.o closes them. The link below + # passes -nostartfiles, which is right for a port with its own reset + # path but also drops these two, and startup.S calls + # __libc_init_array, whose newlib implementation calls _init. Without + # them every AArch64 sample failed to link: + # + # 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' + # + # crti.o must precede every other .init contribution and crtn.o must + # follow all of them, which is why they bracket the object list rather + # than sitting with the other flags. The AArch32 scripts need none of + # this: they use nosys.specs and never reach __libc_init_array. + CRT_BEGIN="$("${CC}" -mcpu="${cpu}" -print-file-name=crti.o)" + CRT_END="$("${CC}" -mcpu="${cpu}" -print-file-name=crtn.o)" ;; atfe) CC="${ATFE_CLANG:-clang}" @@ -52,6 +69,11 @@ case "${TOOLCHAIN}" in # picolibc has no initialise_monitor_handles, and neither does the # toolchain's semihosting library, so the weak stub stands in for it. SEMIHOST_STUB="sample_threadx/semihost_stub.S" + # Deliberately empty. picolibc's __libc_init_array does not call _init, + # so these images link today and adding crti.o would change a working + # link for no reason. + CRT_BEGIN="" + CRT_END="" ;; *) echo "Unknown TOOLCHAIN '${TOOLCHAIN}'; expected gnu or atfe" >&2 @@ -80,7 +102,7 @@ done "${CC}" ${TARGET_FLAGS} -g -mcpu="${cpu}" -nostartfiles \ -T sample_threadx/sample_threadx.ld ${SYSCALL_LIB} \ -o sample_threadx.out -Wl,-Map=sample_threadx.map \ - ${objects} tx.a + ${CRT_BEGIN} ${objects} tx.a ${CRT_END} rm -f ${objects} diff --git a/ports/cortex_a76ae/gnu/example_build/build_threadx_sample.sh b/ports/cortex_a76ae/gnu/example_build/build_threadx_sample.sh index fa5b92ec3..94248a888 100755 --- a/ports/cortex_a76ae/gnu/example_build/build_threadx_sample.sh +++ b/ports/cortex_a76ae/gnu/example_build/build_threadx_sample.sh @@ -44,6 +44,23 @@ case "${TOOLCHAIN}" in # initialise_monitor_handles that startup.S calls. SYSCALL_LIB="--specs=rdimon.specs" SEMIHOST_STUB="" + # crti.o defines _init and _fini; crtn.o closes them. The link below + # passes -nostartfiles, which is right for a port with its own reset + # path but also drops these two, and startup.S calls + # __libc_init_array, whose newlib implementation calls _init. Without + # them every AArch64 sample failed to link: + # + # 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' + # + # crti.o must precede every other .init contribution and crtn.o must + # follow all of them, which is why they bracket the object list rather + # than sitting with the other flags. The AArch32 scripts need none of + # this: they use nosys.specs and never reach __libc_init_array. + CRT_BEGIN="$("${CC}" -mcpu="${cpu}" -print-file-name=crti.o)" + CRT_END="$("${CC}" -mcpu="${cpu}" -print-file-name=crtn.o)" ;; atfe) CC="${ATFE_CLANG:-clang}" @@ -52,6 +69,11 @@ case "${TOOLCHAIN}" in # picolibc has no initialise_monitor_handles, and neither does the # toolchain's semihosting library, so the weak stub stands in for it. SEMIHOST_STUB="sample_threadx/semihost_stub.S" + # Deliberately empty. picolibc's __libc_init_array does not call _init, + # so these images link today and adding crti.o would change a working + # link for no reason. + CRT_BEGIN="" + CRT_END="" ;; *) echo "Unknown TOOLCHAIN '${TOOLCHAIN}'; expected gnu or atfe" >&2 @@ -80,7 +102,7 @@ done "${CC}" ${TARGET_FLAGS} -g -mcpu="${cpu}" -nostartfiles \ -T sample_threadx/sample_threadx.ld ${SYSCALL_LIB} \ -o sample_threadx.out -Wl,-Map=sample_threadx.map \ - ${objects} tx.a + ${CRT_BEGIN} ${objects} tx.a ${CRT_END} rm -f ${objects} diff --git a/ports/cortex_a77/gnu/example_build/build_threadx_sample.sh b/ports/cortex_a77/gnu/example_build/build_threadx_sample.sh index fa5b92ec3..94248a888 100755 --- a/ports/cortex_a77/gnu/example_build/build_threadx_sample.sh +++ b/ports/cortex_a77/gnu/example_build/build_threadx_sample.sh @@ -44,6 +44,23 @@ case "${TOOLCHAIN}" in # initialise_monitor_handles that startup.S calls. SYSCALL_LIB="--specs=rdimon.specs" SEMIHOST_STUB="" + # crti.o defines _init and _fini; crtn.o closes them. The link below + # passes -nostartfiles, which is right for a port with its own reset + # path but also drops these two, and startup.S calls + # __libc_init_array, whose newlib implementation calls _init. Without + # them every AArch64 sample failed to link: + # + # 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' + # + # crti.o must precede every other .init contribution and crtn.o must + # follow all of them, which is why they bracket the object list rather + # than sitting with the other flags. The AArch32 scripts need none of + # this: they use nosys.specs and never reach __libc_init_array. + CRT_BEGIN="$("${CC}" -mcpu="${cpu}" -print-file-name=crti.o)" + CRT_END="$("${CC}" -mcpu="${cpu}" -print-file-name=crtn.o)" ;; atfe) CC="${ATFE_CLANG:-clang}" @@ -52,6 +69,11 @@ case "${TOOLCHAIN}" in # picolibc has no initialise_monitor_handles, and neither does the # toolchain's semihosting library, so the weak stub stands in for it. SEMIHOST_STUB="sample_threadx/semihost_stub.S" + # Deliberately empty. picolibc's __libc_init_array does not call _init, + # so these images link today and adding crti.o would change a working + # link for no reason. + CRT_BEGIN="" + CRT_END="" ;; *) echo "Unknown TOOLCHAIN '${TOOLCHAIN}'; expected gnu or atfe" >&2 @@ -80,7 +102,7 @@ done "${CC}" ${TARGET_FLAGS} -g -mcpu="${cpu}" -nostartfiles \ -T sample_threadx/sample_threadx.ld ${SYSCALL_LIB} \ -o sample_threadx.out -Wl,-Map=sample_threadx.map \ - ${objects} tx.a + ${CRT_BEGIN} ${objects} tx.a ${CRT_END} rm -f ${objects} diff --git a/ports_arch/ARMv8-A/threadx/ports/gnu/example_build/build_threadx_sample.sh b/ports_arch/ARMv8-A/threadx/ports/gnu/example_build/build_threadx_sample.sh index fa5b92ec3..94248a888 100755 --- a/ports_arch/ARMv8-A/threadx/ports/gnu/example_build/build_threadx_sample.sh +++ b/ports_arch/ARMv8-A/threadx/ports/gnu/example_build/build_threadx_sample.sh @@ -44,6 +44,23 @@ case "${TOOLCHAIN}" in # initialise_monitor_handles that startup.S calls. SYSCALL_LIB="--specs=rdimon.specs" SEMIHOST_STUB="" + # crti.o defines _init and _fini; crtn.o closes them. The link below + # passes -nostartfiles, which is right for a port with its own reset + # path but also drops these two, and startup.S calls + # __libc_init_array, whose newlib implementation calls _init. Without + # them every AArch64 sample failed to link: + # + # 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' + # + # crti.o must precede every other .init contribution and crtn.o must + # follow all of them, which is why they bracket the object list rather + # than sitting with the other flags. The AArch32 scripts need none of + # this: they use nosys.specs and never reach __libc_init_array. + CRT_BEGIN="$("${CC}" -mcpu="${cpu}" -print-file-name=crti.o)" + CRT_END="$("${CC}" -mcpu="${cpu}" -print-file-name=crtn.o)" ;; atfe) CC="${ATFE_CLANG:-clang}" @@ -52,6 +69,11 @@ case "${TOOLCHAIN}" in # picolibc has no initialise_monitor_handles, and neither does the # toolchain's semihosting library, so the weak stub stands in for it. SEMIHOST_STUB="sample_threadx/semihost_stub.S" + # Deliberately empty. picolibc's __libc_init_array does not call _init, + # so these images link today and adding crti.o would change a working + # link for no reason. + CRT_BEGIN="" + CRT_END="" ;; *) echo "Unknown TOOLCHAIN '${TOOLCHAIN}'; expected gnu or atfe" >&2 @@ -80,7 +102,7 @@ done "${CC}" ${TARGET_FLAGS} -g -mcpu="${cpu}" -nostartfiles \ -T sample_threadx/sample_threadx.ld ${SYSCALL_LIB} \ -o sample_threadx.out -Wl,-Map=sample_threadx.map \ - ${objects} tx.a + ${CRT_BEGIN} ${objects} tx.a ${CRT_END} rm -f ${objects} diff --git a/ports_smp/cortex_a34_smp/gnu/example_build/build_threadx_sample.sh b/ports_smp/cortex_a34_smp/gnu/example_build/build_threadx_sample.sh index fa5b92ec3..94248a888 100755 --- a/ports_smp/cortex_a34_smp/gnu/example_build/build_threadx_sample.sh +++ b/ports_smp/cortex_a34_smp/gnu/example_build/build_threadx_sample.sh @@ -44,6 +44,23 @@ case "${TOOLCHAIN}" in # initialise_monitor_handles that startup.S calls. SYSCALL_LIB="--specs=rdimon.specs" SEMIHOST_STUB="" + # crti.o defines _init and _fini; crtn.o closes them. The link below + # passes -nostartfiles, which is right for a port with its own reset + # path but also drops these two, and startup.S calls + # __libc_init_array, whose newlib implementation calls _init. Without + # them every AArch64 sample failed to link: + # + # 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' + # + # crti.o must precede every other .init contribution and crtn.o must + # follow all of them, which is why they bracket the object list rather + # than sitting with the other flags. The AArch32 scripts need none of + # this: they use nosys.specs and never reach __libc_init_array. + CRT_BEGIN="$("${CC}" -mcpu="${cpu}" -print-file-name=crti.o)" + CRT_END="$("${CC}" -mcpu="${cpu}" -print-file-name=crtn.o)" ;; atfe) CC="${ATFE_CLANG:-clang}" @@ -52,6 +69,11 @@ case "${TOOLCHAIN}" in # picolibc has no initialise_monitor_handles, and neither does the # toolchain's semihosting library, so the weak stub stands in for it. SEMIHOST_STUB="sample_threadx/semihost_stub.S" + # Deliberately empty. picolibc's __libc_init_array does not call _init, + # so these images link today and adding crti.o would change a working + # link for no reason. + CRT_BEGIN="" + CRT_END="" ;; *) echo "Unknown TOOLCHAIN '${TOOLCHAIN}'; expected gnu or atfe" >&2 @@ -80,7 +102,7 @@ done "${CC}" ${TARGET_FLAGS} -g -mcpu="${cpu}" -nostartfiles \ -T sample_threadx/sample_threadx.ld ${SYSCALL_LIB} \ -o sample_threadx.out -Wl,-Map=sample_threadx.map \ - ${objects} tx.a + ${CRT_BEGIN} ${objects} tx.a ${CRT_END} rm -f ${objects} diff --git a/ports_smp/cortex_a35_smp/gnu/example_build/build_threadx_sample.sh b/ports_smp/cortex_a35_smp/gnu/example_build/build_threadx_sample.sh index fa5b92ec3..94248a888 100755 --- a/ports_smp/cortex_a35_smp/gnu/example_build/build_threadx_sample.sh +++ b/ports_smp/cortex_a35_smp/gnu/example_build/build_threadx_sample.sh @@ -44,6 +44,23 @@ case "${TOOLCHAIN}" in # initialise_monitor_handles that startup.S calls. SYSCALL_LIB="--specs=rdimon.specs" SEMIHOST_STUB="" + # crti.o defines _init and _fini; crtn.o closes them. The link below + # passes -nostartfiles, which is right for a port with its own reset + # path but also drops these two, and startup.S calls + # __libc_init_array, whose newlib implementation calls _init. Without + # them every AArch64 sample failed to link: + # + # 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' + # + # crti.o must precede every other .init contribution and crtn.o must + # follow all of them, which is why they bracket the object list rather + # than sitting with the other flags. The AArch32 scripts need none of + # this: they use nosys.specs and never reach __libc_init_array. + CRT_BEGIN="$("${CC}" -mcpu="${cpu}" -print-file-name=crti.o)" + CRT_END="$("${CC}" -mcpu="${cpu}" -print-file-name=crtn.o)" ;; atfe) CC="${ATFE_CLANG:-clang}" @@ -52,6 +69,11 @@ case "${TOOLCHAIN}" in # picolibc has no initialise_monitor_handles, and neither does the # toolchain's semihosting library, so the weak stub stands in for it. SEMIHOST_STUB="sample_threadx/semihost_stub.S" + # Deliberately empty. picolibc's __libc_init_array does not call _init, + # so these images link today and adding crti.o would change a working + # link for no reason. + CRT_BEGIN="" + CRT_END="" ;; *) echo "Unknown TOOLCHAIN '${TOOLCHAIN}'; expected gnu or atfe" >&2 @@ -80,7 +102,7 @@ done "${CC}" ${TARGET_FLAGS} -g -mcpu="${cpu}" -nostartfiles \ -T sample_threadx/sample_threadx.ld ${SYSCALL_LIB} \ -o sample_threadx.out -Wl,-Map=sample_threadx.map \ - ${objects} tx.a + ${CRT_BEGIN} ${objects} tx.a ${CRT_END} rm -f ${objects} diff --git a/ports_smp/cortex_a53_smp/gnu/example_build/build_threadx_sample.sh b/ports_smp/cortex_a53_smp/gnu/example_build/build_threadx_sample.sh index fa5b92ec3..94248a888 100755 --- a/ports_smp/cortex_a53_smp/gnu/example_build/build_threadx_sample.sh +++ b/ports_smp/cortex_a53_smp/gnu/example_build/build_threadx_sample.sh @@ -44,6 +44,23 @@ case "${TOOLCHAIN}" in # initialise_monitor_handles that startup.S calls. SYSCALL_LIB="--specs=rdimon.specs" SEMIHOST_STUB="" + # crti.o defines _init and _fini; crtn.o closes them. The link below + # passes -nostartfiles, which is right for a port with its own reset + # path but also drops these two, and startup.S calls + # __libc_init_array, whose newlib implementation calls _init. Without + # them every AArch64 sample failed to link: + # + # 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' + # + # crti.o must precede every other .init contribution and crtn.o must + # follow all of them, which is why they bracket the object list rather + # than sitting with the other flags. The AArch32 scripts need none of + # this: they use nosys.specs and never reach __libc_init_array. + CRT_BEGIN="$("${CC}" -mcpu="${cpu}" -print-file-name=crti.o)" + CRT_END="$("${CC}" -mcpu="${cpu}" -print-file-name=crtn.o)" ;; atfe) CC="${ATFE_CLANG:-clang}" @@ -52,6 +69,11 @@ case "${TOOLCHAIN}" in # picolibc has no initialise_monitor_handles, and neither does the # toolchain's semihosting library, so the weak stub stands in for it. SEMIHOST_STUB="sample_threadx/semihost_stub.S" + # Deliberately empty. picolibc's __libc_init_array does not call _init, + # so these images link today and adding crti.o would change a working + # link for no reason. + CRT_BEGIN="" + CRT_END="" ;; *) echo "Unknown TOOLCHAIN '${TOOLCHAIN}'; expected gnu or atfe" >&2 @@ -80,7 +102,7 @@ done "${CC}" ${TARGET_FLAGS} -g -mcpu="${cpu}" -nostartfiles \ -T sample_threadx/sample_threadx.ld ${SYSCALL_LIB} \ -o sample_threadx.out -Wl,-Map=sample_threadx.map \ - ${objects} tx.a + ${CRT_BEGIN} ${objects} tx.a ${CRT_END} rm -f ${objects} diff --git a/ports_smp/cortex_a55_smp/gnu/example_build/build_threadx_sample.sh b/ports_smp/cortex_a55_smp/gnu/example_build/build_threadx_sample.sh index fa5b92ec3..94248a888 100755 --- a/ports_smp/cortex_a55_smp/gnu/example_build/build_threadx_sample.sh +++ b/ports_smp/cortex_a55_smp/gnu/example_build/build_threadx_sample.sh @@ -44,6 +44,23 @@ case "${TOOLCHAIN}" in # initialise_monitor_handles that startup.S calls. SYSCALL_LIB="--specs=rdimon.specs" SEMIHOST_STUB="" + # crti.o defines _init and _fini; crtn.o closes them. The link below + # passes -nostartfiles, which is right for a port with its own reset + # path but also drops these two, and startup.S calls + # __libc_init_array, whose newlib implementation calls _init. Without + # them every AArch64 sample failed to link: + # + # 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' + # + # crti.o must precede every other .init contribution and crtn.o must + # follow all of them, which is why they bracket the object list rather + # than sitting with the other flags. The AArch32 scripts need none of + # this: they use nosys.specs and never reach __libc_init_array. + CRT_BEGIN="$("${CC}" -mcpu="${cpu}" -print-file-name=crti.o)" + CRT_END="$("${CC}" -mcpu="${cpu}" -print-file-name=crtn.o)" ;; atfe) CC="${ATFE_CLANG:-clang}" @@ -52,6 +69,11 @@ case "${TOOLCHAIN}" in # picolibc has no initialise_monitor_handles, and neither does the # toolchain's semihosting library, so the weak stub stands in for it. SEMIHOST_STUB="sample_threadx/semihost_stub.S" + # Deliberately empty. picolibc's __libc_init_array does not call _init, + # so these images link today and adding crti.o would change a working + # link for no reason. + CRT_BEGIN="" + CRT_END="" ;; *) echo "Unknown TOOLCHAIN '${TOOLCHAIN}'; expected gnu or atfe" >&2 @@ -80,7 +102,7 @@ done "${CC}" ${TARGET_FLAGS} -g -mcpu="${cpu}" -nostartfiles \ -T sample_threadx/sample_threadx.ld ${SYSCALL_LIB} \ -o sample_threadx.out -Wl,-Map=sample_threadx.map \ - ${objects} tx.a + ${CRT_BEGIN} ${objects} tx.a ${CRT_END} rm -f ${objects} diff --git a/ports_smp/cortex_a57_smp/gnu/example_build/build_threadx_sample.sh b/ports_smp/cortex_a57_smp/gnu/example_build/build_threadx_sample.sh index fa5b92ec3..94248a888 100755 --- a/ports_smp/cortex_a57_smp/gnu/example_build/build_threadx_sample.sh +++ b/ports_smp/cortex_a57_smp/gnu/example_build/build_threadx_sample.sh @@ -44,6 +44,23 @@ case "${TOOLCHAIN}" in # initialise_monitor_handles that startup.S calls. SYSCALL_LIB="--specs=rdimon.specs" SEMIHOST_STUB="" + # crti.o defines _init and _fini; crtn.o closes them. The link below + # passes -nostartfiles, which is right for a port with its own reset + # path but also drops these two, and startup.S calls + # __libc_init_array, whose newlib implementation calls _init. Without + # them every AArch64 sample failed to link: + # + # 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' + # + # crti.o must precede every other .init contribution and crtn.o must + # follow all of them, which is why they bracket the object list rather + # than sitting with the other flags. The AArch32 scripts need none of + # this: they use nosys.specs and never reach __libc_init_array. + CRT_BEGIN="$("${CC}" -mcpu="${cpu}" -print-file-name=crti.o)" + CRT_END="$("${CC}" -mcpu="${cpu}" -print-file-name=crtn.o)" ;; atfe) CC="${ATFE_CLANG:-clang}" @@ -52,6 +69,11 @@ case "${TOOLCHAIN}" in # picolibc has no initialise_monitor_handles, and neither does the # toolchain's semihosting library, so the weak stub stands in for it. SEMIHOST_STUB="sample_threadx/semihost_stub.S" + # Deliberately empty. picolibc's __libc_init_array does not call _init, + # so these images link today and adding crti.o would change a working + # link for no reason. + CRT_BEGIN="" + CRT_END="" ;; *) echo "Unknown TOOLCHAIN '${TOOLCHAIN}'; expected gnu or atfe" >&2 @@ -80,7 +102,7 @@ done "${CC}" ${TARGET_FLAGS} -g -mcpu="${cpu}" -nostartfiles \ -T sample_threadx/sample_threadx.ld ${SYSCALL_LIB} \ -o sample_threadx.out -Wl,-Map=sample_threadx.map \ - ${objects} tx.a + ${CRT_BEGIN} ${objects} tx.a ${CRT_END} rm -f ${objects} diff --git a/ports_smp/cortex_a65_smp/gnu/example_build/build_threadx_sample.sh b/ports_smp/cortex_a65_smp/gnu/example_build/build_threadx_sample.sh index fa5b92ec3..94248a888 100755 --- a/ports_smp/cortex_a65_smp/gnu/example_build/build_threadx_sample.sh +++ b/ports_smp/cortex_a65_smp/gnu/example_build/build_threadx_sample.sh @@ -44,6 +44,23 @@ case "${TOOLCHAIN}" in # initialise_monitor_handles that startup.S calls. SYSCALL_LIB="--specs=rdimon.specs" SEMIHOST_STUB="" + # crti.o defines _init and _fini; crtn.o closes them. The link below + # passes -nostartfiles, which is right for a port with its own reset + # path but also drops these two, and startup.S calls + # __libc_init_array, whose newlib implementation calls _init. Without + # them every AArch64 sample failed to link: + # + # 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' + # + # crti.o must precede every other .init contribution and crtn.o must + # follow all of them, which is why they bracket the object list rather + # than sitting with the other flags. The AArch32 scripts need none of + # this: they use nosys.specs and never reach __libc_init_array. + CRT_BEGIN="$("${CC}" -mcpu="${cpu}" -print-file-name=crti.o)" + CRT_END="$("${CC}" -mcpu="${cpu}" -print-file-name=crtn.o)" ;; atfe) CC="${ATFE_CLANG:-clang}" @@ -52,6 +69,11 @@ case "${TOOLCHAIN}" in # picolibc has no initialise_monitor_handles, and neither does the # toolchain's semihosting library, so the weak stub stands in for it. SEMIHOST_STUB="sample_threadx/semihost_stub.S" + # Deliberately empty. picolibc's __libc_init_array does not call _init, + # so these images link today and adding crti.o would change a working + # link for no reason. + CRT_BEGIN="" + CRT_END="" ;; *) echo "Unknown TOOLCHAIN '${TOOLCHAIN}'; expected gnu or atfe" >&2 @@ -80,7 +102,7 @@ done "${CC}" ${TARGET_FLAGS} -g -mcpu="${cpu}" -nostartfiles \ -T sample_threadx/sample_threadx.ld ${SYSCALL_LIB} \ -o sample_threadx.out -Wl,-Map=sample_threadx.map \ - ${objects} tx.a + ${CRT_BEGIN} ${objects} tx.a ${CRT_END} rm -f ${objects} diff --git a/ports_smp/cortex_a65ae_smp/gnu/example_build/build_threadx_sample.sh b/ports_smp/cortex_a65ae_smp/gnu/example_build/build_threadx_sample.sh index fa5b92ec3..94248a888 100755 --- a/ports_smp/cortex_a65ae_smp/gnu/example_build/build_threadx_sample.sh +++ b/ports_smp/cortex_a65ae_smp/gnu/example_build/build_threadx_sample.sh @@ -44,6 +44,23 @@ case "${TOOLCHAIN}" in # initialise_monitor_handles that startup.S calls. SYSCALL_LIB="--specs=rdimon.specs" SEMIHOST_STUB="" + # crti.o defines _init and _fini; crtn.o closes them. The link below + # passes -nostartfiles, which is right for a port with its own reset + # path but also drops these two, and startup.S calls + # __libc_init_array, whose newlib implementation calls _init. Without + # them every AArch64 sample failed to link: + # + # 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' + # + # crti.o must precede every other .init contribution and crtn.o must + # follow all of them, which is why they bracket the object list rather + # than sitting with the other flags. The AArch32 scripts need none of + # this: they use nosys.specs and never reach __libc_init_array. + CRT_BEGIN="$("${CC}" -mcpu="${cpu}" -print-file-name=crti.o)" + CRT_END="$("${CC}" -mcpu="${cpu}" -print-file-name=crtn.o)" ;; atfe) CC="${ATFE_CLANG:-clang}" @@ -52,6 +69,11 @@ case "${TOOLCHAIN}" in # picolibc has no initialise_monitor_handles, and neither does the # toolchain's semihosting library, so the weak stub stands in for it. SEMIHOST_STUB="sample_threadx/semihost_stub.S" + # Deliberately empty. picolibc's __libc_init_array does not call _init, + # so these images link today and adding crti.o would change a working + # link for no reason. + CRT_BEGIN="" + CRT_END="" ;; *) echo "Unknown TOOLCHAIN '${TOOLCHAIN}'; expected gnu or atfe" >&2 @@ -80,7 +102,7 @@ done "${CC}" ${TARGET_FLAGS} -g -mcpu="${cpu}" -nostartfiles \ -T sample_threadx/sample_threadx.ld ${SYSCALL_LIB} \ -o sample_threadx.out -Wl,-Map=sample_threadx.map \ - ${objects} tx.a + ${CRT_BEGIN} ${objects} tx.a ${CRT_END} rm -f ${objects} diff --git a/ports_smp/cortex_a72_smp/gnu/example_build/build_threadx_sample.sh b/ports_smp/cortex_a72_smp/gnu/example_build/build_threadx_sample.sh index fa5b92ec3..94248a888 100755 --- a/ports_smp/cortex_a72_smp/gnu/example_build/build_threadx_sample.sh +++ b/ports_smp/cortex_a72_smp/gnu/example_build/build_threadx_sample.sh @@ -44,6 +44,23 @@ case "${TOOLCHAIN}" in # initialise_monitor_handles that startup.S calls. SYSCALL_LIB="--specs=rdimon.specs" SEMIHOST_STUB="" + # crti.o defines _init and _fini; crtn.o closes them. The link below + # passes -nostartfiles, which is right for a port with its own reset + # path but also drops these two, and startup.S calls + # __libc_init_array, whose newlib implementation calls _init. Without + # them every AArch64 sample failed to link: + # + # 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' + # + # crti.o must precede every other .init contribution and crtn.o must + # follow all of them, which is why they bracket the object list rather + # than sitting with the other flags. The AArch32 scripts need none of + # this: they use nosys.specs and never reach __libc_init_array. + CRT_BEGIN="$("${CC}" -mcpu="${cpu}" -print-file-name=crti.o)" + CRT_END="$("${CC}" -mcpu="${cpu}" -print-file-name=crtn.o)" ;; atfe) CC="${ATFE_CLANG:-clang}" @@ -52,6 +69,11 @@ case "${TOOLCHAIN}" in # picolibc has no initialise_monitor_handles, and neither does the # toolchain's semihosting library, so the weak stub stands in for it. SEMIHOST_STUB="sample_threadx/semihost_stub.S" + # Deliberately empty. picolibc's __libc_init_array does not call _init, + # so these images link today and adding crti.o would change a working + # link for no reason. + CRT_BEGIN="" + CRT_END="" ;; *) echo "Unknown TOOLCHAIN '${TOOLCHAIN}'; expected gnu or atfe" >&2 @@ -80,7 +102,7 @@ done "${CC}" ${TARGET_FLAGS} -g -mcpu="${cpu}" -nostartfiles \ -T sample_threadx/sample_threadx.ld ${SYSCALL_LIB} \ -o sample_threadx.out -Wl,-Map=sample_threadx.map \ - ${objects} tx.a + ${CRT_BEGIN} ${objects} tx.a ${CRT_END} rm -f ${objects} diff --git a/ports_smp/cortex_a73_smp/gnu/example_build/build_threadx_sample.sh b/ports_smp/cortex_a73_smp/gnu/example_build/build_threadx_sample.sh index fa5b92ec3..94248a888 100755 --- a/ports_smp/cortex_a73_smp/gnu/example_build/build_threadx_sample.sh +++ b/ports_smp/cortex_a73_smp/gnu/example_build/build_threadx_sample.sh @@ -44,6 +44,23 @@ case "${TOOLCHAIN}" in # initialise_monitor_handles that startup.S calls. SYSCALL_LIB="--specs=rdimon.specs" SEMIHOST_STUB="" + # crti.o defines _init and _fini; crtn.o closes them. The link below + # passes -nostartfiles, which is right for a port with its own reset + # path but also drops these two, and startup.S calls + # __libc_init_array, whose newlib implementation calls _init. Without + # them every AArch64 sample failed to link: + # + # 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' + # + # crti.o must precede every other .init contribution and crtn.o must + # follow all of them, which is why they bracket the object list rather + # than sitting with the other flags. The AArch32 scripts need none of + # this: they use nosys.specs and never reach __libc_init_array. + CRT_BEGIN="$("${CC}" -mcpu="${cpu}" -print-file-name=crti.o)" + CRT_END="$("${CC}" -mcpu="${cpu}" -print-file-name=crtn.o)" ;; atfe) CC="${ATFE_CLANG:-clang}" @@ -52,6 +69,11 @@ case "${TOOLCHAIN}" in # picolibc has no initialise_monitor_handles, and neither does the # toolchain's semihosting library, so the weak stub stands in for it. SEMIHOST_STUB="sample_threadx/semihost_stub.S" + # Deliberately empty. picolibc's __libc_init_array does not call _init, + # so these images link today and adding crti.o would change a working + # link for no reason. + CRT_BEGIN="" + CRT_END="" ;; *) echo "Unknown TOOLCHAIN '${TOOLCHAIN}'; expected gnu or atfe" >&2 @@ -80,7 +102,7 @@ done "${CC}" ${TARGET_FLAGS} -g -mcpu="${cpu}" -nostartfiles \ -T sample_threadx/sample_threadx.ld ${SYSCALL_LIB} \ -o sample_threadx.out -Wl,-Map=sample_threadx.map \ - ${objects} tx.a + ${CRT_BEGIN} ${objects} tx.a ${CRT_END} rm -f ${objects} diff --git a/ports_smp/cortex_a75_smp/gnu/example_build/build_threadx_sample.sh b/ports_smp/cortex_a75_smp/gnu/example_build/build_threadx_sample.sh index fa5b92ec3..94248a888 100755 --- a/ports_smp/cortex_a75_smp/gnu/example_build/build_threadx_sample.sh +++ b/ports_smp/cortex_a75_smp/gnu/example_build/build_threadx_sample.sh @@ -44,6 +44,23 @@ case "${TOOLCHAIN}" in # initialise_monitor_handles that startup.S calls. SYSCALL_LIB="--specs=rdimon.specs" SEMIHOST_STUB="" + # crti.o defines _init and _fini; crtn.o closes them. The link below + # passes -nostartfiles, which is right for a port with its own reset + # path but also drops these two, and startup.S calls + # __libc_init_array, whose newlib implementation calls _init. Without + # them every AArch64 sample failed to link: + # + # 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' + # + # crti.o must precede every other .init contribution and crtn.o must + # follow all of them, which is why they bracket the object list rather + # than sitting with the other flags. The AArch32 scripts need none of + # this: they use nosys.specs and never reach __libc_init_array. + CRT_BEGIN="$("${CC}" -mcpu="${cpu}" -print-file-name=crti.o)" + CRT_END="$("${CC}" -mcpu="${cpu}" -print-file-name=crtn.o)" ;; atfe) CC="${ATFE_CLANG:-clang}" @@ -52,6 +69,11 @@ case "${TOOLCHAIN}" in # picolibc has no initialise_monitor_handles, and neither does the # toolchain's semihosting library, so the weak stub stands in for it. SEMIHOST_STUB="sample_threadx/semihost_stub.S" + # Deliberately empty. picolibc's __libc_init_array does not call _init, + # so these images link today and adding crti.o would change a working + # link for no reason. + CRT_BEGIN="" + CRT_END="" ;; *) echo "Unknown TOOLCHAIN '${TOOLCHAIN}'; expected gnu or atfe" >&2 @@ -80,7 +102,7 @@ done "${CC}" ${TARGET_FLAGS} -g -mcpu="${cpu}" -nostartfiles \ -T sample_threadx/sample_threadx.ld ${SYSCALL_LIB} \ -o sample_threadx.out -Wl,-Map=sample_threadx.map \ - ${objects} tx.a + ${CRT_BEGIN} ${objects} tx.a ${CRT_END} rm -f ${objects} diff --git a/ports_smp/cortex_a76_smp/gnu/example_build/build_threadx_sample.sh b/ports_smp/cortex_a76_smp/gnu/example_build/build_threadx_sample.sh index fa5b92ec3..94248a888 100755 --- a/ports_smp/cortex_a76_smp/gnu/example_build/build_threadx_sample.sh +++ b/ports_smp/cortex_a76_smp/gnu/example_build/build_threadx_sample.sh @@ -44,6 +44,23 @@ case "${TOOLCHAIN}" in # initialise_monitor_handles that startup.S calls. SYSCALL_LIB="--specs=rdimon.specs" SEMIHOST_STUB="" + # crti.o defines _init and _fini; crtn.o closes them. The link below + # passes -nostartfiles, which is right for a port with its own reset + # path but also drops these two, and startup.S calls + # __libc_init_array, whose newlib implementation calls _init. Without + # them every AArch64 sample failed to link: + # + # 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' + # + # crti.o must precede every other .init contribution and crtn.o must + # follow all of them, which is why they bracket the object list rather + # than sitting with the other flags. The AArch32 scripts need none of + # this: they use nosys.specs and never reach __libc_init_array. + CRT_BEGIN="$("${CC}" -mcpu="${cpu}" -print-file-name=crti.o)" + CRT_END="$("${CC}" -mcpu="${cpu}" -print-file-name=crtn.o)" ;; atfe) CC="${ATFE_CLANG:-clang}" @@ -52,6 +69,11 @@ case "${TOOLCHAIN}" in # picolibc has no initialise_monitor_handles, and neither does the # toolchain's semihosting library, so the weak stub stands in for it. SEMIHOST_STUB="sample_threadx/semihost_stub.S" + # Deliberately empty. picolibc's __libc_init_array does not call _init, + # so these images link today and adding crti.o would change a working + # link for no reason. + CRT_BEGIN="" + CRT_END="" ;; *) echo "Unknown TOOLCHAIN '${TOOLCHAIN}'; expected gnu or atfe" >&2 @@ -80,7 +102,7 @@ done "${CC}" ${TARGET_FLAGS} -g -mcpu="${cpu}" -nostartfiles \ -T sample_threadx/sample_threadx.ld ${SYSCALL_LIB} \ -o sample_threadx.out -Wl,-Map=sample_threadx.map \ - ${objects} tx.a + ${CRT_BEGIN} ${objects} tx.a ${CRT_END} rm -f ${objects} diff --git a/ports_smp/cortex_a76ae_smp/gnu/example_build/build_threadx_sample.sh b/ports_smp/cortex_a76ae_smp/gnu/example_build/build_threadx_sample.sh index fa5b92ec3..94248a888 100755 --- a/ports_smp/cortex_a76ae_smp/gnu/example_build/build_threadx_sample.sh +++ b/ports_smp/cortex_a76ae_smp/gnu/example_build/build_threadx_sample.sh @@ -44,6 +44,23 @@ case "${TOOLCHAIN}" in # initialise_monitor_handles that startup.S calls. SYSCALL_LIB="--specs=rdimon.specs" SEMIHOST_STUB="" + # crti.o defines _init and _fini; crtn.o closes them. The link below + # passes -nostartfiles, which is right for a port with its own reset + # path but also drops these two, and startup.S calls + # __libc_init_array, whose newlib implementation calls _init. Without + # them every AArch64 sample failed to link: + # + # 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' + # + # crti.o must precede every other .init contribution and crtn.o must + # follow all of them, which is why they bracket the object list rather + # than sitting with the other flags. The AArch32 scripts need none of + # this: they use nosys.specs and never reach __libc_init_array. + CRT_BEGIN="$("${CC}" -mcpu="${cpu}" -print-file-name=crti.o)" + CRT_END="$("${CC}" -mcpu="${cpu}" -print-file-name=crtn.o)" ;; atfe) CC="${ATFE_CLANG:-clang}" @@ -52,6 +69,11 @@ case "${TOOLCHAIN}" in # picolibc has no initialise_monitor_handles, and neither does the # toolchain's semihosting library, so the weak stub stands in for it. SEMIHOST_STUB="sample_threadx/semihost_stub.S" + # Deliberately empty. picolibc's __libc_init_array does not call _init, + # so these images link today and adding crti.o would change a working + # link for no reason. + CRT_BEGIN="" + CRT_END="" ;; *) echo "Unknown TOOLCHAIN '${TOOLCHAIN}'; expected gnu or atfe" >&2 @@ -80,7 +102,7 @@ done "${CC}" ${TARGET_FLAGS} -g -mcpu="${cpu}" -nostartfiles \ -T sample_threadx/sample_threadx.ld ${SYSCALL_LIB} \ -o sample_threadx.out -Wl,-Map=sample_threadx.map \ - ${objects} tx.a + ${CRT_BEGIN} ${objects} tx.a ${CRT_END} rm -f ${objects} diff --git a/ports_smp/cortex_a77_smp/gnu/example_build/build_threadx_sample.sh b/ports_smp/cortex_a77_smp/gnu/example_build/build_threadx_sample.sh index fa5b92ec3..94248a888 100755 --- a/ports_smp/cortex_a77_smp/gnu/example_build/build_threadx_sample.sh +++ b/ports_smp/cortex_a77_smp/gnu/example_build/build_threadx_sample.sh @@ -44,6 +44,23 @@ case "${TOOLCHAIN}" in # initialise_monitor_handles that startup.S calls. SYSCALL_LIB="--specs=rdimon.specs" SEMIHOST_STUB="" + # crti.o defines _init and _fini; crtn.o closes them. The link below + # passes -nostartfiles, which is right for a port with its own reset + # path but also drops these two, and startup.S calls + # __libc_init_array, whose newlib implementation calls _init. Without + # them every AArch64 sample failed to link: + # + # 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' + # + # crti.o must precede every other .init contribution and crtn.o must + # follow all of them, which is why they bracket the object list rather + # than sitting with the other flags. The AArch32 scripts need none of + # this: they use nosys.specs and never reach __libc_init_array. + CRT_BEGIN="$("${CC}" -mcpu="${cpu}" -print-file-name=crti.o)" + CRT_END="$("${CC}" -mcpu="${cpu}" -print-file-name=crtn.o)" ;; atfe) CC="${ATFE_CLANG:-clang}" @@ -52,6 +69,11 @@ case "${TOOLCHAIN}" in # picolibc has no initialise_monitor_handles, and neither does the # toolchain's semihosting library, so the weak stub stands in for it. SEMIHOST_STUB="sample_threadx/semihost_stub.S" + # Deliberately empty. picolibc's __libc_init_array does not call _init, + # so these images link today and adding crti.o would change a working + # link for no reason. + CRT_BEGIN="" + CRT_END="" ;; *) echo "Unknown TOOLCHAIN '${TOOLCHAIN}'; expected gnu or atfe" >&2 @@ -80,7 +102,7 @@ done "${CC}" ${TARGET_FLAGS} -g -mcpu="${cpu}" -nostartfiles \ -T sample_threadx/sample_threadx.ld ${SYSCALL_LIB} \ -o sample_threadx.out -Wl,-Map=sample_threadx.map \ - ${objects} tx.a + ${CRT_BEGIN} ${objects} tx.a ${CRT_END} rm -f ${objects} diff --git a/ports_smp/cortex_a78_smp/gnu/example_build/build_threadx_sample.sh b/ports_smp/cortex_a78_smp/gnu/example_build/build_threadx_sample.sh index fa5b92ec3..94248a888 100755 --- a/ports_smp/cortex_a78_smp/gnu/example_build/build_threadx_sample.sh +++ b/ports_smp/cortex_a78_smp/gnu/example_build/build_threadx_sample.sh @@ -44,6 +44,23 @@ case "${TOOLCHAIN}" in # initialise_monitor_handles that startup.S calls. SYSCALL_LIB="--specs=rdimon.specs" SEMIHOST_STUB="" + # crti.o defines _init and _fini; crtn.o closes them. The link below + # passes -nostartfiles, which is right for a port with its own reset + # path but also drops these two, and startup.S calls + # __libc_init_array, whose newlib implementation calls _init. Without + # them every AArch64 sample failed to link: + # + # 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' + # + # crti.o must precede every other .init contribution and crtn.o must + # follow all of them, which is why they bracket the object list rather + # than sitting with the other flags. The AArch32 scripts need none of + # this: they use nosys.specs and never reach __libc_init_array. + CRT_BEGIN="$("${CC}" -mcpu="${cpu}" -print-file-name=crti.o)" + CRT_END="$("${CC}" -mcpu="${cpu}" -print-file-name=crtn.o)" ;; atfe) CC="${ATFE_CLANG:-clang}" @@ -52,6 +69,11 @@ case "${TOOLCHAIN}" in # picolibc has no initialise_monitor_handles, and neither does the # toolchain's semihosting library, so the weak stub stands in for it. SEMIHOST_STUB="sample_threadx/semihost_stub.S" + # Deliberately empty. picolibc's __libc_init_array does not call _init, + # so these images link today and adding crti.o would change a working + # link for no reason. + CRT_BEGIN="" + CRT_END="" ;; *) echo "Unknown TOOLCHAIN '${TOOLCHAIN}'; expected gnu or atfe" >&2 @@ -80,7 +102,7 @@ done "${CC}" ${TARGET_FLAGS} -g -mcpu="${cpu}" -nostartfiles \ -T sample_threadx/sample_threadx.ld ${SYSCALL_LIB} \ -o sample_threadx.out -Wl,-Map=sample_threadx.map \ - ${objects} tx.a + ${CRT_BEGIN} ${objects} tx.a ${CRT_END} rm -f ${objects} From 81046de6b956c9b5d24ed703bbb1d98ccd124087 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Desbiens?= Date: Wed, 26 Aug 2026 15:54:45 -0400 Subject: [PATCH 3/4] Added a GCC check for the Arm ports, which nothing had ever compiled GCC is the project's declared default compiler (AGENTS.md, "The default compiler for the project is GCC 14 on Linux"), it is what the gnu ports exist for, and it is what nearly every downstream user builds with -- and nothing in CI compiled a line of any port with it. The only cross-compilation check that ran was the LLVM one, so the ATfE path was better guarded than the GNU one, on ports whose directory is literally named gnu. ci_cortex_m covers four port families; this covers forty. Five stages, mirroring scripts/check_clang.sh stage for stage: 1. assemble every .S and .s of every Arm gnu port -- 840 files 2. assemble again the parts behind TX_ENABLE_VFP_SUPPORT, TX_ENABLE_FIQ_SUPPORT, TX_LOW_POWER and TX_ENABLE_EXECUTION_CHANGE_NOTIFY -- 469 files 3. compile common/src for one core per architecture profile -- 185 x 9 4. link the script-driven example builds -- 42 5. link the CMake-driven Cortex-R52 images -- 5 Two scripts rather than one with a --toolchain flag: the flag surface differs (a prefixed driver against --target=), the C library differs, and the set of examples that can link differs. Folding them together makes it easy to weaken one check while working on the other. Two toolchains, both required. Arm ships arm-none-eabi and aarch64-none-elf as separate downloads and PORT_TARGET maps every port to one of exactly those two triples, so --arm-none-eabi and --aarch64-none-elf each take a driver or the directory holding it, defaulting to the environment and then to PATH. A missing one is a hard error rather than a soft skip: letting a run cover half the tree and still report "all checks passed" is the failure this script exists to end. PORT_TARGET is copied verbatim from check_clang.sh, including its warning not to prefix-match core names -- cortex_a5* also matches the AArch64 cortex_a53. VFP_EXTRA is the one map that is not a copy, and check_clang.sh's comment about it is false for GCC. That comment says the A-profile defaults are already correct; arm-none-eabi-gcc defaults to -mfloat-abi=soft, which disables the FPU outright, so every VFP file fails with "selected processor does not support 'vmrs r1,FPSCR' in ARM mode". -mfloat-abi=hard alone is the fix and is the right one, because it selects the core's own default FPU rather than naming a -d16 one -- which is the trap the clang script warns about, since the A-profile paths save D16-D31. Cortex-R4 is the exception in both scripts and for the same reason: its FPU is an option rather than part of the core, so an explicit -mfpu is required. Every value was measured against 14.3.rel1. Stage 4 *unsets* TOOLCHAIN rather than setting it. The example build scripts already default to GNU, and a stray TOOLCHAIN=atfe from a developer's shell would otherwise make this stage silently check the other compiler. It cleans the example directories on both sides, because the success test is the existence of sample_threadx.out rather than the driver's exit status, and a stale image from a previous toolchain would report success. Failure logs are printed unfiltered: a missing tool says "command not found", and GNU ld's undefined-symbol lines carry no "error:" at all. Every skip is printed by name with a reason, per the house rule check_clang.sh states three times -- a port simply absent from the count reads as covered. This script also says outright that arm9 and arm11 are Arm and are skipped for having no PORT_TARGET entry, which the clang script's "not Arm" wording glosses. Verified on this tree with arm-gnu-toolchain 14.3.rel1: all five stages green, every count identical to check_clang.sh's on the same tree -- 840, 469, 185x9, 42, 5 -- in 4m28s. The failure paths were tested, not assumed. A deliberately broken .S in a module port is reported by name and line in stages 1 and 2 and exits 1, in --quiet mode as well. Reverting the AArch64 _init/_fini fix on one port only gives "FAIL: cortex_a53: example build produced no image", 41 of 42, and exit 1 -- and the log tail it prints contains no "error:" anywhere, which is why it is not filtered. A missing or wrong toolchain path exits 1 naming which triple was not found. RISC-V is deliberately out of scope for this first version: both ports assemble 8 of 8 with the project's own cmake flags, but adding them widens the toolchain download and the review surface for a family that is not regressing. No regression test accompanies this. The script is the test, it exercises no runtime behaviour, and its own failure paths are exercised above. Assisted-by: Claude Code (Opus 5) --- scripts/check_gcc.sh | 571 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 571 insertions(+) create mode 100755 scripts/check_gcc.sh diff --git a/scripts/check_gcc.sh b/scripts/check_gcc.sh new file mode 100755 index 000000000..6b2cb8d5c --- /dev/null +++ b/scripts/check_gcc.sh @@ -0,0 +1,571 @@ +#!/bin/bash +############################################################################## +# Copyright (c) 2026 Eclipse ThreadX contributors +# +# This program and the accompanying materials are made available under the +# terms of the MIT License which is available at +# https://opensource.org/licenses/MIT. +# +# AI Disclosure: This file was largely AI-generated by Claude Code (Opus 5). +# The AI-generated portions may be considered public domain (CC0-1.0) +# and not subject to the project's licence. The human contributor has +# reviewed and verified that the code is correct. +# +# SPDX-License-Identifier: MIT and CC0-1.0 +############################################################################## + +# Builds the Arm ports with the GNU toolchain, in five stages: assemble every +# assembly source of every Arm gnu port, assemble again the parts guarded by +# feature macros, compile the common C sources for one core per architecture +# profile, then link the example builds, both the script-driven ones and those +# driven by CMake. Only the linking stages need a target C library. +# +# scripts/check_gcc.sh # both drivers from PATH +# scripts/check_gcc.sh --arm-none-eabi /path/to/toolchain/bin \ +# --aarch64-none-elf /path/to/toolchain/bin +# +# Options: +# --arm-none-eabi arm-none-eabi-gcc, or the directory holding it. +# Defaults to $ARM_NONE_EABI_GCC then to PATH. +# --aarch64-none-elf aarch64-none-elf-gcc, or its directory. +# Defaults to $AARCH64_NONE_ELF_GCC then to PATH. +# --asm-only Skip the C sources and the example builds. +# --no-examples Skip the example builds. +# --quiet Print only failures and the summary. +# +# Exit status is 0 when everything builds and 1 otherwise. +# +# Why this exists: GCC is the project's declared default compiler (AGENTS.md, +# "The default compiler for the project is GCC 14 on Linux"), it is what the +# gnu ports exist for, and it is what nearly every downstream user builds with +# -- and until this script landed, nothing in CI compiled a line of any port +# with it. The only cross-compilation check that ran was the LLVM one, so the +# ATfE path was better guarded than the GNU one, on ports whose directory is +# literally named gnu. +# +# This is the companion to scripts/check_clang.sh and deliberately mirrors it +# stage for stage. They are two scripts rather than one with a --toolchain flag +# because the flag surface differs (a prefixed driver against --target=), the +# C library differs, and the set of examples that can link differs. Folding +# them together makes it easy to weaken one check while working on the other. +# +# It compiles and links; it executes nothing. The Cortex-R52 FVP ctest suite is +# a separate matter, and the RISC-V, MIPS, RX and ARC families are outside it +# entirely -- every skip is printed by name below. +# +# Arm GNU toolchain releases: +# https://developer.arm.com/downloads/-/arm-gnu-toolchain-downloads + +set -u + +cd "$(dirname "$(realpath "$0")")/.." + +# Two toolchains, not one. Arm ships arm-none-eabi (AArch32: every M and R +# profile core and the A32 A-profile ports) and aarch64-none-elf as separate +# downloads, and PORT_TARGET below maps every port to one of exactly those two +# triples. Both are required: making a missing one a soft skip would let a run +# cover half the tree and still say "all checks passed", which is the failure +# this script was written to end. +CC_ARM="${ARM_NONE_EABI_GCC:-}" +CC_AARCH64="${AARCH64_NONE_ELF_GCC:-}" +asm_only=0 +no_examples=0 +quiet=0 + +while [ "$#" -gt 0 ]; do + case "$1" in + --arm-none-eabi) + [ "$#" -ge 2 ] || { echo "Error: --arm-none-eabi needs a path" >&2; exit 2; } + CC_ARM="$2"; shift 2 ;; + --aarch64-none-elf) + [ "$#" -ge 2 ] || { echo "Error: --aarch64-none-elf needs a path" >&2; exit 2; } + CC_AARCH64="$2"; shift 2 ;; + --asm-only) asm_only=1; no_examples=1; shift ;; + --no-examples) no_examples=1; shift ;; + --quiet) quiet=1; shift ;; + -h|--help) sed -n '17,36p' "$0"; exit 0 ;; + *) echo "Error: unknown option '$1'" >&2; exit 2 ;; + esac +done + +say() { [ "$quiet" -eq 1 ] || echo "$@"; } +fail() { echo " FAIL: $*"; } + +# Accept either the driver itself or the directory holding it, since a +# toolchain is unpacked as a tree and naming its bin directory is the natural +# thing to reach for. Resolve to an absolute path: the example stages run the +# build scripts from inside their own directories, so a relative path would +# stop resolving there. +resolve_gcc() { + triple="$1" + given="$2" + + if [ -z "$given" ]; then + command -v "${triple}-gcc" >/dev/null 2>&1 || return 1 + command -v "${triple}-gcc" + return 0 + fi + if [ -d "$given" ]; then + for candidate in "$given/${triple}-gcc" "$given/bin/${triple}-gcc"; do + [ -x "$candidate" ] && { realpath "$candidate"; return 0; } + done + return 1 + fi + [ -x "$given" ] || return 1 + realpath "$given" +} + +missing="" +CC_ARM="$(resolve_gcc arm-none-eabi "$CC_ARM")" || missing="$missing arm-none-eabi" +CC_AARCH64="$(resolve_gcc aarch64-none-elf "$CC_AARCH64")" || missing="$missing aarch64-none-elf" + +if [ -n "$missing" ]; then + echo "Error: compiler(s) not found:$missing" + echo "Pass --arm-none-eabi and --aarch64-none-elf, set ARM_NONE_EABI_GCC and" + echo "AARCH64_NONE_ELF_GCC, or put both drivers on PATH. Downloads:" + echo " https://developer.arm.com/downloads/-/arm-gnu-toolchain-downloads" + exit 1 +fi + +say "" +say "Using: $CC_ARM" +say " $("$CC_ARM" --version | head -1)" +say " $CC_AARCH64" +say " $("$CC_AARCH64" --version | head -1)" + +# The example build scripts and the CMake toolchain file call the drivers by +# their bare prefixed names, so both bin directories go on PATH for the linking +# stages. Done once, here, rather than per stage: a second toolchain arriving +# on PATH halfway through a run is exactly the kind of difference that makes a +# failure irreproducible. +PATH="$(dirname "$CC_ARM"):$(dirname "$CC_AARCH64"):$PATH" +export PATH + +# Pick the driver for a port from its triple, so the map below stays the single +# place a port's architecture is decided. +cc_for() { + case "$1" in + aarch64-none-elf) echo "$CC_AARCH64" ;; + *) echo "$CC_ARM" ;; + esac +} + +# Each port directory is mapped explicitly to a target triple and CPU. Do not +# replace this with prefix matching: cortex_a5* also matches cortex_a53 and +# cortex_a55, which are AArch64, and assembling those as ARM32 produces a flood +# of misleading errors. +# +# Copied verbatim from scripts/check_clang.sh. Keep the two identical -- a port +# covered by one check and not the other is worse than one covered by neither, +# because the checks list implies parity that does not exist. +declare -A PORT_TARGET=( + [cortex_m0]="arm-none-eabi cortex-m0 -mthumb" + [cortex_m0+]="arm-none-eabi cortex-m0plus -mthumb" + [cortex_m3]="arm-none-eabi cortex-m3 -mthumb" + [cortex_m4]="arm-none-eabi cortex-m4 -mthumb" + [cortex_m7]="arm-none-eabi cortex-m7 -mthumb" + [cortex_m23]="arm-none-eabi cortex-m23 -mthumb" + [cortex_m33]="arm-none-eabi cortex-m33 -mthumb" + [cortex_m52]="arm-none-eabi cortex-m52 -mthumb -mfloat-abi=hard" + [cortex_m55]="arm-none-eabi cortex-m55 -mthumb -mfloat-abi=hard" + [cortex_m85]="arm-none-eabi cortex-m85 -mthumb -mfloat-abi=hard" + [cortex_a5]="arm-none-eabi cortex-a5" + [cortex_a7]="arm-none-eabi cortex-a7" + [cortex_a8]="arm-none-eabi cortex-a8" + [cortex_a9]="arm-none-eabi cortex-a9" + [cortex_a12]="arm-none-eabi cortex-a12" + [cortex_a15]="arm-none-eabi cortex-a15" + [cortex_a17]="arm-none-eabi cortex-a17" + [cortex_a5_smp]="arm-none-eabi cortex-a5" + [cortex_a7_smp]="arm-none-eabi cortex-a7" + [cortex_a9_smp]="arm-none-eabi cortex-a9" + [cortex_r4]="arm-none-eabi cortex-r4" + [cortex_r5]="arm-none-eabi cortex-r5" + [cortex_r52]="arm-none-eabi cortex-r52" + [cortex_a34]="aarch64-none-elf cortex-a34" + [cortex_a35]="aarch64-none-elf cortex-a35" + [cortex_a53]="aarch64-none-elf cortex-a53" + [cortex_a55]="aarch64-none-elf cortex-a55" + [cortex_a57]="aarch64-none-elf cortex-a57" + [cortex_a65]="aarch64-none-elf cortex-a65" + [cortex_a65ae]="aarch64-none-elf cortex-a65ae" + [cortex_a72]="aarch64-none-elf cortex-a72" + [cortex_a73]="aarch64-none-elf cortex-a73" + [cortex_a75]="aarch64-none-elf cortex-a75" + [cortex_a76]="aarch64-none-elf cortex-a76" + [cortex_a76ae]="aarch64-none-elf cortex-a76ae" + [cortex_a77]="aarch64-none-elf cortex-a77" + [cortex_a34_smp]="aarch64-none-elf cortex-a34" + [cortex_a35_smp]="aarch64-none-elf cortex-a35" + [cortex_a53_smp]="aarch64-none-elf cortex-a53" + [cortex_a55_smp]="aarch64-none-elf cortex-a55" + [cortex_a57_smp]="aarch64-none-elf cortex-a57" + [cortex_a65_smp]="aarch64-none-elf cortex-a65" + [cortex_a65ae_smp]="aarch64-none-elf cortex-a65ae" + [cortex_a72_smp]="aarch64-none-elf cortex-a72" + [cortex_a73_smp]="aarch64-none-elf cortex-a73" + [cortex_a75_smp]="aarch64-none-elf cortex-a75" + [cortex_a76_smp]="aarch64-none-elf cortex-a76" + [cortex_a76ae_smp]="aarch64-none-elf cortex-a76ae" + [cortex_a77_smp]="aarch64-none-elf cortex-a77" + [cortex_a78_smp]="aarch64-none-elf cortex-a78" +) + +# Assembly guarded by a feature macro is invisible to the stage above, which +# assembles with default flags and so lets the preprocessor discard every #ifdef +# block before the assembler sees it. These are the macros a user can turn on; +# each file carrying one is assembled again with it defined. +# +# This is not hypothetical, and it is not only clang's finding. The Cortex-M23 +# module manager carried "POP {r0, lr}" in exactly these paths -- invalid on +# Armv8-M Baseline, where the 16-bit POP takes r0-r7 and pc only -- for six +# months after the identical fix landed in its non-module sibling, because no +# glob in either script reached ports_module until #672. +FEATURE_MACROS="TX_ENABLE_VFP_SUPPORT TX_ENABLE_FIQ_SUPPORT TX_LOW_POWER + TX_ENABLE_EXECUTION_CHANGE_NOTIFY" + +# TX_ENABLE_IRQ_NESTING and TX_ENABLE_FIQ_NESTING are deliberately not here. +# They guard no assembly in the trees this script walks: the nesting start and +# end routines are separate files compiled unconditionally, and the macros only +# feed the TX_PORT_SPECIFIC_BUILD_OPTIONS bitfield in tx_port.h. Adding them +# would assemble nothing new and imply coverage that does not exist. + +# Extra flags for the VFP paths, per core. +# +# check_clang.sh's equivalent map has one entry and a comment saying "Do not +# extend this to the A profile ports ... their defaults are already correct." +# That is true of clang and false of GCC, so do not copy that comment here. +# arm-none-eabi-gcc defaults to -mfloat-abi=soft, which disables the FPU +# outright, and every VFP file then fails with +# +# selected processor does not support 'vmrs r1,FPSCR' in ARM mode +# +# -mfloat-abi=hard alone is the fix, and it is the right one: it selects the +# core's own default FPU rather than naming one. Naming a -d16 FPU is the trap +# the clang script warns about -- the A-profile paths save D16-D31, which exist +# only on a 32-register FPU, so a -d16 choice turns 28 working files into +# "register expected". +# +# Cortex-R4 is the exception, in both scripts and for the same reason: its FPU +# is an option rather than part of the core, so -mfloat-abi=hard alone gives +# "selected architecture lacks an FPU" and an explicit -mfpu is required. The +# value matches check_clang.sh's, so the two scripts say the same thing about +# the same port. +# +# Every entry below was measured against arm-gnu-toolchain 14.3.rel1. A core +# that acquires a VFP-guarded file without an entry here fails loudly rather +# than silently, which is the intended behaviour. +declare -A VFP_EXTRA=( + [cortex_a5]="-mfloat-abi=hard" + [cortex_a7]="-mfloat-abi=hard" + [cortex_a8]="-mfloat-abi=hard" + [cortex_a9]="-mfloat-abi=hard" + [cortex_a12]="-mfloat-abi=hard" + [cortex_a15]="-mfloat-abi=hard" + [cortex_a17]="-mfloat-abi=hard" + [cortex_a5_smp]="-mfloat-abi=hard" + [cortex_a7_smp]="-mfloat-abi=hard" + [cortex_a9_smp]="-mfloat-abi=hard" + [cortex_r4]="-mfpu=vfpv3-d16 -mfloat-abi=softfp" + [cortex_r5]="-mfloat-abi=hard" + [cortex_r52]="-mfloat-abi=hard" +) + +# One core per architecture profile for the C sources. Compiling all of them +# for every core would multiply the run time without adding coverage, since the +# port headers differ by profile rather than by core. +# +# cortex_r52 earns a slot of its own next to cortex_r5 because Armv8-R AArch32 +# is a separate profile rather than a variant of Armv7-R. That port is written +# by hand instead of generated from ports_arch, and its tx_port.h differs +# accordingly, so cortex_r5 does not stand in for it. +C_CORES="cortex_m0 cortex_m4 cortex_m23 cortex_m33 cortex_m55 cortex_a7 cortex_a53 cortex_r5 cortex_r52" + +# Example builds driven by CMake rather than by a build_threadx.sh pair. These +# are covered by their own stage below, so the script-driven loop passes over +# them without reporting them as a gap. +CMAKE_EXAMPLE_CORES="cortex_r52" + +# Example builds that are not expected to link, with the reason. Named by +# their port directory, which covers both ports/ and ports_smp/. Listed +# explicitly rather than silently skipped, so the gaps stay visible. +# +# The same four as check_clang.sh, and the reason there is stated in terms of +# GNU tooling because that is where it was reproduced: +# +# their linker scripts define the .init and .fini sections but not the _init +# and _fini symbols. Those come from crti.o and crtn.o, which -nostartfiles +# leaves out, so newlib's fini.c cannot resolve them and the link ends with +# "undefined reference to `_fini'". +# +# The 27 AArch64 examples failed the same way until #673, which links crti.o +# and crtn.o back. They are deliberately absent from this list: they link. +EXAMPLES_EXPECTED_TO_FAIL="arm9 arm11 cortex_r4 cortex_r5" + +failures=0 +skipped="" + +# -------------------------------------------------------------------------- +say "" +say "== Assembly sources of every Arm gnu port ==" + +total=0 +# The module ports keep their assembly in module_manager/src, not src. +# check_clang.sh read ports_module/*/gnu/src until #672; that directory does +# not exist, the [ -d ] guard skipped it in silence, and 116 files across nine +# Arm module ports were assembled by no check with either compiler. This script +# has never had that hole and must not acquire it. +for dir in ports/*/gnu/src ports_smp/*/gnu/src ports_module/*/gnu/module_manager/src; do + [ -d "$dir" ] || continue + core="$(echo "$dir" | cut -d/ -f2)" + spec="${PORT_TARGET[$core]:-}" + if [ -z "$spec" ]; then + skipped="$skipped $core" + continue + fi + # shellcheck disable=SC2086 + set -- $spec + target="$1"; cpu="$2"; shift 2; extra="$*" + CC="$(cc_for "$target")" + + for src in "$dir"/*.S "$dir"/*.s; do + [ -f "$src" ] || continue + total=$((total + 1)) + output="$("$CC" -mcpu="$cpu" $extra -c "$src" -o /dev/null 2>&1)" + if [ -n "$output" ]; then + fail "$src" + echo "$output" | sed 's/^/ /' + failures=$((failures + 1)) + fi + done +done +say " $((total - failures)) of $total assembled" +if [ -n "$skipped" ]; then + say " not Arm, skipped:$(echo $skipped | tr ' ' '\n' | sort -u | tr '\n' ' ')" + say " (arm9 and arm11 are Arm; they are skipped for having no PORT_TARGET entry)" +fi + +# -------------------------------------------------------------------------- +say "" +say "== Assembly behind feature macros ==" + +for macro in $FEATURE_MACROS; do + macro_total=0 + macro_bad=0 + for src in $(grep -rl "$macro" ports/*/gnu/src/*.S ports_smp/*/gnu/src/*.S \ + ports_module/*/gnu/module_manager/src/*.S \ + 2>/dev/null | sort); do + core="$(echo "$src" | cut -d/ -f2)" + spec="${PORT_TARGET[$core]:-}" + [ -n "$spec" ] || continue + # shellcheck disable=SC2086 + set -- $spec + target="$1"; cpu="$2"; shift 2; extra="$*" + CC="$(cc_for "$target")" + + # The FPU flags apply to the VFP paths only; the other macros guard no + # floating-point code and do not need them. + fpu="" + if [ "$macro" = "TX_ENABLE_VFP_SUPPORT" ]; then + fpu="${VFP_EXTRA[$core]:-}" + fi + + macro_total=$((macro_total + 1)) + output="$("$CC" -mcpu="$cpu" $extra $fpu \ + -D"$macro" -c "$src" -o /dev/null 2>&1)" + if [ -n "$output" ]; then + fail "$src with -D$macro" + # Not filtered on "error": GCC prefixes its diagnostics with an + # "Assembler messages:" line and a missing tool says nothing of the + # kind, so filtering would hide the case worth seeing. + echo "$output" | head -4 | sed 's/^/ /' + macro_bad=$((macro_bad + 1)) + failures=$((failures + 1)) + fi + done + if [ "$macro_total" -eq 0 ]; then + say " $macro: no assembly is guarded by it" + else + say " $macro: $((macro_total - macro_bad)) of $macro_total assembled" + fi +done + +# -------------------------------------------------------------------------- +if [ "$asm_only" -eq 0 ]; then + say "" + say "== Common C sources, one core per architecture profile ==" + + for core in $C_CORES; do + spec="${PORT_TARGET[$core]:-}" + [ -n "$spec" ] || continue + # shellcheck disable=SC2086 + set -- $spec + target="$1"; cpu="$2"; shift 2; extra="$*" + CC="$(cc_for "$target")" + + count=0; bad=0 + for src in common/src/*.c; do + count=$((count + 1)) + output="$("$CC" -mcpu="$cpu" $extra \ + -Iports/"$core"/gnu/inc -Icommon/inc -c "$src" -o /dev/null 2>&1)" + if [ -n "$output" ]; then + fail "$core: $src" + echo "$output" | head -4 | sed 's/^/ /' + bad=$((bad + 1)); failures=$((failures + 1)) + fi + done + say " $core: $((count - bad)) of $count compiled" + done +fi + +# -------------------------------------------------------------------------- +if [ "$no_examples" -eq 0 ]; then + say "" + say "== Example builds, linked with GNU ld ==" + + example_ok=0 + example_total=0 + example_known="" + example_nodriver="" + example_nosample="" + for dir in ports/*/gnu/example_build ports_smp/*/gnu/example_build; do + [ -d "$dir" ] || continue + core="$(echo "$dir" | cut -d/ -f2)" + + # Anything on the expected-to-fail list is reported before any other + # filter is applied, so a name placed there can never drop out of the + # output. arm9 and arm11 are the cases that matter: they are Arm ports + # with example drivers, but they carry no PORT_TARGET entry, so the + # Arm test below would discard them. + case " $EXAMPLES_EXPECTED_TO_FAIL " in + *" $core "*) example_known="$example_known $core"; continue ;; + esac + + # Arm ports only, the same rule the assembly stage applies. Naming + # linux or mips32 as a gap here would be noise, not information. + [ -n "${PORT_TARGET[$core]:-}" ] || continue + + # Covered by the CMake stage below rather than here. + case " $CMAKE_EXAMPLE_CORES " in + *" $core "*) continue ;; + esac + + # A driverless example is not covered by this stage, so say so rather + # than dropping out in silence. A port that is simply absent from the + # count reads as covered. + if [ ! -f "$dir/build_threadx.sh" ]; then + example_nodriver="$example_nodriver $core" + continue + fi + if [ ! -f "$dir/build_threadx_sample.sh" ]; then + example_nosample="$example_nosample $core" + continue + fi + example_total=$((example_total + 1)) + + # Clean on both sides. A stale sample_threadx.out from a previous + # toolchain makes a failed link report success, because the success + # test below is the existence of the output file rather than the exit + # status of the driver. + rm -f "$dir"/*.o "$dir"/*.a "$dir"/*.out "$dir"/*.map 2>/dev/null || true + + # TOOLCHAIN is *unset*, not set: the build scripts already default to + # GNU with `: "${TOOLCHAIN:=gnu}"`, and a stray TOOLCHAIN=atfe from a + # developer's shell or an earlier command would otherwise make this + # stage silently check the other compiler. + log="$(cd "$dir" && unset TOOLCHAIN && ./build_threadx.sh 2>&1 && \ + ./build_threadx_sample.sh 2>&1)" || true + + if [ -f "$dir/sample_threadx.out" ]; then + example_ok=$((example_ok + 1)) + else + fail "$core: example build produced no image" + # Not filtered on "error": a missing tool reports "command not + # found" or "Permission denied", and filtering hid exactly that. + echo "$log" | tail -6 | sed 's/^/ /' + failures=$((failures + 1)) + fi + rm -f "$dir"/*.o "$dir"/*.a "$dir"/*.out "$dir"/*.map 2>/dev/null || true + done + say " $example_ok of $example_total example builds linked" + if [ -n "$example_known" ]; then + say " known not to link, see the list at the top of this script:$example_known" + fi + if [ -n "$example_nosample" ]; then + say " has build_threadx.sh but no build_threadx_sample.sh, so not linked:$example_nosample" + fi + if [ -n "$example_nodriver" ]; then + say " no script driver, so outside this stage:$example_nodriver" + fi +fi + +# -------------------------------------------------------------------------- +# The Cortex-R52 examples are built by CMake, so they need a toolchain file +# rather than the build_threadx.sh pair. Same compiler, same purpose as the +# stage above. +if [ "$no_examples" -eq 0 ]; then + say "" + say "== CMake example builds, linked with GNU ld ==" + + if ! command -v cmake >/dev/null 2>&1 || ! command -v ninja >/dev/null 2>&1; then + say " skipped: cmake and ninja are both required" + else + for core in $CMAKE_EXAMPLE_CORES; do + build_dir="$(mktemp -d)" + # ARM_TOOLCHAIN_PATH follows --arm-none-eabi, so this stage uses + # the same compiler as every other stage rather than the absolute + # path cmake/cortex_r52.cmake pins by default. + if cmake -S . -B "$build_dir" -G Ninja \ + -DCMAKE_TOOLCHAIN_FILE="cmake/${core}.cmake" \ + -DARM_TOOLCHAIN_PATH="$(dirname "$CC_ARM")" \ + -DTX_R52_BUILD_FVP_EXAMPLE=ON \ + -DTX_R52_ENABLE_MPU=ON >"$build_dir/configure.log" 2>&1; then + # Read the image list from the generated graph instead of + # repeating it here, so adding a target cannot silently escape + # this check. The images are EXCLUDE_FROM_ALL, so "ninja" alone + # would build none of them. + # + # The cmake_object_order_depends_target_* entries are CMake's + # own ordering phonies, one per real image and named after it. + # Counting those doubled the total and reported ten images built + # where there are five. + images="$(ninja -C "$build_dir" -t targets all 2>/dev/null \ + | grep -oE '^[A-Za-z0-9_]+\.elf' \ + | grep -v '^cmake_' | sort -u)" + if [ -z "$images" ]; then + fail "$core: no .elf targets found in the CMake graph" + failures=$((failures + 1)) + else + built=0; total=0 + for image in $images; do + total=$((total + 1)) + if ninja -C "$build_dir" "$image" \ + >"$build_dir/$image.log" 2>&1; then + built=$((built + 1)) + else + fail "$core: $image did not build" + tail -6 "$build_dir/$image.log" | sed 's/^/ /' + failures=$((failures + 1)) + fi + done + say " $core: $built of $total images linked" + fi + else + fail "$core: CMake configure failed" + tail -6 "$build_dir/configure.log" | sed 's/^/ /' + failures=$((failures + 1)) + fi + rm -rf "$build_dir" + done + fi +fi + +# -------------------------------------------------------------------------- +say "" +if [ "$failures" -eq 0 ]; then + say "All GNU toolchain checks passed." + exit 0 +fi + +echo "$failures GNU toolchain check(s) failed." +exit 1 From dec89ba9334adc6c90c48db90dd26e05258a7e29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Desbiens?= Date: Wed, 26 Aug 2026 15:58:26 -0400 Subject: [PATCH 4/4] Ran the GCC port check in CI, on dev as well as master scripts/check_gcc.sh with nothing invoking it would be a script nobody runs. This adds the workflow, modelled on clang_check.yml, and fixes a trigger gap in that file at the same time. One job, two cache steps. Arm ships AArch32 and AArch64 as separate downloads and the script needs both, so two caches keep the checks list short and let a single invocation see both compilers. The AArch32 cache path and key match cortex_m's exactly, so the two workflows share one entry rather than each holding its own copy of the same archive -- noted in a comment, because the only symptom of breaking that is a slower run. Both triggers name dev. A workflow that triggers only on master gates no pull request anybody opens; that is the defect ports_arch_check.yml carries a comment about, and it cost cortex_m three months of failing in seven seconds unnoticed. push is included as well as pull_request so dev's own history has a baseline and a bad squash-merge is caught rather than waiting for the next PR. The checksum suffix is .sha256asc and it is not interchangeable with .sha256. Arm publishes both for this release, and verified 26 Aug 2026, the .sha256 file for arm-none-eabi contains a 32-character MD5 rather than a SHA-256, so sha256sum -c on it fails with "no properly formatted checksum lines found". .sha256asc is a plain sha256sum-format line for both triples. The plan warned that this suffix had changed between releases; the sharper truth is that both suffixes exist simultaneously and one of them is not a SHA-256 at all. Recorded in a comment beside the step. Verified before writing them in rather than copied: both archive URLs and both checksum URLs resolve, the archives are xz, the checksum files are sha256sum-format for .sha256asc, and the AArch64 archive extracts to arm-gnu-toolchain-14.3.rel1-x86_64-aarch64-none-elf/bin/aarch64-none-elf-gcc, which is the path the workflow builds. The paths: lists are duplicated between push and pull_request rather than shared through a YAML anchor, deliberately: GitHub Actions' parser does not dependably honour anchors and the failure mode is the workflow refusing to parse, which is the cortex_m failure again. Ten duplicated lines are cheaper. clang_check.yml's paths: list was missing CMakeLists.txt, cmake/ and common_smp/, so that check did not run when files it reads changed -- the ports_smp example builds compile common_smp/src and its CMake stage reads the toolchain file and the top-level project. Both lists are now identical apart from each file's own name, and both say so. cortex_m is kept rather than deleted, against the plan's recommendation. It builds four ports *through CMake*, and that is the only thing exercising cmake/cortex_m*.cmake and the top-level CMakeLists for the M profile; this script's CMake stage covers cortex_r52 only. The overlap is the assembly and the C sources, not the build system, so deleting it would lose coverage rather than remove a duplicate. Said so in the workflow header. The script is passed explicit toolchain paths rather than left to find the drivers on PATH, so nothing about the runner image can decide which compiler runs, and it prints both versions it resolved. Assisted-by: Claude Code (Opus 5) --- .github/workflows/clang_check.yml | 10 ++ .github/workflows/gcc_check.yml | 175 ++++++++++++++++++++++++++++++ 2 files changed, 185 insertions(+) create mode 100644 .github/workflows/gcc_check.yml diff --git a/.github/workflows/clang_check.yml b/.github/workflows/clang_check.yml index 405033f0b..2c90c790b 100644 --- a/.github/workflows/clang_check.yml +++ b/.github/workflows/clang_check.yml @@ -10,7 +10,17 @@ on: paths: - ".github/workflows/clang_check.yml" - "scripts/check_clang.sh" + # CMakeLists.txt, cmake/ and common_smp/ were missing until 26 Aug 2026, + # so this check did not run when the files it reads changed. The + # ports_smp example builds compile common_smp/src and the CMake stage + # reads the toolchain file and the top-level project. utility/ is + # deliberately absent: the FreeRTOS and POSIX layers under it are not + # enabled by any target this workflow builds. Keep this list and + # gcc_check.yml's the same. + - "CMakeLists.txt" + - "cmake/**" - "common/**" + - "common_smp/**" - "ports/**" - "ports_arch/**" - "ports_module/**" diff --git a/.github/workflows/gcc_check.yml b/.github/workflows/gcc_check.yml new file mode 100644 index 000000000..31e1ec346 --- /dev/null +++ b/.github/workflows/gcc_check.yml @@ -0,0 +1,175 @@ +name: gcc_check + +# Builds the Arm ports with the Arm GNU toolchain, in five stages: assemble +# every assembly source of every Arm gnu port, assemble again the parts guarded +# by feature macros, compile the common C sources for one core per architecture +# profile, then link the example builds, both the script-driven ones and those +# driven by CMake. +# +# Why this exists: GCC is the project's declared default compiler (AGENTS.md, +# "The default compiler for the project is GCC 14 on Linux") and until this +# workflow landed, nothing in CI compiled a line of any port with it. The only +# cross-compilation check that ran was clang_check, so the LLVM path was better +# guarded than the GNU one, on ports whose directory is literally named gnu. +# +# What it covers: 840 assembly sources across 40 port families, 469 of them +# again behind feature macros, common/src for nine cores, 42 script-driven +# example links and the five Cortex-R52 CMake images. Every skip is printed by +# name with a reason -- run scripts/check_gcc.sh --help, or read its header. +# +# What it does not cover: it compiles and links and **executes nothing**. The +# Cortex-R52 FVP ctest suite is not part of it. RISC-V, MIPS, RX and ARC are +# outside it entirely -- RISC-V deliberately, as both its ports do assemble and +# adding them widens the toolchain download for a family that is not regressing. +# +# It does not supersede cortex_m. That workflow builds four ports *through +# CMake*, which is the only thing exercising cmake/cortex_m*.cmake and the +# top-level CMakeLists for the M profile; this script's CMake stage covers +# cortex_r52 only. The overlap is the assembly and the C sources, not the build +# system. +on: + # push as well as pull_request, so dev's own history has a baseline and a bad + # squash-merge is caught rather than waiting for the next PR to notice. dev is + # named because it is the integration branch: a workflow that triggers only on + # master does not gate any pull request anybody opens, which is the defect + # ports_arch_check.yml carries a comment about and which cost cortex_m three + # months of failing in seven seconds unnoticed. + push: + branches: [ master, dev ] + paths: + - ".github/workflows/gcc_check.yml" + - "scripts/check_gcc.sh" + - "CMakeLists.txt" + - "cmake/**" + - "common/**" + - "common_smp/**" + - "ports/**" + - "ports_arch/**" + - "ports_module/**" + - "ports_smp/**" + pull_request: + branches: [ master, dev ] + # The two lists are duplicated rather than shared through a YAML anchor. + # GitHub Actions' workflow parser does not dependably honour anchors, and + # the failure mode is the whole workflow refusing to parse -- which is the + # cortex_m failure again, a job that dies before it does anything. Ten + # duplicated lines are cheaper than that. **Edit both.** + # + # common_smp, CMakeLists.txt and cmake/ are here and are absent from + # clang_check.yml's otherwise identical list, which is a gap in that file + # and is fixed alongside this one: the ports_smp example builds compile + # common_smp/src, and the CMake stage reads the toolchain file and the + # top-level project. utility/ is deliberately absent -- the FreeRTOS and + # POSIX layers under it are not enabled by any target this workflow builds. + paths: + - ".github/workflows/gcc_check.yml" + - "scripts/check_gcc.sh" + - "CMakeLists.txt" + - "cmake/**" + - "common/**" + - "common_smp/**" + - "ports/**" + - "ports_arch/**" + - "ports_module/**" + - "ports_smp/**" + +jobs: + gnu: + runs-on: ubuntu-24.04 + + env: + # Pinned deliberately, as the runner image is: a toolchain upgrade should + # be a reviewable commit rather than something that changes underneath the + # ports. 14.3.rel1 matches AGENTS.md's GCC 14 default and the version + # cortex_m already pins. + # Releases: https://developer.arm.com/downloads/-/arm-gnu-toolchain-downloads + GCC_VERSION: 14.3.rel1 + + steps: + # Actions are pinned to a commit SHA, with the version in the trailing + # comment. A tag can be moved; a SHA cannot, so this is what makes "which + # code ran in CI" answerable from the repository. Dependabot moves these + # pins and rewrites the comment with them -- see .github/dependabot.yml. + - name: Check out the repository + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + + # Two toolchains, because Arm ships AArch32 and AArch64 as separate + # downloads and scripts/check_gcc.sh needs both -- every port maps to one of + # exactly those two triples. One job with two cache steps rather than two + # jobs, so the checks list stays short and a single script invocation sees + # both compilers. + # + # The AArch32 path and key match cortex_m's exactly, so the two workflows + # share one cache entry rather than each holding its own copy of the same + # 500MB archive. Change them together or the sharing silently stops and the + # only symptom is a slower run. + - name: Cache the AArch32 Arm GNU toolchain + id: cache-arm32 + uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 + with: + path: toolchain + key: arm-gnu-toolchain-${{ env.GCC_VERSION }}-x86_64-arm-none-eabi + + - name: Cache the AArch64 Arm GNU toolchain + id: cache-arm64 + uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 + with: + path: toolchain64 + key: arm-gnu-toolchain-${{ env.GCC_VERSION }}-x86_64-aarch64-none-elf + + # The checksum suffix is .sha256asc and not .sha256, and that is not a + # stylistic choice. Arm publishes both for this release, and for + # arm-none-eabi the .sha256 file contains a 32-character MD5 rather than a + # SHA-256 -- verified 26 Aug 2026 -- so sha256sum -c on it fails with "no + # properly formatted checksum lines found". .sha256asc is a plain + # sha256sum-format line for both triples. Do not "simplify" the suffix. + - name: Install the AArch32 Arm GNU toolchain + if: steps.cache-arm32.outputs.cache-hit != 'true' + run: | + set -eu + base="https://developer.arm.com/-/media/Files/downloads/gnu/${GCC_VERSION}/binrel" + archive="arm-gnu-toolchain-${GCC_VERSION}-x86_64-arm-none-eabi.tar.xz" + mkdir -p toolchain && cd toolchain + curl -fsSLO "$base/$archive" + curl -fsSLO "$base/$archive.sha256asc" + sha256sum -c "$archive.sha256asc" + tar xf "$archive" + rm -f "$archive" + + - name: Install the AArch64 Arm GNU toolchain + if: steps.cache-arm64.outputs.cache-hit != 'true' + run: | + set -eu + base="https://developer.arm.com/-/media/Files/downloads/gnu/${GCC_VERSION}/binrel" + archive="arm-gnu-toolchain-${GCC_VERSION}-x86_64-aarch64-none-elf.tar.xz" + mkdir -p toolchain64 && cd toolchain64 + curl -fsSLO "$base/$archive" + curl -fsSLO "$base/$archive.sha256asc" + sha256sum -c "$archive.sha256asc" + tar xf "$archive" + rm -f "$archive" + + # Only reaches apt if the runner image has stopped shipping ninja, which + # the CMake stage needs. This repository has already paid for unguarded apt + # calls: scripts/install.sh carries a long comment about apt-get update + # stalling for over two hours and taking whole regression runs with it. Do + # not turn this into an unconditional install. + - name: Ensure ninja is available + run: | + set -eu + if command -v ninja >/dev/null 2>&1; then + ninja --version + else + sudo apt-get update + sudo apt-get install -y --no-install-recommends ninja-build + fi + + # The script is told where both toolchains are rather than being left to + # find them on PATH, so nothing about the runner image can decide which + # compiler is used. The script prints both versions it resolved, which is + # what makes "was this really 14.3.rel1?" answerable from the log. + - name: Build the Arm ports with GCC + run: | + scripts/check_gcc.sh \ + --arm-none-eabi "$GITHUB_WORKSPACE/toolchain/arm-gnu-toolchain-${GCC_VERSION}-x86_64-arm-none-eabi/bin" \ + --aarch64-none-elf "$GITHUB_WORKSPACE/toolchain64/arm-gnu-toolchain-${GCC_VERSION}-x86_64-aarch64-none-elf/bin"