1# Picolibc and Operating Systems
2
3Picolibc is designed to be operating-system independent, so it doesn't
4embed any operating system support into libc. Some portions of
5Picolibc need system support, like I/O and task termination.
6
7## System Interfaces used by Picolibc
8
9Here's the full list of system functions used by Picolibc, split into
10sections based on what libc support they enable
11
12### stdin/stdout/stderr
13
14Picolibc stdio splits support for simple console input/output and more
15complex file operations so that a minimal system can easily support
16the former with only a few functions.
17
18To get stdin/stdout/stderr working, the application needs to define
19the `stdin`, `stdout` and `stderr` globals, which contain pointers to
20FILE objects. The pointers may reside in read-only memory, but the
21FILE objects may not. A single FILE object may be used for all three
22pointers, and linker aliases may be used to make all three pointers be
23stored in the same location. The FILE object contains function
24pointers for putc, getc, which might be defined as follows:
25
26	static int
27	sample_putc(char c, FILE *file)
28	{
29		(void) file;		/* Not used in this function
30		__uart_putc(c);		/* Defined by underlying system */
31		return c;
32	}
33
34	static int
35	sample_getc(FILE *file)
36	{
37		unsigned char c;
38		(void) file;		/* Not used in this function */
39		c = __uart_getc();	/* Defined by underlying system */
40		return c;
41	}
42
43It also contains a pointer to an optional `flush` function, which, if
44provide, will be called to flush pending output to the file, e.g.,
45when the `fflush()` function is called:
46
47	static int
48	sample_flush(FILE *file)
49	{
50		/* This function doesn't need to do anything */
51		(void) file;		/* Not used in this function */
52		return 0;
53	}
54
55These functions are used to initialize a FILE structure:
56
57	static FILE __stdio = FDEV_SETUP_STREAM(sample_putc,
58						sample_getc,
59						NULL,
60						_FDEV_SETUP_RW);
61
62This defines a FILE which can read and write characters using the putc
63and getc functions described above, but not using any flush
64function. The final paramter, which specifies the operations
65supported, can be one of the following:
66
67| Mode              | Operations | Required Functions |
68|-------------------|------------|--------------------|
69| _FDEV_SETUP_READ  | Read       | getc               |
70| _FDEV_SETUP_WRITE | Write      | putc               |
71| _FDEV_SETUP_RW    | Read/Write | putc, getc         |
72
73Finally, the FILE is used to initialize the `stdin`, `stdout` and
74`stderr` values, the latter two of which are simply aliases to `stdin`:
75
76   FILE *const stdin = &__stdio;
77   __strong_reference(stdin, stdout);
78   __strong_reference(stdin, stderr);
79
80### fopen, fdopen
81
82Support for these requires malloc/free along with a handful of
83POSIX-compatible functions:
84
85	int open (const char *, int, ...);
86	int close (int fd);
87	ssize_t read (int fd, void *buf, size_t nbyte);
88	ssize_t write (int fd, const void *buf, size_t nbyte);
89	off_t lseek (int fd, off_t offset, int whence);
90
91The code needed for this is built into Picolibc by default, but can be
92disabled by specifying `-Dposix-io=false` in the meson command line.
93
94### exit
95
96Exit is just a wrapper around _exit that also calls destructors and
97callbacks registered with atexit. To make it work, you'll need to
98implement the `_exit` function:
99
100	_Noreturn void _exit (int status);
101
102### malloc and free
103
104Both versions of malloc in picolibc require sbrk to be supported. The
105smaller version, enabled (by default) with -Dnewlib-nano-malloc=true,
106can handle sbrk returning dis-continuous memory while the larger
107version (enabled with -Dnewlib-nano-malloc=false) requires sbrk return
108contiguous chunks of memory.
109
110### sbrk
111
112Picolibc includes a simple version of sbrk that can return chunks of
113memory from a pre-defined contiguous heap. To use this function, your
114application linking process needs to define two symbols:
115
116 * __heap_start — points at the start of the heap available for sbrk.
117 * __heap_end — points at the end of the heap available for sbrk.
118
119The sample linker script provided with picolibc defines these two
120symbols to enclose all RAM which is not otherwise used by the
121application.
122
123## abort
124
125Posix says that `abort` sends `SIGABRT` to the calling process as if
126the process called `raise(SIGABRT)`. It also says `abort` shall not
127return. The picolibc implementation of `abort` calls `raise`; if that
128returns, it then calls `_exit`. The picolibc version of `raise` also
129calls `_exit` for uncaught and un-ignored signals.
130
131This means that an application needs to provide an implementation of
132`_exit` to support `abort`.
133
134## Linking with System Library
135
136To get Picolibc to use a system library, that library needs to be
137specified *after* libc on the linker command line. The picolibc.specs
138file provides a way to specify a library after libc using the
139`--oslib=` parameter:
140
141	$ gcc -o program.elf program.o --oslib=myos
142
143This will include -lmyos after -lc so that the linker can resolve
144functions used by picolibc from libmyos.a. You can, alternatively,
145include the functions in object files with the rest of your
146application, which avoids the problem with libraries. Note that this
147mechanism requires the definition of _exit in the myos library.
148
149## Semihosting support
150
151For RISC-V and ARM processors, Picolibc provides an implementation of
152all of the above functions along with a couple more POSIX APIs used by
153the Picolibc test suite. This implementation relies on semihosting
154support from the execution environment, which is available when
155running under qemu or when using openocd and gdb. Link this into your
156application using `--oslib=semihost` in your link command line.
157Please note that this will replace the default `crt0` with a variant
158calling `exit` upon return from `main`. The default is to enter an
159infinite loop, and the change ensure a clean return to the execution
160environment.
161
162## POSIX console support
163
164As a build-time option, Picolibc can be configured to use POSIX read
165and write APIs to support stdin, stdout and stderr. Add
166`-Dposix-console=true` to enable this. This is incompatible with
167semihosting support above.
168
169## Building picolibc on native POSIX systems
170
171To allow for testing of picolibc and applications using picolibc, you
172can actually build picolibc on a full POSIX system. In this
173configuration, picolibc provides the non-POSIX libc APIs while the
174underlying system C library is used for the POSIX functions described
175above. To build in this mode, you'll need to override a few default
176picolibc configuration parameters:
177
178	$ meson \
179		-Dtls-model=global-dynamic \
180		-Dmultilib=false \
181		-Dpicolib=false \
182		-Dpicocrt=false \
183		-Dposix-console=true \
184		-Dnewlib-global-atexit=true \
185		-Dincludedir=lib/picolibc/include \
186		-Dlibdir=lib/picolibc/lib \
187		-Dspecsdir=none
188
189 * -Dtls-model=global-dynamic makes picolibc use the default TLS model
190   for GCC.
191
192 * -Dmultilib=false makes picolibc build only a single library for the
193   default GCC configuration.
194
195 * -Dpicolib=false disables building the TLS and sbrk support built-in
196   to picolibc so that the underlying system support is used instead.
197
198 * -Dpicocrt=false disables building the C startup code as that is
199   provided by the underlying system.
200
201 * -Dposix-console=true uses POSIX I/O read/write APIs for stdin,
202    stdout and stderr.
203
204 * -Dnewlib-global-atexit=true disables the per-thread atexit behavior
205   so that picolibc acts like a regular C library.
206
207 * -Dincludedir and -Dlibdir specify install locations for the headers
208   and library
209
210 * -Dspecsdir=none disables installing picolibc.specs as that file
211   is not useful in this environment
212
213Once built, you can install and use picolibc on the host:
214
215	$ cc -I/usr/local/lib/picolibc/include hello-world.c \
216		/usr/local/lib/picolibc/lib/libc.a
217