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