每日科普 · 2026-11-02 周一
考研 408 × 求职面试
知识点 · 操作系统 · 进阶
系统调用的执行过程与参数传递
系统调用是用户程序请求操作系统内核服务的受控入口。执行过程可概括为:
1. 用户态准备:按 ABI 把系统调用号放入约定寄存器(如 x86-64 Linux 用 rax),参数放入 rdi、rsi、rdx、r10、r8、r9,超过 6 个参数通常放到内存并由寄存器传指针。
2. 陷入内核:执行 syscall(或 int 0x80)触发特权级切换,CPU 保存返回地址和标志,跳到内核入口。
3. 内核处理:保存用户上下文,检查调用号,查系统调用表找到服务例程,把用户参数安全拷贝/校验后执行,可能阻塞或调度。
4. 返回用户态:结果放回 rax,恢复现场并执行 sysret/iret;若出错常用负 errno 表示,用户库再设置 errno。
参数传递核心是 ABI 约定:少量参数用寄存器,多参数用栈/内存指针;内核不能直接信任用户指针,需 copy_from_user 等机制。与普通函数调用不同,系统调用跨越特权级,开销更大。
每日一题 · 操作系统
系统调用的执行过程与参数传递
在 Linux x86-64 中执行 write(fd, buf, len) 系统调用时,参数传递和调用号位置通常是?
A. 参数压栈,调用号放 eax
B. 调用号放 rax,前三个参数依次放 rdi、rsi、rdx,再用 syscall
C. 调用号放 rdi,参数放 rax
D. 全部参数由内核从用户栈直接读取,无需寄存器
解析
答案 B。x86-64 Linux 的系统调用约定是:rax 放系统调用号,rdi、rsi、rdx、r10、r8、r9 依次传前六个参数,超过部分放内存。用户态执行 syscall 陷入内核后,内核保存现场、按 rax 查系统调用表并分派,参数从寄存器或用户内存安全拷贝,返回值放 rax。因此 write 的 fd、buf、len 分别放 rdi、rsi、rdx。
面试小贴士 · 操作系统
系统调用的执行过程与参数传递
面试常问执行流程、参数如何传、与函数调用区别。答:用户态按 ABI 准备调用号与参数→陷入→内核保存现场、查表分派、执行并返回;参数多用寄存器,超限用内存,用户指针需校验/拷贝。易错:syscall 不是普通函数、返回值与 errno、寄存器约定。
代码实现 · C
代码示例
#include <stddef.h>
int main(void) {
const char msg[] = "hello syscall\n";
long ret;
// x86-64 Linux:rax=1(write),rdi=fd,rsi=buf,rdx=len
__asm__ volatile(
"mov $1, %%rax\n"
"mov $1, %%rdi\n"
"mov %1, %%rsi\n"
"mov %2, %%rdx\n"
"syscall\n"
: "=a"(ret)
: "r"(msg), "r"(sizeof(msg) - 1)
: "rdi", "rsi", "rdx", "rcx", "r11", "memory"
);
return ret == (long)(sizeof(msg) - 1) ? 0 : 1;
}