Linux system calls, the kernel boundary
Every time a program reads a file, allocates memory, spawns a process or opens a socket, it crosses from user space into the kernel through a system call. On x86-64, the syscall number goes in the rax register, arguments in rdi, rsi, rdx, r10, r8, r9, and the syscall instruction transfers control to the kernel. This reference lists the most common syscalls with their number, C signature and category so you can decode an strace log or write inline assembly without leaving the page.
How it works
A syscall is dispatched by number. The kernel’s syscall table maps rax to a handler, the handler runs in kernel mode, and the result comes back in rax. At the raw level a return value in the range -4095 to -1 is a negated errno — the glibc wrapper detects this, returns -1 and sets errno to the positive code. Successful calls return a non-negative value: a count of bytes, a new file descriptor, a pointer (from mmap), or 0.
Syscalls group into families. Process calls (fork, clone, execve, exit_group, wait4) manage the process lifecycle. File calls (open/openat, read, write, close, lseek, stat) move data through file descriptors. Memory calls (mmap, munmap, mprotect, brk) manage the address space. Network calls (socket, bind, listen, accept, connect, sendto, recvfrom) drive sockets. Signal calls (kill, rt_sigaction, rt_sigprocmask) deliver and handle asynchronous notifications.
Frequently used syscalls with context
File I/O
openat(dirfd, pathname, flags, mode) — Open a file relative to a directory file descriptor. The *at variant is preferred over open because it avoids TOCTOU races when the directory might change between path resolution and the open. flags include O_RDONLY, O_WRONLY, O_RDWR, O_CREAT, O_NONBLOCK, O_CLOEXEC. Returns a new file descriptor or -1.
read(fd, buf, count) — Read up to count bytes from fd into buf. Returns the number of bytes actually read, which may be less than count (a short read). A return of 0 means end-of-file. EINTR means a signal arrived — restart the loop.
write(fd, buf, count) — Write count bytes from buf to fd. Returns bytes written, which may be less than count on a non-blocking descriptor or a full kernel buffer. Always loop until all bytes are written.
close(fd) — Releases the file descriptor. Always check the return value — on network file systems a flush error appears here, not in the last write.
Process lifecycle
clone(flags, stack, ...) — The underlying primitive for both threads and processes. Pass CLONE_VM | CLONE_FILES | CLONE_SIGHAND (and others) to share resources as a thread; pass 0 to copy everything as a process. fork() is essentially clone(SIGCHLD, 0).
execve(pathname, argv[], envp[]) — Replace the current process image with a new program. The PID is preserved; the address space, signal handlers, and file descriptors (except those with O_CLOEXEC) carry over.
wait4(pid, wstatus, options, rusage) — Wait for a child process to change state. The WNOHANG option makes it non-blocking. Inspect wstatus with WIFEXITED, WEXITSTATUS, WIFSIGNALED, WTERMSIG.
Memory management
mmap(addr, length, prot, flags, fd, offset) — Map files or devices into memory, or allocate anonymous memory with MAP_ANONYMOUS. The prot flags (PROT_READ | PROT_WRITE | PROT_EXEC) set page permissions enforced by the MMU. Returns the mapped address or MAP_FAILED (-1) on error.
mprotect(addr, len, prot) — Change permissions on an existing mapping. Used by runtimes to mark JIT-compiled pages executable after writing them.
Tracing with strace
# Trace all syscalls made by a program
strace ./myprogram
# Trace only specific syscalls
strace -e trace=openat,read,write ./myprogram
# Count syscalls and time spent in each (profile mode)
strace -c ./myprogram
# Attach to a running process
strace -p 1234
The output format is syscall_name(arg1, arg2, ...) = return_value. A return of -1 is followed by the errno name and description: openat(...) = -1 ENOENT (No such file or directory).
Tips and examples
- Prefer the
*atvariants (openat,unlinkat,fstatat) for race-free path resolution relative to a directory file descriptor. strace -c ./proggives a histogram of which syscalls dominate — useful when a program feels slow or chatty.- The numbers here are x86-64 specific. The canonical table lives at
arch/x86/entry/syscalls/syscall_64.tblin the kernel source. - Use
seccomp(SECCOMP_SET_MODE_FILTER, ...)with a BPF filter to restrict which syscalls a sandboxed process may make — this is how Docker and Chrome’s renderer use the syscall table as a security boundary.