Picolibc: A C Standard Library for Embedded Systems

Picolibc is a C standard library suitable for small microcontroller embedded systems, which can operate in low memory (RAM) devices. Picolibc is an upgraded version of “newlib-nano” that lacks a mature stdio lib, using a lightweight stdio lib from avrlibc, making it more suitable for low memory embedded devices. Zephyr introduced Picolibc in v3.3.0, and starting from v3.5.0, Picolibc is set as the default standard C library.

Picolibc is a complete C library implementation written for embedded systems, targeting C17 (ISO/IEC 9899:2018) and POSIX 2018 (IEEE Std 1003.1-2017) standards. Picolibc is an external open-source project, and Zephyr imports Picolibc in the following two ways:

  1. As a module
  2. As part of the Zephyr SDK, included in precompiled form in each supported architecture toolchain (libc.a)

Picolibc Module

As a module, Picolibc will be placed by default under modules/lib/picolibc. When configuring CONFIG_PICOLIBC_USE_MODULE=y, the Picolibc module code will be compiled directly. To update the Picolibc module to a newer version, the Picolibc version bundled with the Zephyr SDK toolchain must also be updated.

Zephyr adjusts the functionality set in the Picolibc library through the following configurations to balance the support range of the library and the code size of the generated functions.

  • CONFIG_PICOLIBC_FAST_STRCMP
  • CONFIG_PICOLIBC_IO_C99_FORMATS
  • CONFIG_PICOLIBC_IO_LONG_LONG
  • CONFIG_PICOLIBC_IO_PERCENT_B
  • CONFIG_PICOLIBC_IO_FLOAT
  • CONFIG_PICOLIBC_IO_FLOAT_EXACT
  • CONFIG_PICOLIBC_LOCALE_INFO
  • CONFIG_PICOLIBC_LOCALE_EXTENDED_INFO
  • CONFIG_PICOLIBC_MULTIBYTE
  • CONFIG_PICOLIBC_MULTITHREAD
  • CONFIG_THREAD_LOCAL_STORAGE
  • CONFIG_PICOLIBC_GLOBAL_ERRNO
  • CONFIG_SIZE_OPTIMIZATIONS

Points to note when using the Picolibc module:

  • Since the standard C++ library must be compiled against the target C library, the Picolibc module cannot be used in applications that use the standard C++ library.
  • Building the Picolibc module will increase the time required to compile the application.
  • When updating the Picolibc module to a newer version, the bundled toolchain version in the Zephyr SDK must also be updated to match the Picolibc version.

Picolibc in Toolchain

Starting from Zephyr SDK 0.16, a precompiled version of Picolibc for each target architecture is included, along with a precompiled version of libstdc++. By default, CONFIG_PICOLIBC_USE_MODULE=n will directly use the Picolibc in the toolchain. It is recommended to use the corresponding recommended version of the Zephyr SDK according to the Zephyr release version to ensure consistency between the bundled Picolibc module and the precompiled Picolibc version in the toolchain.

C Library Formatted Output

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

The implementation of formatted input and output functions in Picolibc supports all format specifiers defined in the C17 and POSIX 2018 standards, with the following exceptions:

  • Floating-point format specifiers (e.g., %f) require enabling CONFIG_PICOLIBC_IO_FLOAT.
  • Long long integer format specifiers (e.g., %lld) require enabling CONFIG_PICOLIBC_IO_LONG_LONG. This option will be automatically enabled when CONFIG_PICOLIBC_IO_FLOAT is enabled.

Zephyr Formatted Output

When using Picolibc, the formatted output functions in Zephyr are implemented based on stdio calls, which include:

  • printk, snprintk, and vsnprintk
  • cbprintf and cbvprintf
  • fprintfcb, vfprintfcb, printfcb, vprintfcb, snprintfcb, and vsnprintfcb

When enabling CONFIG_CBPRINTF_PACKAGE_SUPPORT_TAGGED_ARGUMENTS and CBPRINTF_PACKAGE_ARGS_ARE_TAGGED, cbpprintf will not use Picolibc’s stdio.

Mathematical Functions

Except for the long double version of the Bessel functions, Picolibc provides complete support for mathematical operations for float, double, and long double according to C17/IEEE STD 754-2019.

Thread Local Storage (TLS)

Picolibc supports TLS, and when TLS is enabled, the addition of TLS variables will increase the demand for thread stack.

Picolibc Internal Global Variables

Some internal global variables in Picolibc are collected in a dedicated memory partition z_libc_partition, which can be seen in zephyr/lib/libc/picolibc/libc-hooks.c. Applications using CONFIG_USERSPACE and memory domains must ensure that this partition is included in the active domain during Picolibc calls.

Dynamic Memory Management

Picolibc uses the implementation of the malloc API family provided by the general C library, which is built on kernel heap management.

References

https://docs.zephyrproject.org/3.5.0/develop/languages/c/picolibc.html

Leave a Comment