Linux Syscall Support
Use Cases for Direct Syscalls / nolibc-like Layers
- Used to build freestanding or near-bare-metal systems: actor frameworks, toy OSes, Lisp interpreters, and new languages without pulling in full glibc.
- Helpful for bootstrapping new languages and runtimes where a C ABI and full libc are undesired.
- Also used for special threading models (e.g., raw
clone()threads for real-time audio or high-performance I/O) where libc/pthreads are unsafe or too heavy.
Linux vs Other OSes: Syscall ABI Stability
- Linux guarantees a stable syscall ABI; many see this as a deliberate design choice enabling language-agnostic system interfaces.
- *BSDs and macOS often treat direct syscalls as unstable/private and expect everyone to go through libc; OpenBSD in particular is explicit about syscall ABI instability.
- On OpenBSD, static binaries may work only when built against the matching release; future compatibility is not guaranteed.
Pros and Cons of Bypassing libc
- Claimed advantages:
- No dependency on libc, C ABI, or dynamic linking.
- Smaller, simpler binaries; good for static, freestanding, or kernel-adjacent use.
- Potentially reduced attack surface vs. large libc implementations.
- Counterpoints:
- Function-call overhead is negligible vs syscall cost; libc brings useful optimizations and tracks kernel best practices.
- You must maintain syscall mappings yourself and handle syscall evolution.
- Losing ASLR for code when avoiding relocatable binaries is a real trade-off, even if ASLR is viewed as a “weak” defense by some.
- Some OS features (vDSO, NSS, name service) are harder or fragile without libc.
nolibc, Chromium’s Library, and Completeness
- Linux’s
nolibcis minimal by design (e.g., nopread/pwrite, basicprintf, no threads). - This leaves room for richer syscall layers like Chromium’s, tuned for large projects.
nolibcis MIT/LGPL-2.1 licensed and lives undertools/, not as a core kernel header.- Some see an “official” minimal layer as obsoleting third-party ones; others argue scale- and project-specific needs still justify custom implementations.
Language Ecosystem Examples
- Go and Zig use direct syscalls on Linux (with caveats on BSD/macOS).
- A Lisp-like language is described that boots as a freestanding interpreter using syscalls and self-contained ELF tricks.
- Golang’s original
syscallpackage is “frozen”; a newerx/sys/unixpackage tracks new syscalls.
Error Handling and errno
- Some criticize persisting with
errno-style global/thread-local error reporting in new syscall wrappers, preferring return-based (Result-style) errors. - Others argue compatibility and “drop-in” behavior with libc justify keeping
errno, despite its threading/signal complexities.
Technical Pitfalls and Gotchas
syscall()in C is vararg; naïve use can mis-pass 6th+ arguments on some ABIs if types aren’t widened correctly.- Direct use of fork/clone-like syscalls can conflict with threads created via glibc/pthreads.
- Some libc and wrappers transparently map deprecated syscalls like
opentoopenat, which can surprise tools or seccomp profiles.