Linux 系统调用手册
系统调用是用户态程序进入 Linux 内核的唯一入口。本手册综合了三份文档,涵盖 x86-64 调用约定与实战速查、350+ syscall 完整目录(Kernel 5.10)、以及 PlantUML 架构图(执行流程、分类全景、迁移路径等)。
关于用户态到内核态的桥接:C 程序一般通过 glibc/musl 封装调用 syscall;Go、Rust 等语言的运行时则直接执行 syscall 指令,绕过 libc。无论哪种方式,最终都经过同一个内核入口 entry_SYSCALL_64。
1. 概述
什么是系统调用
系统调用(syscall)是内核暴露给用户空间的编程接口。用户态程序通过 syscall 请求内核执行特权操作(如读写文件、创建进程、收发网络数据)。CPU 从用户态(ring 3)切换到内核态(ring 0),执行内核代码,完成后返回用户态。
Linux x86_64 共 335+ 个系统调用(截至 5.10),涵盖 15 个功能类别。每个系统调用标注了首次出现的内核版本。未标注版本号的系统调用在 1.0 或更早版本中就已存在。
| # | 分类 | 数量 | 核心调用举例 |
| 1 | 文件与目录操作 | ~90 | open, read, write, close, stat, rename |
| 2 | 进程与线程管理 | ~60 | fork, clone3, execve, exit, wait4, prctl |
| 3 | 内存管理 | ~25 | mmap, munmap, mprotect, brk, madvise |
| 4 | 网络套接字 | ~22 | socket, bind, connect, accept, sendmsg |
| 5 | 信号与定时器 | ~28 | rt_sigaction, kill, timerfd_create |
| 6 | 用户与权限 | ~38 | setuid, capget, setrlimit, seccomp |
| 7 | 时间与时钟 | ~14 | clock_gettime, nanosleep, gettimeofday |
| 8 | IPC | ~21 | pipe, shmget, semop, mq_open, futex |
| 9 | 文件系统与挂载 | ~11 | mount, umount2, pivot_root, fsopen |
| 10 | I/O 多路复用 | ~18 | epoll_create1, epoll_ctl, poll, select |
| 11 | 异步 I/O / io_uring | ~9 | io_uring_setup, io_submit, io_getevents |
| 12 | 系统控制与信息 | ~26 | syslog, uname, bpf, getrandom, ioctl |
| 13 | 内核模块与密钥 | ~6 | init_module, keyctl, request_key |
| 14 | 架构专属 | ~42 | arch_prctl, riscv_flush_icache... |
| 15 | 已废弃/已移除 | ~20+ | _sysctl, create_module, nfsservctl... |
2. 系统调用执行流程
3. vDSO 快速路径 vs 慢速路径
vDSO 原理:内核将一段只读代码和数据页映射到每个进程的地址空间。调用频率极高的 clock_gettime 和 gettimeofday 完全在用户态完成(读 TSC 寄存器 + 内核维护的校准数据),避免上下文切换开销。
4. 调用约定
4.1 x86-64
| 项目 | 约定 |
| 指令 | syscall |
| 调用号 | 存于 rax |
| 第1参数 | rdi |
| 第2参数 | rsi |
| 第3参数 | rdx |
| 第4参数 | r10(非 rcx,因为 syscall 会破坏 rcx) |
| 第5参数 | r8 |
| 第6参数 | r9 |
| 返回值 | rax(0 ~ -4095 表示错误,errno = -rax) |
| 被破坏的寄存器 | rcx, r11 |
; 示例: read(0, buf, 128)
mov rax, 0 ; syscall 号: read
mov rdi, 0 ; fd = 0 (stdin)
mov rsi, buf ; 缓冲区地址
mov rdx, 128 ; 长度
syscall
cmp rax, -4095
ja error_handler ; 如果 rax > -4095,说明是负的 errno
errno 判断:内核返回负的 errno 值(-1 到 -4095),glibc 将其转为 -1 并设置 errno。直接 syscall 时需自行处理:若 rax 在 -4095 到 -1 之间,则调用失败,errno = -rax。
4.2 其他架构对比
| 架构 | 指令 | 调用号寄存器 | 参数寄存器(按顺序) | 返回 |
| x86-64 | syscall | rax | rdi, rsi, rdx, r10, r8, r9 | rax |
| i386 (32-bit) | int 0x80 | eax | ebx, ecx, edx, esi, edi, ebp | eax |
| arm64 | svc #0 | x8 | x0, x1, x2, x3, x4, x5 | x0 |
| RISCV64 | ecall | a7 | a0, a1, a2, a3, a4, a5 | a0 |
5. 系统调用分类全景图
6. 文件 I/O
6.1 核心调用 (x86-64 编号)
| syscall | 号 | 签名 | 说明 |
read | 0 | read(fd, buf, count) | 从 fd 读取 count 字节到 buf。返回实际读取字节数;0 表示 EOF |
write | 1 | write(fd, buf, count) | 将 buf 中 count 字节写入 fd |
open | 2 | open(path, flags, mode) | 打开文件,返回 fd。flags 如 O_RDONLY/O_WRONLY/O_CREAT 等 |
close | 3 | close(fd) | 关闭 fd |
stat | 4 | stat(path, buf) | 获取文件元信息(大小、权限、inode 等),填入 struct stat |
fstat | 5 | fstat(fd, buf) | 同 stat,但通过 fd 而非路径 |
lstat | 6 | lstat(path, buf) | 同 stat,但对符号链接不解引用 |
lseek | 8 | lseek(fd, offset, whence) | 移动文件读写位置。whence: SEEK_SET/SEEK_CUR/SEEK_END |
pread64 | 17 | pread64(fd, buf, count, offset) | 从指定 offset 读取,不改变 fd 的当前位置(原子操作) |
pwrite64 | 18 | pwrite64(fd, buf, count, offset) | 从指定 offset 写入,不改变 fd 当前位置 |
rename | 82 | rename(old, new) | 重命名文件。若 new 已存在则原子替换 |
truncate | 76 | truncate(path, length) | 将文件截断/扩展到 length |
unlink | 87 | unlink(path) | 删除文件(硬链接计数 -1,为 0 时真正删除) |
mkdir | 83 | mkdir(path, mode) | 创建目录 |
rmdir | 84 | rmdir(path) | 删除空目录 |
getdents64 | 217 | getdents64(fd, dirp, count) | 读取目录项(ls 等工具用此实现) |
openat | 257 | openat(dirfd, path, flags, mode) | 相对 dirfd 打开文件,避免 TOCTOU 竞态 |
readlink | 89 | readlink(path, buf, bufsiz) | 读取符号链接的目标路径 |
fsync | 74 | fsync(fd) | 将 fd 所有缓冲数据写入磁盘 |
fdatasync | 75 | fdatasync(fd) | 同 fsync 但仅同步数据(不同步元数据),更快 |
fallocate | 285 | fallocate(fd, mode, offset, len) | 预分配文件空间(比 lseek+write 高效) |
6.2 文件 I/O 操作栈
6.3 扩展文件操作 (Kernel 版本)
| syscall | 版本 | 说明 |
close_range | 5.9 | 批量关闭文件描述符范围 |
copy_file_range | 4.5 | 内核态文件范围拷贝,零拷贝 |
openat2 | 5.6 | openat 增强版,可扩展参数结构 |
statx | 4.11 | 增强版文件状态查询(含出生时间等) |
renameat2 | 3.15 | renameat 增强版(支持交换等) |
preadv2 / pwritev2 | 4.6 | 指定偏移量 + 标志的分散/集中 I/O |
splice | 2.6.17 | 管道间零拷贝数据传输 |
tee | 2.6.17 | 管道数据复制(零拷贝) |
vmsplice | 2.6.17 | 用户态内存→管道(零拷贝) |
syncfs | 2.6.39 | 刷回特定文件系统 |
name_to_handle_at | 2.6.39 | 路径→文件句柄 |
open_by_handle_at | 2.6.39 | 文件句柄→fd |
open flag 常用组合
O_RDONLY = 0x0 // 只读
O_WRONLY = 0x1 // 只写
O_RDWR = 0x2 // 读写
O_CREAT = 0x40 // 不存在则创建
O_EXCL = 0x80 // 与 O_CREAT 联合,文件已存在则失败
O_TRUNC = 0x200 // 打开时清空
O_APPEND = 0x400 // 追加写
O_NONBLOCK = 0x800 // 非阻塞
O_DIRECT = 0x4000 // 绕过 page cache
O_CLOEXEC = 0x80000 // exec 时自动关闭
7. 进程管理
7.1 核心调用
| syscall | 号 | 签名 | 说明 |
fork | 57 | fork() | 创建子进程(复制父进程)。父返回子 pid,子返回 0 |
execve | 59 | execve(path, argv, envp) | 执行新程序,替换当前进程镜像。成功不返回 |
exit | 60 | exit(status) | 终止当前进程,不会返回 |
exit_group | 231 | exit_group(status) | 终止所有线程(glibc exit() 实际调用此) |
wait4 | 61 | wait4(pid, wstatus, options, rusage) | 等待子进程状态变更,回收僵尸进程 |
clone | 56 | clone(fn, stack, flags, arg, ...) | 创建新进程/线程的底层接口 |
clone3 | 435 | clone3(cl_args, size) | clone 新版本,使用结构体传参 |
nanosleep | 35 | nanosleep(req, rem) | 让进程休眠指定时间(纳秒精度) |
sched_yield | 24 | sched_yield() | 主动放弃 CPU |
getpid | 39 | getpid() | 获取当前进程 PID |
gettid | 186 | gettid() | 获取当前线程 TID |
getppid | 110 | getppid() | 获取父进程 PID |
futex | 202 | futex(uaddr, op, val, timeout, uaddr2, val3) | 快速用户态互斥锁(pthread_mutex 底层实现) |
rseq | 334 | rseq(rseq, rseq_len, flags, sig) | Restartable Sequences(Go runtime 使用) |
7.2 扩展进程/线程操作
| syscall | 版本 | 说明 |
execveat | 3.19 | 相对目录执行程序 |
pidfd_open | 5.3 | 打开进程文件描述符 (pidfd) |
pidfd_send_signal | 5.1 | 通过 pidfd 发送信号(避免 PID 复用) |
pidfd_getfd | 5.6 | 通过 pidfd 获取目标进程 fd |
process_vm_readv | 3.2 | 跨进程读取内存 |
process_vm_writev | 3.2 | 跨进程写入内存 |
process_madvise | 5.10 | 对另一进程地址空间给出建议 |
ptrace | 1.0 | 进程跟踪与调试(gdb/strace 基础) |
getcpu | 2.6.19 | 获取当前 CPU 和 NUMA 节点 |
setns | 3.0 | 加入命名空间 |
vfork | 2.2 | 轻量级 fork(共享地址空间直到 execve) |
clone flags 常用值
CLONE_VM = 0x100 // 共享地址空间(线程)
CLONE_FS = 0x200 // 共享文件系统信息
CLONE_FILES = 0x400 // 共享 fd 表
CLONE_SIGHAND = 0x800 // 共享信号处理表
CLONE_THREAD = 0x10000 // 同一线程组
CLONE_NEWNS = 0x20000 // 新 mount namespace
CLONE_NEWUTS = 0x4000000 // 新 UTS namespace(hostname)
CLONE_NEWIPC = 0x8000000 // 新 IPC namespace
CLONE_NEWPID = 0x20000000// 新 PID namespace
CLONE_NEWNET = 0x40000000// 新 network namespace
// 创建一个新线程:
clone_flags := CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | CLONE_THREAD
7.3 进程生命周期
8. 内存管理
8.1 核心调用
| syscall | 号 | 签名 | 说明 |
mmap | 9 | mmap(addr, len, prot, flags, fd, offset) | 映射文件或匿名内存到虚拟地址空间 |
munmap | 11 | munmap(addr, len) | 取消内存映射 |
mprotect | 10 | mprotect(addr, len, prot) | 修改内存区域保护属性(r/w/x) |
brk | 12 | brk(addr) | 调整数据段边界(堆顶)。malloc 小于 128KB 时用 |
madvise | 28 | madvise(addr, len, advice) | 给内核内存使用建议(MADV_DONTNEED 等) |
mremap | 25 | mremap(old_addr, old_len, new_len, flags, ...) | 调整已有映射的大小(可移动) |
mlock | 149 | mlock(addr, len) | 锁定内存页,禁止换出(需要 CAP_IPC_LOCK) |
mincore | 27 | mincore(addr, len, vec) | 检查内存页是否在 RAM 中 |
8.2 mmap prot 和 flags
// prot 保护标志
PROT_NONE = 0x0 PROT_READ = 0x1 PROT_WRITE = 0x2 PROT_EXEC = 0x4
// flags
MAP_SHARED = 0x01 // 映射修改共享(写入同步到文件)
MAP_PRIVATE = 0x02 // COW 私有映射
MAP_ANONYMOUS = 0x20 // 匿名映射(分配零初始化内存)
MAP_FIXED = 0x10 // 必须映射到指定地址
MAP_POPULATE = 0x8000 // 预填充页表
MAP_LOCKED = 0x2000 // 锁定映射页
malloc 的两种底层方式
| 方式 | syscall | 适用场景 |
brk | 12 | 小块内存(通常 <128KB),通过移动 program break 扩展堆 |
mmap | 9 | 大块内存(≥128KB),独立映射,释放时真正归还给内核 |
8.3 mmap 为核心的关系图
8.4 其他内存管理 syscall
| syscall | 版本 | 说明 |
memfd_create | 3.17 | 创建匿名内存文件(共享内存/密封) |
membarrier | 3.17 | 多核内存屏障同步 |
userfaultfd | 4.3 | 用户态缺页处理 |
mlock2 | 4.4 | mlock 增强版 |
pkey_alloc / pkey_free | 4.8 | 内存保护密钥分配/释放 |
pkey_mprotect | 4.8 | 带保护密钥的 mprotect |
migrate_pages | 2.6.16 | 迁移进程页面到指定 NUMA 节点 |
move_pages | 2.6.18 | 将页面移动到指定 NUMA 节点 |
mbind | 2.6.6 | 设置内存范围 NUMA 绑定策略 |
9. 网络 Socket
9.1 核心调用
| syscall | 号 | 签名 | 说明 |
socket | 41 | socket(family, type, protocol) | 创建 socket fd。family: AF_INET/AF_UNIX 等 |
bind | 49 | bind(sockfd, addr, addrlen) | 将 socket 绑定到本地地址 |
listen | 50 | listen(sockfd, backlog) | 监听 TCP 连接 |
accept | 43 | accept(sockfd, addr, addrlen) | 接受一个 TCP 连接,返回新 fd(阻塞) |
accept4 | 288 | accept4(sockfd, addr, addrlen, flags) | 同 accept 但可设置 SOCK_NONBLOCK/SOCK_CLOEXEC |
connect | 42 | connect(sockfd, addr, addrlen) | 连接远程地址 |
sendto | 44 | sendto(sockfd, buf, len, flags, dest_addr, addrlen) | 发送数据到指定地址(UDP 常用) |
recvfrom | 45 | recvfrom(sockfd, buf, len, flags, src_addr, addrlen) | 接收数据并获取源地址 |
sendmsg | 46 | sendmsg(sockfd, msg, flags) | 高级发送(分散/聚集 I/O、传 fd) |
recvmsg | 47 | recvmsg(sockfd, msg, flags) | 高级接收 |
sendfile | 40 | sendfile(out_fd, in_fd, offset, count) | 零拷贝文件传输 |
shutdown | 48 | shutdown(sockfd, how) | 关闭 socket 读端/写端/双向 |
setsockopt | 54 | setsockopt(sockfd, level, optname, optval, optlen) | 设置 socket 选项 |
getsockopt | 55 | getsockopt(sockfd, level, optname, optval, optlen) | 获取 socket 选项 |
getsockname | 51 | getsockname(sockfd, addr, addrlen) | 获取 socket 本地地址 |
getpeername | 52 | getpeername(sockfd, addr, addrlen) | 获取 socket 对端地址 |
常用 socket 选项
SO_REUSEADDR = 2 // 重用 TIME_WAIT 状态的地址
SO_KEEPALIVE = 9 // TCP keepalive
SO_LINGER = 13 // close 时的行为
SO_RCVBUF = 8 // 接收缓冲区大小
SO_SNDBUF = 7 // 发送缓冲区大小
TCP_NODELAY = 1 // 禁用 Nagle 算法(低延迟)
9.2 TCP 生命周期
9.3 批量操作
| syscall | 版本 | 说明 |
recvmmsg | 2.6.33 | 批量接收多条消息 |
sendmmsg | 3.0 | 批量发送多条消息 |
socketpair | 2.0 | 创建套接字对(Unix 域) |
10. 进程间通信
10.1 核心调用
| syscall | 号 | 签名 | 说明 |
pipe | 22 | pipe(fds[2]) | 创建单向管道,fds[0]读端,fds[1]写端 |
pipe2 | 293 | pipe2(fds[2], flags) | 同 pipe 但支持 O_NONBLOCK/O_CLOEXEC |
shmget | 29 | shmget(key, size, shmflg) | 创建/获取 System V 共享内存段 |
shmat | 30 | shmat(shmid, shmaddr, shmflg) | 将共享内存段映射到进程地址空间 |
shmdt | 67 | shmdt(shmaddr) | 解除共享内存映射 |
shmctl | 31 | shmctl(shmid, cmd, buf) | 共享内存段控制(IPC_RMID 删除等) |
semget | 64 | semget(key, nsems, semflg) | 创建/获取 System V 信号量集 |
semop | 65 | semop(semid, sops, nsops) | 信号量 P/V 操作(原子) |
semctl | 66 | semctl(semid, semnum, cmd, ...) | 信号量控制(GETVAL/SETVAL/IPC_RMID) |
msgget | 68 | msgget(key, msgflg) | 创建/获取 System V 消息队列 |
msgsnd | 69 | msgsnd(msqid, msg, msgsz, msgflg) | 发送消息到队列 |
msgrcv | 70 | msgrcv(msqid, msg, msgsz, msgtyp, msgflg) | 从队列接收消息 |
IPC 方式选择:实际开发中,POSIX 共享内存 (shm_open + mmap) 和 memfd_create 比 System V 更推荐;管道适用于父子进程;UNIX domain socket 传 fd 更灵活。
10.2 POSIX 消息队列
| syscall | 版本 | 说明 |
mq_open | 2.6.6 | 打开/创建 POSIX 消息队列 |
mq_timedsend | 2.6.6 | 带超时发送消息 |
mq_timedreceive | 2.6.6 | 带超时接收消息 |
mq_notify | 2.6.6 | POSIX 消息队列异步通知 |
mq_unlink | 2.6.6 | 删除 POSIX 消息队列 |
mq_getsetattr | 2.6.6 | 获取/设置 POSIX 消息队列属性 |
11. 信号处理
11.1 核心调用
| syscall | 号 | 签名 | 说明 |
kill | 62 | kill(pid, sig) | 向进程发送信号。pid=0 发给进程组;pid=-1 发给所有 |
tkill | 200 | tkill(tid, sig) | 向指定线程发送信号 |
tgkill | 234 | tgkill(tgid, tid, sig) | 向指定线程组中的指定线程发送信号 |
rt_sigaction | 13 | rt_sigaction(sig, act, oact, sigsetsize) | 设置信号处理函数(取代老的 signal/sigaction) |
rt_sigprocmask | 14 | rt_sigprocmask(how, set, oset, sigsetsize) | 阻塞/解除阻塞信号 |
rt_sigreturn | 15 | rt_sigreturn() | 从信号处理函数返回(自动调用) |
sigaltstack | 131 | sigaltstack(ss, oss) | 设置信号处理用备用栈(处理 SIGSEGV 关键) |
pause | 34 | pause() | 挂起进程直到收到信号 |
11.2 信号演进
12. 时间相关
| syscall | 号 | 签名 | 说明 |
clock_gettime | 228 | clock_gettime(clk_id, tp) | 获取高精度时间。CLOCK_REALTIME / CLOCK_MONOTONIC |
gettimeofday | 96 | gettimeofday(tv, tz) | 获取当前时间(微秒,已过时,推荐 clock_gettime) |
time | 201 | time(tloc) | 获取 Unix 时间戳(秒) |
nanosleep | 35 | nanosleep(req, rem) | 高精度休眠(纳秒级) |
clock_nanosleep | 230 | clock_nanosleep(clk_id, flags, req, rem) | 同 nanosleep 但可指定时钟源(支持绝对时间) |
timerfd_create | 283 | timerfd_create(clockid, flags) | 创建定时器 fd(可放入 epoll 统一监听) |
timerfd_settime | 286 | timerfd_settime(fd, flags, new, old) | 设置定时器 fd 触发时间 |
times | — | times(buf) | 获取进程及子进程 CPU 时间 |
utimensat | — | utimensat(dirfd, path, times, flags) | 纳秒精度文件时间戳设置 |
CLOCK_REALTIME vs CLOCK_MONOTONIC:REALTIME 受系统时间调整(NTP/手动)影响,可能倒退;MONOTONIC 从系统启动开始单调递增,适合测量时间间隔。clock_gettime + gettimeofday 走 vDSO 快速路径,零 syscall 开销。
13. epoll 多路复用
13.1 核心调用
| syscall | 号 | 签名 | 说明 |
epoll_create1 | 291 | epoll_create1(flags) | 创建 epoll 实例,返回 fd。flags 通常传 EPOLL_CLOEXEC |
epoll_ctl | 233 | epoll_ctl(epfd, op, fd, event) | 添加/修改/删除监听的 fd。op: ADD / MOD / DEL |
epoll_pwait | 281 | epoll_pwait(epfd, events, maxevents, timeout, sigmask) | 等待事件就绪,支持信号屏蔽(比 epoll_wait 更安全) |
event types
EPOLLIN = 0x001 // 可读
EPOLLOUT = 0x004 // 可写
EPOLLERR = 0x008 // 出错
EPOLLHUP = 0x010 // 挂断
EPOLLRDHUP = 0x2000 // 对端关闭(半关闭检测)
EPOLLET = 1 << 31 // 边缘触发 (Edge Triggered)
EPOLLONESHOT= 1 << 30 // 只触发一次
边缘触发 (ET) 注意事项:必须在一次事件中循环 read/write 直到返回 EAGAIN,否则可能丢失事件。新手建议先用水平触发 (LT)。
13.2 I/O 多路复用三代进化
13.3 其他多路复用和通知机制
| syscall | 版本 | 说明 |
inotify_init1 | 2.6.27 | 创建 inotify 实例(文件系统事件监控) |
inotify_add_watch | 2.6.13 | 添加 inotify 监控项 |
inotify_rm_watch | 2.6.13 | 移除 inotify 监控项 |
fanotify_init | 2.6.37 | 创建文件系统通知组(比 inotify 更强大) |
fanotify_mark | 2.6.37 | 标记文件/目录为监控目标 |
eventfd / eventfd2 | 2.6.22 / 2.6.27 | 创建事件通知 fd(轻量,比 pipe 高效) |
signalfd / signalfd4 | 2.6.22 / 2.6.27 | 通过 fd 读取信号(可 epoll) |
14. io_uring
Linux 5.1+ 引入的高性能异步 I/O 框架,通过共享内存环形缓冲区 (SQ/CQ) 提交和完成 I/O 请求,避免 syscall 上下文切换开销。
| syscall | 号 | 签名 | 说明 |
io_uring_setup | 425 | io_uring_setup(entries, params) | 创建 io_uring 实例,返回 fd。内核分配 SQ/CQ 共享内存 |
io_uring_enter | 426 | io_uring_enter(fd, to_submit, min_complete, flags, ...) | 提交 SQ 中的请求,并等待 at least min_complete 个完成 |
io_uring_register | 427 | io_uring_register(fd, opcode, arg, nr_args) | 注册文件或缓冲区(减少每次 I/O 的 fd 引用开销) |
io_uring 架构
传统 AIO (io_setup/io_submit/io_getevents/io_cancel/io_destroy) 仅支持 O_DIRECT 文件 I/O,io_uring 是通用替代方案。
15. 系统信息
| syscall | 号 | 签名 | 说明 |
uname | 63 | uname(buf) | 获取内核名称、版本、架构等信息(uname -a 的实现) |
sysinfo | 99 | sysinfo(info) | 获取系统统计信息(内存、负载、运行时间等) |
getpid | 39 | getpid() | 获取当前进程 PID |
gettid | 186 | gettid() | 获取当前线程 TID |
getuid | 102 | getuid() | 获取用户 UID |
getgid | 104 | getgid() | 获取组 GID |
getrandom | 318 | getrandom(buf, len, flags) | 获取内核 CSPRNG 随机数(比 /dev/urandom 更快) |
getrlimit | 97 | getrlimit(resource, rlim) | 获取资源限制(打开文件数、栈大小等) |
setrlimit | 160 | setrlimit(resource, rlim) | 设置资源限制 |
prctl | 157 | prctl(option, arg2, arg3, arg4, arg5) | 进程控制(PR_SET_NAME 设置线程名、PR_SET_SECCOMP 等) |
personality | 135 | personality(persona) | 设置进程执行域(如运行 i386 二进制时设置 PER_LINUX32) |
16. 其他常用
| syscall | 号 | 签名 | 说明 |
fcntl | 72 | fcntl(fd, cmd, ...) | fd 控制操作(F_GETFL/F_SETFL/F_DUPFD 等) |
dup | 32 | dup(fd) | 复制 fd |
dup2 | 33 | dup2(oldfd, newfd) | 复制 fd 到指定编号 |
chdir | 80 | chdir(path) | 切换当前工作目录 |
chmod | 90 | chmod(path, mode) | 修改文件权限 |
chown | 92 | chown(path, owner, group) | 修改文件所有者 |
mount | 165 | mount(source, target, fstype, flags, data) | 挂载文件系统 |
umount2 | 166 | umount2(target, flags) | 卸载文件系统(MNT_DETACH 延迟卸载) |
pivot_root | 155 | pivot_root(new_root, put_old) | 切换根文件系统(容器启动关键步骤) |
unshare | 272 | unshare(flags) | 解除共享的 namespace(容器隔离基础) |
eventfd | 284 | eventfd(initval, flags) | 创建事件通知 fd |
bpf | — | bpf(cmd, attr, size) | BPF 字节码加载/管理(eBPF 核心入口) |
ioctl | — | ioctl(fd, request, ...) | 设备通用控制操作 |
seccomp | — | seccomp(op, flags, args) | 安全计算模式(系统调用过滤) |
kcmp | 3.5 | kcmp(pid1, pid2, type, idx1, idx2) | 比较两进程的内核资源 |
文件系统与挂载 (新 API, Kernel 5.2+)
| syscall | 说明 |
fsopen | 打开文件系统上下文 |
fsconfig | 配置文件系统上下文 |
fsmount | 获取挂载文件描述符 |
fspick | 选择已有文件系统 |
move_mount | 移动挂载点 |
open_tree | 获取挂载树 fd |
17. 废弃系统调用与迁移路径
废弃/替换的核心规律
- *at 系列替代竞态版本:open→openat, stat→fstatat, rename→renameat2
- *2/*4/create1替代无 flags 版本:pipe→pipe2, dup2→dup3, epoll_create→epoll_create1
- fd 化替代信号版本:alarm→timerfd, SIGIO→signalfd, pipe→eventfd
- 64 位替代 32 位:getdents→getdents64, stat→stat64→statx
- /proc替代专有 syscall:_sysctl, get_kernel_syms, query_module
- 用户态替代内核态:nfsservctl→nfs-utils, uselib→dlopen
18. 安全与隔离
19. IPC 机制对比
20. sys_call_table 结构 (x86_64)
- x86_64 调用号即 sys_call_table 索引
- 调用号一旦分配,永不回收(即使 syscall 被移除)
- 新增调用追加到表尾
- 不同架构编号不同:x86_64 ≠ ARM ≠ RISC-V
- 32位兼容通过单独的 ia32_sys_call_table
21. 核心系统调用速查 (x86_64)
| 编号 | 调用名 | 频率 | 一句话说明 |
| 0 | read | 核心 | 从 fd 读数据,返回实际字节数 |
| 1 | write | 核心 | 向 fd 写数据,大块需循环 |
| 2 | open | 核心 | 打开/创建文件,返回 fd |
| 3 | close | 核心 | 关闭 fd |
| 9 | mmap | 核心 | 映射文件/匿名内存 |
| 41 | socket | 核心 | 创建网络套接字 |
| 42 | connect | 核心 | 发起 TCP 连接 |
| 49 | bind | 核心 | 绑定地址/端口 |
| 59 | execve | 核心 | 替换进程映像 |
| 57 | fork | 核心 | 创建子进程 |
| 56 | clone | 核心 | 创建进程/线程(底层) |
| 202 | futex | 核心 | 用户态锁的内核支撑 |
| 232 | epoll_wait | 核心 | 等待 epoll 事件就绪 |
| 291 | epoll_create1 | 核心 | 创建 epoll 实例 |
| 233 | epoll_ctl | 核心 | 注册/修改/删除监控 fd |
| 228 | clock_gettime | 核心 | 获取高精度时间 (vDSO) |
| 425 | io_uring_setup | 核心 | 创建 io_uring 实例 |
| 7 | poll | 核心 | 等待多个 fd 事件 |
| 217 | getdents64 | 常用 | 读取目录项 |
| 72 | fcntl | 常用 | fd 属性/锁控制 |
| 281 | epoll_pwait | 常用 | epoll_wait + 信号掩码 |
| 319 | memfd_create | 常用 | 创建匿名内存文件 |
| 12 | brk | 低频 | 调整进程堆边界 |
| 135 | personality | 极冷门 | 设置执行域 (Wine) |
22. 设计哲学
23. 附录
23.1 常用错误码
| errno | 名称 | 含义 |
| 1 | EPERM | 操作不允许(权限不足) |
| 2 | ENOENT | 文件/目录不存在 |
| 4 | EINTR | 系统调用被信号中断 |
| 5 | EIO | I/O 错误 |
| 9 | EBADF | fd 无效 |
| 11 | EAGAIN | 非阻塞操作暂无资源(try again) |
| 12 | ENOMEM | 内存不足 |
| 13 | EACCES | 权限拒绝 |
| 14 | EFAULT | 地址无效(bad address) |
| 17 | EEXIST | 文件已存在 |
| 22 | EINVAL | 参数无效 |
| 24 | EMFILE | 进程 fd 达到上限(too many open files) |
| 28 | ENOSPC | 磁盘空间不足 |
| 32 | EPIPE | 管道破裂(写入端已关闭) |
| 105 | ENOBUFS | 内存缓冲区耗尽(网络常见) |
| 111 | ECONNREFUSED | 连接被拒绝 |
23.2 常用信号
| 编号 | 名称 | 默认行为 | 说明 |
| 1 | SIGHUP | Term | 挂断(终端关闭) |
| 2 | SIGINT | Term | 中断(Ctrl+C) |
| 3 | SIGQUIT | Core | 退出(Ctrl+\) |
| 6 | SIGABRT | Core | 异常终止(abort()) |
| 8 | SIGFPE | Core | 算术异常(除零等) |
| 9 | SIGKILL | Term | 强制杀死(不可捕获/忽略) |
| 10 | SIGUSR1 | Term | 用户自定义信号1 |
| 11 | SIGSEGV | Core | 段错误(非法内存访问) |
| 12 | SIGUSR2 | Term | 用户自定义信号2 |
| 13 | SIGPIPE | Term | 管道破裂 |
| 14 | SIGALRM | Term | 定时器到期 |
| 15 | SIGTERM | Term | 终止(优雅退出) |
| 17 | SIGCHLD | Ignore | 子进程状态变更 |
| 18 | SIGCONT | Continue | 继续被暂停的进程 |
| 19 | SIGSTOP | Stop | 暂停进程(不可捕获/忽略) |
| 20 | SIGTSTP | Stop | 终端暂停(Ctrl+Z) |
| 31 | SIGSYS | Core | 非法系统调用(seccomp 触发) |