Skip to content

Commit d0c75f3

Browse files
keith-packardcarlescufi
authored andcommitted
lib/libc: Add picolibc support (aarch32, aarch64 and RISC-V) [v21]
Picolibc is a fork of newlib designed and tested on embedded systems. It offers a smaller memory footprint (both ROM and RAM), and native TLS support, which uses the Zephyr TLS support. By default, the full printf version is included in the executable, which includes exact floating point and long long input and output. A configuration option has been added to switch to the integer-only version (which also omits long long support). Here are some size comparisons using qemu-cortex-m3 and this application (parameters passed to printf to avoid GCC optimizing it into puts): void main(void) { printf("Hello World! %s %d\n", CONFIG_BOARD, 12); } FLASH SRAM minimal 8696 3952 picolibc int 7600 3960 picolibc float 12304 3960 newlib-nano int 11696 4128 newlib-nano float 30516 4496 newlib 34800 6112 --- v2: Include picolibc-tls.ld v3: Document usage in guides/c_library.rst and getting_started/toolchain_other_x_compilers.rst v4: Lost the lib/libc/picolibc directory somehow! v5: Add PICOLIBC_ALIGNED_HEAP_SIZE configuration option. Delete PICOLIBC_SEMIHOST option support code v6: Don't allocate static RAM for TLS values; TLS values only need to be allocated for each thread. v7: Use arm coprocessor for TLS pointer storage where supported for compatibility with the -mtp=cp15 compiler option (or when the target cpu type selects this option) Add a bunch of tests Round TLS segment up to stack alignment so that overall stack remains correctly aligned Add aarch64 support Rebase to upstream head v8: Share NEWLIB, NEWLIB_NANO and PICOLIBC library configuration variables in a single LIBC_PARTITIONS variable instead of having separate PICOLIBC_PART and NEWLIB_PART variables. v9: Update docs to reference pending sdk-ng support for picolibc v10: Support memory protection by creating a partition for picolibc shared data and any pre-defined picolibc heap. v11: Fix formatting in arch/arm/core/aarch64/switch.S v12: Remove TLS support from this patch now that TLS is upstream Require THREAD_LOCAL_STORAGE when using PICOLIBC for architectures that support it. v13: Merge errno changes as they're only needed for picolibc. Adapt cmake changes suggested by Torsten Tejlmand Rasmussen v14: Update to picolibc 1.7 and newer (new stdin/stdout/stderr ABI) v15: Respond to comments from dcpleung: * switch kernel/errno to use CONFIG_LIBC_ERRNO instead of CONFIG_PICOLIBC * Add comment to test/lib/sprintf as to why the %n test was disabled for picolibc. v16: Switch picolibc to a module built with Zephyr. This eliminates toolchain dependencies and allows compiler settings for Zephyr to also be applied to picolibc. v17: Provide Zephyr-specific 'abort' implementation. Support systems with MMU v18: Allow use of toolchain picolibc version. v19: Use zephyr/ for zephyr headers v20: Add locking Use explicit commit for picolibc module v21: Create PICOLIBC_SUPPORTED config param. Set on arc, arm, arm64, mips and riscv architectures. Signed-off-by: Keith Packard <keithp@keithp.com>
1 parent e6d27c7 commit d0c75f3

File tree

9 files changed

+712
-10
lines changed

9 files changed

+712
-10
lines changed

‎CMakeLists.txt‎

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -253,8 +253,10 @@ endif()
253253
# @Intent: Set compiler specific macro inclusion of AUTOCONF_H
254254
zephyr_compile_options("SHELL: $<TARGET_PROPERTY:compiler,imacros> ${AUTOCONF_H}")
255255

256-
# @Intent: Set compiler specific flag for bare metal freestanding option
257-
zephyr_compile_options($<TARGET_PROPERTY:compiler,freestanding>)
256+
if(NOT CONFIG_PICOLIBC)
257+
# @Intent: Set compiler specific flag for bare metal freestanding option
258+
zephyr_compile_options($<TARGET_PROPERTY:compiler,freestanding>)
259+
endif()
258260

259261
# @Intent: Set compiler specific flag for tentative definitions, no-common
260262
zephyr_compile_options($<TARGET_PROPERTY:compiler,no_common>)
@@ -695,7 +697,14 @@ add_custom_command(
695697
DEPENDS ${syscalls_subdirs_trigger} ${PARSE_SYSCALLS_HEADER_DEPENDS}
696698
)
697699

698-
add_custom_target(${SYSCALL_LIST_H_TARGET} DEPENDS ${syscall_list_h})
700+
# Make sure Picolibc is built before the rest of the system; there's no explicit
701+
# reference to any of the files as they're all picked up by various compiler
702+
# settings
703+
if(CONFIG_PICOLIBC_USE_MODULE)
704+
set(picolibc_dependency PicolibcBuild)
705+
endif()
706+
707+
add_custom_target(${SYSCALL_LIST_H_TARGET} DEPENDS ${syscall_list_h} ${picolibc_dependency})
699708

700709
set_property(TARGET ${SYSCALL_LIST_H_TARGET}
701710
APPEND PROPERTY
@@ -929,10 +938,13 @@ if(CONFIG_USERSPACE)
929938
set(OBJ_FILE_DIR "${PROJECT_BINARY_DIR}/../")
930939

931940
if(CONFIG_NEWLIB_LIBC)
932-
set(NEWLIB_PART -l libc.a z_libc_partition -l libm.a z_libc_partition)
941+
set(LIBC_PART -l libc.a z_libc_partition -l libm.a z_libc_partition)
933942
endif()
934943
if(CONFIG_NEWLIB_LIBC_NANO)
935-
set(NEWLIB_PART -l libc_nano.a z_libc_partition -l libm_nano.a z_libc_partition)
944+
set(LIBC_PART -l libc_nano.a z_libc_partition -l libm_nano.a z_libc_partition)
945+
endif()
946+
if(CONFIG_PICOLIBC)
947+
set(LIBC_PART -l libc.a z_libc_partition)
936948
endif()
937949

938950
add_custom_command(
@@ -943,7 +955,7 @@ if(CONFIG_USERSPACE)
943955
-o ${APP_SMEM_UNALIGNED_LD}
944956
$<$<BOOL:${APP_SMEM_PINNED_UNALIGNED_LD}>:--pinoutput=${APP_SMEM_PINNED_UNALIGNED_LD}>
945957
${APP_SMEM_PINNED_PARTITION_LIST_ARG}
946-
${NEWLIB_PART}
958+
${LIBC_PART}
947959
$<TARGET_PROPERTY:zephyr_property_target,COMPILE_OPTIONS>
948960
$<$<BOOL:${CMAKE_VERBOSE_MAKEFILE}>:--verbose>
949961
DEPENDS
@@ -981,7 +993,7 @@ if (CONFIG_USERSPACE)
981993
-o ${APP_SMEM_ALIGNED_LD}
982994
$<$<BOOL:${APP_SMEM_PINNED_ALIGNED_LD}>:--pinoutput=${APP_SMEM_PINNED_ALIGNED_LD}>
983995
${APP_SMEM_PINNED_PARTITION_LIST_ARG}
984-
${NEWLIB_PART}
996+
${LIBC_PART}
985997
$<TARGET_PROPERTY:zephyr_property_target,COMPILE_OPTIONS>
986998
$<$<BOOL:${CMAKE_VERBOSE_MAKEFILE}>:--verbose>
987999
DEPENDS

‎boards/x86/qemu_x86/qemu_x86_tiny.ld‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,14 @@ MEMORY
143143

144144
#endif /* CONFIG_NEWLIB_LIBC */
145145

146+
#ifdef CONFIG_PICOLIBC
147+
/* For Picolibc libc-hook.c. */
148+
#define LIB_C_IN_SECT(lsect) \
149+
*liblib__libc__picolibc.a:libc-hooks.c.obj(.##lsect) \
150+
*liblib__libc__picolibc.a:libc-hooks.c.obj(.##lsect##.*)
151+
152+
#endif /* CONFIG_PICOLIBC */
153+
146154
/*
147155
* For drivers that are usually used (e.g. serial)
148156
*/

‎include/zephyr/sys/libc-hooks.h‎

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
* that need to call into the kernel as system calls
1818
*/
1919

20-
#if defined(CONFIG_NEWLIB_LIBC) || defined(CONFIG_ARCMWDT_LIBC)
20+
#if defined(CONFIG_NEWLIB_LIBC) || defined(CONFIG_ARCMWDT_LIBC) || defined(CONFIG_PICOLIBC)
2121

2222
/* syscall generation ignores preprocessor, ensure this is defined to ensure
2323
* we don't have compile errors
@@ -57,7 +57,21 @@ extern struct k_mem_partition z_malloc_partition;
5757
*/
5858
#define Z_MALLOC_PARTITION_EXISTS 1
5959
#endif /* CONFIG_MINIMAL_LIBC_MALLOC_ARENA_SIZE > 0 */
60-
#endif /* CONFIG_MINIMAL_LIBC */
60+
#elif defined(CONFIG_PICOLIBC)
61+
/* If we are using picolibc, the heap arena is in one of two areas:
62+
* - If we have an MPU that requires power of two alignment, the heap bounds
63+
* must be specified in Kconfig via CONFIG_PICOLIBC_ALIGNED_HEAP_SIZE.
64+
* - Otherwise, the heap arena on most arches starts at a suitably
65+
* aligned base addreess after the `_end` linker symbol, through to the end
66+
* of system RAM.
67+
*/
68+
#if (!defined(CONFIG_MPU_REQUIRES_POWER_OF_TWO_ALIGNMENT) || \
69+
(defined(CONFIG_MPU_REQUIRES_POWER_OF_TWO_ALIGNMENT) && \
70+
CONFIG_PICOLIBC_ALIGNED_HEAP_SIZE))
71+
#define Z_MALLOC_PARTITION_EXISTS 1
72+
extern struct k_mem_partition z_malloc_partition;
73+
#endif
74+
#endif /* CONFIG_PICOLIBC */
6175

6276
#ifdef Z_MALLOC_PARTITION_EXISTS
6377
/* Memory partition containing the libc malloc arena. Configuration controls
@@ -67,7 +81,7 @@ extern struct k_mem_partition z_malloc_partition;
6781
#endif
6882

6983
#if defined(CONFIG_NEWLIB_LIBC) || defined(CONFIG_STACK_CANARIES) || \
70-
defined(CONFIG_NEED_LIBC_MEM_PARTITION)
84+
defined(CONFIG_PICOLIBC) || defined(CONFIG_NEED_LIBC_MEM_PARTITION)
7185
/* - All newlib globals will be placed into z_libc_partition.
7286
* - Minimal C library globals, if any, will be placed into
7387
* z_libc_partition.

‎lib/libc/CMakeLists.txt‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,6 @@ elseif(CONFIG_MINIMAL_LIBC)
88
add_subdirectory(minimal)
99
elseif(CONFIG_ARMCLANG_STD_LIBC)
1010
add_subdirectory(armstdc)
11+
elseif(CONFIG_PICOLIBC)
12+
add_subdirectory(picolibc)
1113
endif()

‎lib/libc/Kconfig‎

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,13 @@ config SUPPORT_MINIMAL_LIBC
1515
bool
1616
default y
1717

18+
config PICOLIBC_SUPPORTED
19+
bool
20+
depends on ARC || ARM || ARM64 || MIPS || RISCV
21+
default y
22+
help
23+
Selected when the target has support for picolibc.
24+
1825
choice LIBC_IMPLEMENTATION
1926
prompt "C Library Implementation"
2027
default EXTERNAL_LIBC if NATIVE_APPLICATION
@@ -29,6 +36,16 @@ config MINIMAL_LIBC
2936
help
3037
Build with minimal C library.
3138

39+
config PICOLIBC
40+
bool "Picolibc library"
41+
select LIBC_ERRNO
42+
select THREAD_LOCAL_STORAGE if ARCH_HAS_THREAD_LOCAL_STORAGE
43+
depends on !NATIVE_APPLICATION
44+
help
45+
Build with picolibc library. The picolibc library is built as
46+
a module if PICOLIBC_MODULE is set, otherwise picolibc is
47+
expected to be provided by the toolchain.
48+
3249
config NEWLIB_LIBC
3350
bool "Newlib C library"
3451
depends on !NATIVE_APPLICATION
@@ -53,6 +70,12 @@ endchoice # LIBC_IMPLEMENTATION
5370
config HAS_NEWLIB_LIBC_NANO
5471
bool
5572

73+
if PICOLIBC
74+
75+
source "lib/libc/picolibc/Kconfig"
76+
77+
endif # PICOLIBC
78+
5679
if NEWLIB_LIBC
5780

5881
config NEWLIB_LIBC_NANO

‎lib/libc/picolibc/CMakeLists.txt‎

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# SPDX-License-Identifier: Apache-2.0
2+
3+
zephyr_library()
4+
zephyr_library_sources(libc-hooks.c)
5+
6+
if(NOT CONFIG_PICOLIBC_USE_MODULE)
7+
8+
# Use picolibc provided with the toolchain
9+
10+
zephyr_compile_options(--specs=picolibc.specs)
11+
zephyr_compile_definitions(_POSIX_C_SOURCE=200809)
12+
zephyr_link_libraries(-T/dev/null --specs=picolibc.specs c -lgcc)
13+
if(CONFIG_PICOLIBC_IO_FLOAT)
14+
zephyr_compile_definitions(PICOLIBC_DOUBLE_PRINTF_SCANF)
15+
zephyr_link_libraries(-DPICOLIBC_DOUBLE_PRINTF_SCANF)
16+
else()
17+
zephyr_compile_definitions(PICOLIBC_INTEGER_PRINTF_SCANF)
18+
zephyr_link_libraries(-DPICOLIBC_INTEGER_PRINTF_SCANF)
19+
endif()
20+
21+
endif()

‎lib/libc/picolibc/Kconfig‎

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
# Copyright © 2021 Amazon.com, Inc. or its affiliates.
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
config PICOLIBC_USE_MODULE
5+
bool "Use picolibc module"
6+
default y
7+
select PICOLIBC_MODULE
8+
help
9+
Use picolibc module instead of picolibc included with toolchain
10+
11+
config PICOLIBC_ALIGNED_HEAP_SIZE
12+
int "Picolibc aligned heap size (bytes)"
13+
depends on MPU_REQUIRES_POWER_OF_TWO_ALIGNMENT
14+
depends on USERSPACE
15+
default 0
16+
help
17+
If user mode is enabled, and MPU hardware has requirements that
18+
regions be sized to a power of two and aligned to their size,
19+
and user mode threads need to access this heap, then this is necessary
20+
to properly define an MPU region for the heap.
21+
22+
If this is left at 0, then remaining system RAM will be used for this
23+
area and it may not be possible to program it as an MPU region.
24+
25+
config PICOLIBC_LIBC_MAX_MAPPED_REGION_SIZE
26+
int "Maximum memory mapped for picolibc heap"
27+
depends on MMU
28+
default 1048576
29+
help
30+
On MMU-based systems, indicates the maximum amount of memory which
31+
will be used for the picolibc malloc() heap. The actual amount of
32+
memory used will be the minimum of this value and the amount of
33+
free physical memory at kernel boot.
34+
35+
config PICOLIBC_IO_LONG_LONG
36+
bool "support for long long in integer-only printf/scanf"
37+
default n
38+
help
39+
Includes support for long long in integer-only printf/scanf. long long
40+
types are always supported in the floating-point versions.
41+
42+
config PICOLIBC_IO_FLOAT
43+
bool "support for floating point values in printf/scanf"
44+
default n
45+
help
46+
Include floating point support in printf/scanf functions.
47+
48+
if PICOLIBC_USE_MODULE
49+
50+
if PICOLIBC
51+
choice PICOLIBC_OPTIMIZATIONS
52+
prompt "Optimization level"
53+
default PICOLIBC_SIZE_OPTIMIZATIONS if SIZE_OPTIMIZATIONS
54+
default PICOLIBC_SPEED_OPTIMIZATIONS if SPEED_OPTIMIZATIONS
55+
default PICOLIBC_DEBUG_OPTIMIZATIONS if DEBUG_OPTIMIZATIONS
56+
default PICOLIBC_NO_OPTIMIZATIONS if NO_OPTIMIZATIONS
57+
help
58+
Note that these flags shall only control the compiler
59+
optimization level for picolibc, not the level for the
60+
rest of Zephyr
61+
62+
config PICOLIBC_SIZE_OPTIMIZATIONS
63+
bool "Optimize for size"
64+
help
65+
Compiler optimizations will be set to -Os independently of other
66+
options.
67+
68+
config PICOLIBC_SPEED_OPTIMIZATIONS
69+
bool "Optimize for speed"
70+
help
71+
Compiler optimizations will be set to -O2 independently of other
72+
options.
73+
74+
config PICOLIBC_DEBUG_OPTIMIZATIONS
75+
bool "Optimize debugging experience"
76+
help
77+
Compiler optimizations will be set to -Og independently of other
78+
options.
79+
80+
config PICOLIBC_NO_OPTIMIZATIONS
81+
bool "Optimize nothing"
82+
help
83+
Compiler optimizations will be set to -O0 independently of other
84+
options.
85+
86+
endchoice
87+
88+
config PICOLIBC_FAST_STRCMP
89+
bool "always use fast strcmp paths"
90+
default y
91+
help
92+
This provides a faster strcmp version even when libc is
93+
built in space-optimized mode
94+
95+
config PICOLIBC_IO_C99_FORMATS
96+
bool "support C99 format additions in printf/scanf"
97+
default y
98+
help
99+
Includes support for hex floats (in floating-point version) and j, z,
100+
t size modifiers.
101+
102+
config PICOLIBC_IO_POS_ARGS
103+
bool "Support POSIX positional args (e.g. %$1d) in printf/scanf"
104+
default y
105+
depends on !PICOLIBC_IO_FLOAT
106+
help
107+
Includes support for positional args (e.g. $1) in integer-only printf
108+
and scanf. Positional args are always supported in the floating-point
109+
versions.
110+
111+
config PICOLIBC_IO_FLOAT_EXACT
112+
bool "support for exact float/string conversion"
113+
default y
114+
depends on PICOLIBC_USE_MODULE
115+
help
116+
Uses Ryu algorithm for exact binary/decimal float conversions.
117+
This ensures that printf values with enough digits can be
118+
fed to scanf and generate exactly the same binary value.
119+
120+
config PICOLIBC_LOCALE_INFO
121+
bool "support locales in libc functions"
122+
default n
123+
depends on PICOLIBC_USE_MODULE
124+
help
125+
Includes code for basic locale support
126+
127+
config PICOLIBC_LOCALE_EXTENDED_INFO
128+
bool "support extended locales in libc functions"
129+
default n
130+
depends on PICOLIBC_USE_MODULE
131+
help
132+
Includes code for extended locale support
133+
134+
config PICOLIBC_MULTIBYTE
135+
bool "support multibyte functions in libc"
136+
default n
137+
depends on PICOLIBC_USE_MODULE
138+
help
139+
Includes code for multi-byte characters
140+
141+
config PICOLIBC_PICOEXIT
142+
bool "use smaller atexit/onexit implementation"
143+
default y
144+
depends on PICOLIBC_USE_MODULE
145+
help
146+
Provides a simpler atexit/onexit implementation that doesn't use
147+
malloc, but only supports a small number (32) of exit handlers.
148+
149+
config PICOLIBC_MULTITHREAD
150+
bool "support multiple threads using retargetable locking API"
151+
default y
152+
depends on PICOLIBC_USE_MODULE
153+
help
154+
Protects shared data structures in libc with mutexes that use
155+
an API which can be retargeted to OS provided routines.
156+
157+
config PICOLIBC_GLOBAL_ERRNO
158+
bool "use a single global variable for errno"
159+
depends on PICOLIBC_USE_MODULE
160+
help
161+
Picolibc usually uses a TLS variable for errno, ensuring that
162+
multiple threads have a reliable mechanism for detecting libc
163+
exceptions. This option switches to a single global errno variable,
164+
which can be used to avoid TLS variable usage by the library if
165+
necessary.
166+
167+
endif
168+
169+
endif

0 commit comments

Comments
 (0)