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 nolibc is minimal by design (e.g., no pread/pwrite, basic printf, no threads).
  • This leaves room for richer syscall layers like Chromium’s, tuned for large projects.
  • nolibc is MIT/LGPL-2.1 licensed and lives under tools/, 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 syscall package is “frozen”; a newer x/sys/unix package 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 open to openat, which can surprise tools or seccomp profiles.