Picolibc

Picolibc is a complete C library implementation written for the embedded systems, targeting C17 (ISO/IEC 9899:2018) and POSIX 2018 (IEEE Std 1003.1-2017) standards. Picolibc is an external open source project which is provided for Zephyr as a module, and included as part of the Zephyr SDK in precompiled form for each supported architecture (libc.a).

Note

Picolibc is also available for other 3rd-party toolchains, such as GNU Arm Embedded.

Zephyr implements the “API hook” functions that are invoked by the C standard library functions in the Picolibc. These hook functions are implemented in lib/libc/picolibc/libc-hooks.c and translate the library internal system calls to the equivalent Zephyr API calls.

Picolibc Module

When built as a Zephyr module, there are several configuration knobs available to adjust the feature set in the library, balancing what the library supports versus the code size of the resulting functions. Because the standard C++ library must be compiled for the target C library, the Picolibc module cannot be used with applications which use the standard C++ library. Building the Picolibc module will increase the time it takes to compile the application.

The Picolibc module can be enabled by selecting CONFIG_PICOLIBC_USE_MODULE in the application configuration file.

Toolchain Picolibc

Starting with version 0.16, the Zephyr SDK includes precompiled versions of Picolibc for every target architecture, along with precompiled versions of libstdc++.

The toolchain version of Picolibc can be enabled by de-selecting CONFIG_PICOLIBC_USE_MODULE in the application configuration file.

Formatted Output

Picolibc supports all standard C formatted input and output functions, including printf(), fprintf(), sprintf() and sscanf().

Picolibc formatted input and output function implementation supports all format specifiers defined by the C17 and POSIX 2018 standards with the following exceptions:

Printk, cbprintf and friends

When using Picolibc, Zephyr formatted output functions are implemented in terms of stdio calls. This includes:

  • printk, snprintk and vsnprintk

  • cbprintf and cbvprintf

  • fprintfcb, vfprintfcb, printfcb, vprintfcb, snprintfcb and vsnprintfcb

When using tagged args (CONFIG_CBPRINTF_PACKAGE_SUPPORT_TAGGED_ARGUMENTS and CBPRINTF_PACKAGE_ARGS_ARE_TAGGED), calls to cbpprintf will not use Picolibc, so formatting of output using those code will differ from Picolibc results as the cbprintf functions are not completely C/POSIX compliant.

Math Functions

Picolibc provides full C17/IEEE STD 754-2019 support for float, double and long double math operations, except for long double versions of the Bessel functions.

Thread Local Storage

Picolibc uses Thread Local Storage (TLS) (where supported) for data which is supposed to remain local to each thread, like errno. This means that TLS support is enabled when using Picolibc. As all TLS variables are allocated out of the thread stack area, this can affect stack size requirements by a few bytes.

C Library Local Variables

Picolibc uses a few internal variables for things like heap management. These are collected in a dedicated memory partition called z_libc_partition. Applications using CONFIG_USERSPACE and memory domains must ensure that this partition is included in any domain active during Picolibc calls.

Dynamic Memory Management

Picolibc implements an internal heap allocator to manage the memory blocks used by the standard dynamic memory management interface functions (for example, malloc() and free()).

The only interface between the Picolibc dynamic memory management functions and the Zephyr-side libc hooks is the sbrk() function, which is used by Picolibc to manage the size of the memory pool reserved for its internal heap allocator.

The sbrk() hook function, implemented in libc-hooks.c, handles the memory pool size change requests from Picolibc and ensures that the Picolibc internal heap allocator memory pool size does not exceed the amount of available memory space by returning an error when the system is out of memory.

When userspace is enabled, the Picolibc internal heap allocator memory pool is placed in a dedicated memory partition called z_malloc_partition, which can be accessed from the user mode threads.

The amount of memory space available for the Picolibc heap is set by the CONFIG_PICOLIBC_HEAP_SIZE, or the amount of free memory available, whichever is smallest. Set CONFIG_PICOLIBC_HEAP_SIZE to -1 to always use the amount of free memory available.

  • When MMU is enabled (CONFIG_MMU is selected), the amount of free memory available is determined at runtime with the k_mem_free_get() function.

  • When MPU is enabled and the MPU requires power-of-two partition size, then CONFIG_PICOLIBC_HEAP_SIZE (if not -1) must be set to a power of two value.

  • Otherwise, the amount of free memory available is equal to the amount of unallocated memory in the SRAM region as determined at compile time.

The standard dynamic memory management interface functions implemented by Picolibc are thread safe and may be simultaneously called by multiple threads.