1# Using Picolibc in Embedded Systems 2 3Picolibc is designed to be used in deeply embedded systems, those 4running either no operating system or a small RTOS. It is designed to 5be linked statically along with any operating system and application 6code. 7 8### Prerequisites 9 10It is expected that the toolchain used for compilation of applicatons 11against Picolibc provides the follwoing headers in its default search 12paths: 13 14 * float.h 15 * iso646.h 16 * stdalign.h 17 * stdarg.h 18 * stdbool.h 19 * stddef.h 20 * tgmath.h 21 22Vanilla GCC & Clang/LLVM toolchains take care of that so most of 23the users have everything in place. But some third-party toolchains 24may expect these headers to be provided by the C library. Unfortunately 25it is not possible as these headers have compiler-specific parts and 26so whatever version could be imported in the Picolibc, it won't work 27nicely with certain compilers. Moreover even different versions of the 28same compiler may not work well with the same version of one of the 29headers mentioned above. 30 31## Compiling with Picolibc 32 33To compile source code to use Picolibc, you can use the GCC .specs 34file delivered with Picolibc. This will set the system header file 35path and the linker library path to point at Picolibc. For example, to 36compile a single file and generate a .o file: 37 38 $ gcc --specs=picolibc.specs -c foo.c 39 40When installed directly into the system, picolibc.specs is placed in 41the gcc directory so that it will be found using just the base name of 42the file. If installed in a separate location, you will need to 43provide an absolute pathname to the picolibc.specs file: 44 45 $ gcc --specs=/usr/local/picolibc/picolibc.specs -c foo.c 46 47When building for an embedded system, you'll probably need to use a 48longer name for the compiler, something like `riscv-unknown-elf-gcc` 49or `arm-none-eabi-gcc`. 50 51## Picolibc startup 52 53Initializing an embedded system usually requires a combination of 54hardware, run-time, library and application setup. You may want to 55perform all of these in your own code, or you be able to use the 56Picolibc startup code. Either works fine, using the Picolibc code 57means writing less of your own. 58 59### Picocrt — Picolibc startup code 60 61Picocrt is the crt0.o code provided by Picolibc. This is enabled by 62default when using -specs=picolibc.specs: 63 64 $ gcc -specs=picolibc.specs -o foo.elf foo.c 65 66Picocrt goes through a sequence of initialization steps, many of which 67you can plug your own code into: 68 69 1) Architecture-specific runtime initialization. For instance, RISC-V 70 needs the `gp` register initialized for quick access to global 71 variables while ARM with hardware floating point needs to have the 72 FPSCR register set up to match C semantics for rounding. 73 74 2) Data initialization. Here's the code inside Picocrt:\ 75 \ 76 `memcpy(__data_start, __data_source, (uintptr_t) __data_size);`\ 77 \ 78 For this to work, the linker script must assign correct values to 79 each of these symbols: 80 81 * __data_start points to the RAM location where the .data segment 82 starts. 83 * __data_source points to the Flash location where the .data segment 84 initialization values are stored. 85 * __data_size is an absolute symbol noting the size of the 86 initialized data segment 87 88 3) BSS initialization. Here's the code inside Picocrt:\ 89 \ 90 `memset(__bss_start, '\0', (uintptr_t) __bss_size);`\ 91 \ 92 Assign these symbols in the linker script as follows: 93 94 * __bss_start points to the RAM location where the .bss segment 95 starts. 96 * __bss_size is an absolute symbol noting the size of the cleared 97 data segment 98 99 4) Optionally call constructors: 100 101 * The default and hosted crt0 variants call 102 [initializers/constructors](init.md) using `__libc_init_array()` 103 104 * The minimal crt0 variant doesn't call any constructors 105 106 5) Call `main()` 107 108 6) After main returns: 109 110 * The default and minimal crt0 variants run an infinite 111 loop if main returns. 112 113 * The hosted crt0 variant calls `exit`, passing it the value 114 returned from main. 115 116## Linking 117 118Picolibc provides two sample linker scripts: `picolibc.ld` for C 119applications and `picolibcpp.ld` for C++ applications. These are 120designed to be useful for fairly simple applications running on 121embedded hardware which need read-only code and data stored in flash 122and read-write data allocated in RAM and initialized by picolibc at 123boot time. You can read more about this on the [linking](linking.md) 124page. 125 126## Semihosting 127 128“Semihosting” is a mechanism used when the application is run under a 129debugger or emulation environment that provides access to some 130functionality of the OS running the debugger or emulator. Picolibc 131has semihosting support for console I/O and the exit() call. 132 133One common use for semihosting is to generate debug messages before 134any of the target hardware has been set up. 135 136Picolibc distributes the semihosting implementation as a separate 137library, `libsemihost.a`. Because it provides interfaces that are used 138by libc itself, it must be included in the linker command line *after* 139libc. You can do this by using the GCC --oslib=semihost 140command line flag defined by picolibc.specs: 141 142 $ gcc --specs=picolibc.specs --oslib=semihost -o program.elf program.o 143 144You can also list libc and libsemihost in the correct order 145explicitly: 146 147 $ gcc --specs=picolibc.specs -o program.elf program.o -lc -lsemihost 148 149## Crt0 variants 150 151The default `crt0` version provided by Picolibc calls any constructors 152before it calls main and then goes into an infinite loop after main 153returns to avoid requiring an `_exit` function. 154 155In an environment which provides a useful `_exit` implementation, applications 156may want to use the `crt0-hosted` variant that calls `exit` when main 157returns, resulting in a clean return to the hosting environment (this 158conforms to a hosted execution environment as per the C 159specification). Select this using the `--crt0=hosted` flag: 160 161 $ gcc --specs=picolibc.specs --crt0=hosted -o program.elf program.o 162 163In a smaller environment which is not using any constructors (or any 164Picolibc code which requires constructors) may want to use the 165`crt0-minimal` variant that removes the call to 166`__libc_init_array()`. This variant also runs an infinite loop in case 167main returns. Select this using the `--crt0=minimal` flag: 168 169 $ gcc --specs=picolibc.specs --crt0=minimal -o program.elf program.o 170