libc #
This page explains the LionsOS libc implementation and how to configure and build it using the provided Makefile snippet.
Overview #
LionsOS uses a custom libc setup based on our fork of musllibc. We also provide implementations of a POSIX subset and vendored compiler runtime helpers. This setup is compatible with the sDDF build system.
The final libc.a is built from three main sources:
- musllibc (our fork): Provides core libc functionality, with system calls redirected to a general dispatcher.
- Syscall implementations: Functionality found in
lib/libc/posix/. - Compiler runtime helpers: Low-level arithmetic and runtime support from
lib/libc/compiler_rt/.
Available Functionality #
Syscall implementation is not comprehensive. Below is a summary of what can be expected to work.
- Standard I/O:
STDOUTandSTDERRare opened by default on the expected file descriptors and will output to a connected serial subsystem, enablingprintf. - File System: Standard operations
open/openat,read/readv,write/writev,lseek, andcloseare available for regular files, as well asfstat/fstatat. Directories can be created withmkdirat. - Networking: Client-related socket operations are supported. Sockets can be
created with
socket, used toconnectto a server,sendtodata, andrecvfromdata. Additional networking support is currently being worked on. - Memory: Basic heap management is available via
brk. - Other: An insecure implementation of
getrandom(based onrand) is available.
musllibc Fork: Syscall Redirection #
Our musllibc fork replaces architecture-specific inline assembly syscall traps
(like svc 0 on AArch64) with a generic function call mechanism. Instead of
invoking syscalls directly with assembly, musl’s internal __syscallN functions
now call a dispatcher function via __sysinfo.
In upstream musl, __sysinfo is normally a hook for vDSO (Virtual Dynamic
Shared Object) support on Linux systems, letting musl call kernel-provided
user-space functions without a full syscall. We’ve repurposed it as a general
syscall dispatcher, since all our syscalls are provided in a user-space library.
As a result, all libc syscall invocations are routed through the LionsOS POSIX
syscall handler, which is implemented in the lib/libc/posix/ layer.
For example:
#define CALL_SYSINFO(n, ...) ((long(*)(long,...))__sysinfo)(n, ##__VA_ARGS__)
static inline long __syscall3(long n, long a1, long a2, long a3) {
return CALL_SYSINFO(n, a1, a2, a3);
}
LionsOS provides the __sysinfo implementation in libc_init():
void libc_init() {
/* Syscall table init */
__sysinfo = sel4_vsyscall;
...
Usage #
To build the LionsOS libc, include the lib/libc/libc.mk snippet in your
top-level Makefile:
include $(LIONSOS)/lib/libc/libc.mk
This snippet defines and builds the following targets:
$(LIONS_LIBC): The absolute path to the libc build directory.$(LIONS_LIBC)/include: The installed musl headers for components requiring libc. This is also a build target for musllibc, allowing you to specify the headers as a build prerequisite.$(LIONS_LIBC)/lib/libc.a: The final static libc archive combining musl, syscalls, and compiler runtime objects. This must be linked into your final binary. Please note that libmath (libm.a) is bundled with ourlibc.a, so there is no need to link to this explicitly.
For sDDF components, do not set SDDF_CUSTOM_LIBC. Instead, define the
following:
SDDF_LIBC_INCLUDE := $(LIONS_LIBC)/include
include <path_to_sddf_snippet.mk>
More information on SDDF_LIBC_INCLUDE can be found in the
sDDF docs.
Note that the LionsOS libc.mk automatically adds the headers to CFLAGS as an
include path so there is no need to do this explicitly.
This ensures sDDF components use the LionsOS library headers instead of falling back to sDDF’s internal, vendored libc. Since sDDF components list this as a prerequisite, it also guarantees the headers are available before compilation begins.
POSIX Implementations and Compiler Runtime Support #
The extra functionality is provided via:
lib/libc/posix/*.c: POSIX wrappers and syscall implementations.lib/libc/compiler_rt/*.c: Arithmetic helpers and low-level runtime support.
These files are compiled into objects and simply bundled into the final libc.a
archive.