README introduces the project and build workflow; CONTRIBUTING covers the stub convention and syscall wrapper process; docs/ explains the architecture and the kernel ABI surface. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <[email protected]>
2.9 KiB
Syscalls
This project's first principle (project guideline #6): the kernel is the API. This document is the map of every syscall nulsl-libc touches, how errors travel, and how to add the next one.
The one and only ABI surface
src/syscall.c — the only file that executes the syscall instruction.
long syscall(long number, ...);
- Arguments 1-6 map to the platform's syscall argument registers.
- On success the kernel return value is returned as-is.
- On error the Linux kernel returns
-errno(range-1..-4095).syscall()translates it:errno = -ret; return -1;— the standard libc convention. - Numbers live in
include/sys/syscall.hasSYS_*macros,#ifndef-guarded so kernel UAPI headers can coexist.
The syscalls we use
x86_64 Linux ABI:
| Number | Name | Used by | Status |
|---|---|---|---|
| 0 | read | read() |
wrapped |
| 1 | write | write(), puts(), putchar() |
wrapped |
| 2 | open | — | constant |
| 3 | close | close() |
wrapped |
| 39 | getpid | getpid(), bench_syscall |
wrapped |
| 60 | exit | _exit(), exit(), abort() |
wrapped |
| 87 | unlink | — (stub uses errno = ENOSYS) | constant |
| 228 | clock_gettime | benchmarks only | constant |
"Wrapped" means there is a public function in src/ that calls it.
"Constant" means the number is defined in the header but nothing wraps it
yet (benchmarks call it directly through syscall()).
Adding a new syscall wrapper
-
Add the number to
include/sys/syscall.h(guarded, with the ABI it belongs to in a comment). -
Add the public declaration to the right header (
include/unistd.hfor POSIX stuff,include/stdio.hfor stdio, ...). -
Implement it in the matching
src/file as a thin wrapper:ssize_t write(int fd, const void *buf, size_t count) { return (ssize_t)syscall(SYS_write, fd, buf, count); }If the syscall is not implemented yet, follow the stub convention instead (return the documented error value,
errno = ENOSYS,/* TODO */comment naming what it needs). -
Update this table.
-
Add or extend a smoke test in
tests/— if nothing exercises it, it does not exist.
Porting to a new architecture
src/syscall.c— add the register mapping for the new ABI (#errorotherwise).src/crt/crt0.S— add_startfor the new ABI.include/sys/syscall.h— the numbers are per-architecture; split the table or move it tosrc/arch/once a second target exists.configure.ac— extend thehost_cpucase.
The project targets Linux on x86_64 today; everything above is written so a second port is a contained, reviewable change.