当前位置:首页>Linux>Linux执行系统调用的完整过程

Linux执行系统调用的完整过程

  • 2026-09-26 15:25:45
Linux执行系统调用的完整过程
步骤1:用户态程序准备调用参数(用户态)
用户程序,以write(1,"hello",5);为例
1,确定系统调用号(write是1)
2,将系统调用号存入rax寄存器
3,将调用参数按顺序存入指定寄存器
第一个参数->rdi(write的文件描述符1)
第二个参数->rsi(比如字符串地址)
第三个参数->rdx(字符串长度)
这一步全程在用户态
步骤2:执行syscall指令,触发内核调用(用户态->内核态)

用户程序执行汇编指令 syscall(64 位专属特权指令):

  • 这个指令直接向 CPU 发送 “请求切换到内核态” 的信号,比 32 位int 0x80更高效(无中断处理的冗余开销);
  • 这是整个流程的 “开关”,执行完这条指令,CPU 就开始准备切换特权级。
步骤 3:CPU 切换到内核态,保存用户态现场(CPU + 内核)
CPU接收到syscall后,自动完成两件事:
1,特权级切换:从用户态(Ring3,低特权,不能操作硬件 / 内核内存)切换到内核态(Ring0,高特权,可访问所有资源);
2,保存现场:
    • 把用户态的程序计数器(rip,记录下一条要执行的指令地址)存入 rcx 寄存器;
    • 把用户态的标志寄存器(rflags)存入 r11 寄存器;
    • 内核会把这些寄存器值 + 用户态其他寄存器(如rdi/rsi)保存到内核栈中(目的:处理完能精准回到用户程序原来的位置)。
步骤4:内核找到对应的系统调用处理函数(内核态)
内核通过rax中的系统调用号,匹配具体的逻辑处理
1,内核有一张系统调用表(sys_call_table),表里存储了所有系统调用的处理函数地址(比如sys_write对应write,sys_exit对应exit)
2,内核根据rax中的数值,从表中找到对应的函数->内核确认要办什么事情,避免调错逻辑
步骤5:内核执行系统调用处理函数(内核态)
步骤6:内核设置返回值(内核态)
处理完成后,内核把执行结果存入rax寄存器
1,成功:返回操作结果(例如write返回实际写入的字节数,read返回读取的字节数)
2,失败:返回负数错误码(比如 - 1),并在内核中记录errno(用户态程序可通过perror()等函数查看具体错误)。
步骤7:内核恢复用户态现场,切换回到用户态(内核+CPU)

内核从内核栈中取出步骤 3 保存的用户态数据,完成 “返程准备”:

  • 把rcx中保存的用户态rip恢复到 CPU 的程序计数器;
  • 把r11中保存的用户态rflags恢复;
  • CPU 执行sysret指令(syscall的配套指令),从内核态(Ring0)切回用户态(Ring3);→ 这一步完成后,CPU 的特权级回到用户态,且记住了用户程序该继续执行的位置。
步骤8:用户程序继续执行(用户态)
CPU回到用户程序中,从syscall指令的下一条指令开始执行
1,用户程序读取rax寄存器中的返回值,判断系统调用是否成功
2,继续执行后续逻辑

最新文章

随机文章