libc already includes the wrapper functions you're looking for. The prototypes for many of them are in #include <unistd.h>
, as specified by POSIX.
C is the language of low-level systems program on Unix (and Linux), so this has been a thing since Unix existed. (Providing wrapper functions in libc is easier than teaching compilers the difference between function call and system calls, and allows for setting errno
on errors. It also allows for tricks like LD_PRELOAD
to intercept system calls in user-space.)
The man pages for system calls are in section 2, vs. section 3 for library functions (which might or might not use system calls as part of their implementation: math.h cos(3)
, ISO C stdio printf(3)
and fwrite(3)
, vs. POSIX write(2)
).
execve(2)
is the system call.
See execl(3)
and friends are also part of libc, and eventually call execve(2)
. They are convenience wrappers on top of it for constructing the argv array, doing $PATH
lookup, and passing along the current process's environment. Thus they're classed as functions, not system calls.
See syscalls(2)
for an overview, and complete list of system Linux calls with links to their man-page wrappers. (I've linked the Linux man pages, but there are also POSIX man pages for all of the standard system calls.)
In the unlikely case that you're not linking libc, you can use macros like MUSL's syscall2
/ syscall3
/ etc. macros (the number is the arg count) to inline the right asm on whatever platform. You use __NR_write
from asm/unistd.h
to get system call numbers.
But note that the raw Linux system calls might have small differences from the interface provided by the libc wrappers. For example, they won't check for pthreads cancellation points, and brk
/ sbrk
requires bookkeeping in user-space by libc.
See SYSCALL_INLINE in Android for a portable raw sys_write()
inline wrapper using MUSL macros.
But if you are using libc like a normal person for functions like malloc
and printf
, you should just use its system call wrapper functions.