Skip to content

Conversation

keith-packard
Copy link

Add picolibc bits to linker scripts.
Support picolibc stdio.
Add _exit stub.
Switch to picolibc.specs

The linker appears to get confused by this section which is
relocated to CODE_RAM but loaded to FLASH. Clear things up by
forcing the '.' value back to the correct FLASH address which
will then be used by subsequent sections.

Signed-off-by: Keith Packard <[email protected]>
@keith-packard keith-packard force-pushed the picolibc branch 3 times, most recently from 8e27bff to 85833fd Compare July 27, 2025 23:20
Add picolibc bits to linker scripts.
Support picolibc stdio.
Add _exit stub.
Switch to picolibc.specs

Signed-off-by: Keith Packard <[email protected]>
@keith-packard
Copy link
Author

These are (finally) passing Zephyr tests using both SDK 0.17 and SDK 0.18-alpha4 (although each requires some additional changes which are wending their way upstream). I think they're ready for review and help getting them upstream.

Comment on lines +195 to +196
/* Reset current position for subsequent sections */
. = LOADADDR(.ER_CODE_SRAM) + SIZEOF(.ER_CODE_SRAM);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How did the linker get confused exactly? Is this really needed?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

. got set to LOADADDR instead of ADDR when building with binutils 2.43. I'm afraid that after spending several hours chasing this down, I didn't dig into the linker code to figure out precisely why that happened.

Copy link
Collaborator

@tomi-font tomi-font left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Had a chat with upstream about these (picolibc) changes. Let's keep them only in this fork until they're not needed anymore (TF-M is moving away from C library usage), in the next release or the one following it.
But it would be good to have someone who understands this a bit to review the changes. Don't know who that could be. cc @frkv @d3zd3z @ceolin @dleach02 @Vge0rge

@keith-packard
Copy link
Author

Had a chat with upstream about these (picolibc) changes. Let's keep them only in this fork until they're not needed anymore (TF-M is moving away from C library usage), in the next release or the one following it. But it would be good to have someone who understands this a bit to review the changes. Don't know who that could be. cc @frkv @d3zd3z @ceolin @dleach02 @Vge0rge

Sounds good. I'll keep running tests as this series moves forward. This is not buildable using SDK 0.17.2 because of a last-minute oops in that release, but it should be buildable with the upcoming SDK 0.17.3.

@frkv
Copy link

frkv commented Jul 29, 2025

I recommend @wearyzen and @adeaarm give it a quick look from TF-M's perspective.

The Clang/LLVM toolchain for TF-M was added with no dependency on libc and/or picolib in the core TF-M code, but you still see references to nano.specs in the GNUARM toolchain

Zephyr, making this choice for GNUARM toolchain (this change), will take any penalty related to support, any security advisories etc... But the choice to go to picolibc is an active choice in the Zephyr community, and in extension it will impact any vendor who makes use of standard c library function in PSA crypto and PSA crypto driver build as well as in bootloaders...

With regards to these commits, I think we should consider them to be marked as commits emitted from zephyr integration, unless they are possible to add upstream in the TF-M project... If they are out-of-tree patches required for Zephyr integration, they would need to be maintained across updated versions of TF-M in our fork

@tomi-font tomi-font requested a review from wearyzen July 29, 2025 09:28
@tomi-font
Copy link
Collaborator

With regards to these commits, I think we should consider them to be marked as commits emitted from zephyr integration

Yeah this is something we've agreed on and I think just needs to be implemented (documenting the practice basically). In the meantime I don't think we can require that of anyone yet.

@Anton-TF
Copy link
Contributor

True, TF-M plans to remove libc from all secure binaries (BL1, BL2, tfm_s) for Clang/LLVM and GCC toolchains at least.
As part of this effort, we also intend to clean up and streamline the linker scripts.

Additionally, you might want to consider these recent fixes in the scripts:
https://review.trustedfirmware.org/c/TF-M/trusted-firmware-m/+/40014
https://review.trustedfirmware.org/c/TF-M/trusted-firmware-m/+/40068

@keith-packard
Copy link
Author

Sounds like any libc-specific changes will be transient then, which will be nice.

keith-packard added a commit to keith-packard/zephyr that referenced this pull request Aug 11, 2025
This adds linker script bits and compiler options so that trusted-firmware-m will
build with picolibc.

This has not been merged to the Zephyr trusted-firmware-m repository yet, that PR is
zephyrproject-rtos/trusted-firmware-m#134

Signed-off-by: Keith Packard <[email protected]>
keith-packard added a commit to keith-packard/zephyr that referenced this pull request Aug 11, 2025
This adds linker script bits and compiler options so that
trusted-firmware-m will build with picolibc.

This has not been merged to the Zephyr trusted-firmware-m repository yet:

zephyrproject-rtos/trusted-firmware-m#134

Signed-off-by: Keith Packard <[email protected]>
keith-packard added a commit to keith-packard/zephyr that referenced this pull request Aug 19, 2025
This adds linker script bits and compiler options so that
trusted-firmware-m will build with picolibc.

This has not been merged to the Zephyr trusted-firmware-m repository yet:

zephyrproject-rtos/trusted-firmware-m#134

Signed-off-by: Keith Packard <[email protected]>
@wearyzen
Copy link
Collaborator

While trying to build the non-secure MPS4 board with this PR and Zephyr SDK 0.18.0-alpha4 we see below error:

west build -p -b mps4/corstone320/fvp/ns samples/hello_world/ -t run
...
/home/zephyr-sdk-0.18.0-alpha4/gnu/arm-zephyr-eabi/bin/../lib/gcc/arm-zephyr-eabi/14.3.0/../../../../arm-zephyr-eabi/bin/ld: (.text._start+0x30): undefined reference to `__data_source'
/home/zephyr-sdk-0.18.0-alpha4/gnu/arm-zephyr-eabi/bin/../lib/gcc/arm-zephyr-eabi/14.3.0/../../../../arm-zephyr-eabi/bin/ld: (.text._start+0x34): undefined reference to `__data_start'
/home/zephyr-sdk-0.18.0-alpha4/gnu/arm-zephyr-eabi/bin/../lib/gcc/arm-zephyr-eabi/14.3.0/../../../../arm-zephyr-eabi/bin/ld: (.text._start+0x38): undefined reference to `__bss_size'
/home/zephyr-sdk-0.18.0-alpha4/gnu/arm-zephyr-eabi/bin/../lib/gcc/arm-zephyr-eabi/14.3.0/../../../../arm-zephyr-eabi/bin/ld: (.text._start+0x3c): undefined reference to `__bss_start'
/home/zephyr-sdk-0.18.0-alpha4/gnu/arm-zephyr-eabi/bin/../lib/gcc/arm-zephyr-eabi/14.3.0/../../../../arm-zephyr-eabi/bin/ld: (.text._start+0x40): undefined reference to `__tls_base'
/home/zephyr-sdk-0.18.0-alpha4/gnu/arm-zephyr-eabi/bin/../lib/gcc/arm-zephyr-eabi/14.3.0/../../../../arm-zephyr-eabi/bin/ld: /home/zephyr-sdk-0.18.0-alpha4/gnu/arm-zephyr-eabi/bin/../lib/gcc/arm-zephyr-eabi/14.3.0/../../../../arm-zephyr-eabi/lib/thumb/v8-m.main/nofp/space/libc.a(libc_picolib_machine_arm_set_tls.c.o): in function `_set_tls':
set_tls.c:(.text._set_tls+0xc): undefined reference to `__arm32_tls_tcb_offset'

Referring to the changes in this PR, I tried below patch and it seems to fix the issue:

git diff
diff --git a/bl1/bl1_2/bl1_dummy_rotpk.prv b/bl1/bl1_2/bl1_dummy_rotpk.prv
index bf011cd4d..b6bf9b600 100644
Binary files a/bl1/bl1_2/bl1_dummy_rotpk.prv and b/bl1/bl1_2/bl1_dummy_rotpk.prv differ
diff --git a/platform/ext/target/arm/mps4/common/device/source/gcc/mps4_corstone3xx_bl1_1.ld b/platform/ext/target/arm/mps4/common/device/source/gcc/mps4_corstone3xx_bl1_1.ld
index 44f04021a..7fad80960 100644
--- a/platform/ext/target/arm/mps4/common/device/source/gcc/mps4_corstone3xx_bl1_1.ld
+++ b/platform/ext/target/arm/mps4/common/device/source/gcc/mps4_corstone3xx_bl1_1.ld
@@ -160,6 +160,25 @@ SECTIONS
     } > RAM

     bss_size = __bss_end__ - __bss_start__;
+    /* --- add after the .bss section --- */
+    PROVIDE( __bss_start = __bss_start__ );
+    PROVIDE( __bss_end   = __bss_end__ );
+    PROVIDE( __bss_size  = __bss_end - __bss_start );
+
+    PROVIDE( __data_start  = ADDR(.data) );
+    PROVIDE( __data_end    = __data_end__ );
+    PROVIDE( __data_source = LOADADDR(.data) );
+    PROVIDE( __data_size   = __data_end - __data_start );
+
+    /* BL1_1 doesn’t use TLS, but picolibc’s _set_tls needs these present */
+    PROVIDE( __tls_base = 0 );
+    PROVIDE( __tls_align = 8 );
+    PROVIDE( __arm32_tls_tcb_offset = 8 );
+
+    /* --- add after the .heap section (where __HeapBase/Limit are set) --- */
+    PROVIDE( __heap_start = __HeapBase );
+    PROVIDE( __heap_end   = __HeapLimit );
+

 #if defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U)
     .msp_stack (NOLOAD) : ALIGN(32)
diff --git a/platform/ext/target/arm/mps4/common/device/source/gcc/mps4_corstone3xx_bl1_2.ld b/platform/ext/target/arm/mps4/common/device/source/gcc/mps4_corstone3xx_bl1_2.ld
index 83aaf144f..9151ff3a0 100644
--- a/platform/ext/target/arm/mps4/common/device/source/gcc/mps4_corstone3xx_bl1_2.ld
+++ b/platform/ext/target/arm/mps4/common/device/source/gcc/mps4_corstone3xx_bl1_2.ld
@@ -162,6 +162,25 @@ SECTIONS

     bss_size = __bss_end__ - __bss_start__;

+    /* --- add after the .bss section --- */
+    PROVIDE( __bss_start = __bss_start__ );
+    PROVIDE( __bss_end   = __bss_end__ );
+    PROVIDE( __bss_size  = __bss_end - __bss_start );
+
+    PROVIDE( __data_start  = ADDR(.data) );
+    PROVIDE( __data_end    = __data_end__ );
+    PROVIDE( __data_source = LOADADDR(.data) );
+    PROVIDE( __data_size   = __data_end - __data_start );
+
+    /* BL1_1 doesn’t use TLS, but picolibc’s _set_tls needs these present */
+    PROVIDE( __tls_base = 0 );
+    PROVIDE( __tls_align = 8 );
+    PROVIDE( __arm32_tls_tcb_offset = 8 );
+
+    /* --- add after the .heap section (where __HeapBase/Limit are set) --- */
+    PROVIDE( __heap_start = __HeapBase );
+    PROVIDE( __heap_end   = __HeapLimit );
+
 #if defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U)
     .msp_stack (NOLOAD) : ALIGN(32)
     {
(END)

I am not a linker script expert but if above change looks good then please let me know if you would like to include it in this PR.
Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants