当前位置: 首页 > news >正文

【Note】《深入理解Linux内核》Chapter 10 :Linux 内核中的系统调用机制全解析

《深入理解Linux内核》Chapter 10 :Linux 内核中的系统调用机制全解析

摘要:系统调用、内核态、用户态、中断门、syscall 表、寄存器传参、x86 调用号、调用路径、安全检查、性能优化


一、什么是系统调用?

系统调用(System Call)是操作系统为用户程序提供的 受控访问内核资源 的接口。

用户态程序不能直接访问内核内存、I/O、文件、进程管理等,必须通过系统调用请求服务。

典型的系统调用包括:

  • 文件操作:open(), read(), write(), close()
  • 进程控制:fork(), execve(), exit(), wait()
  • 内存管理:mmap(), brk()
  • 网络通信:socket(), bind(), recv(), send()

二、系统调用的实现机制总览

系统调用流程可分为以下几个步骤:

  1. 用户程序调用 glibc 封装函数(如 read());
  2. glibc 使用特定指令触发 CPU 进入内核态;
  3. 内核接收调用号和参数,执行对应服务;
  4. 系统调用完成后返回用户态,恢复现场。

三、系统调用号与调用表

每个系统调用对应一个唯一编号(call number),在源码中定义:

// include/uapi/asm-generic/unistd.h
#define __NR_read 0
#define __NR_write 1
#define __NR_open 2
...

3.1 系统调用表

Linux 使用系统调用表(system call table)将编号映射为内核函数指针:

// arch/x86/kernel/syscall_table.S
ENTRY(sys_call_table).quad sys_read.quad sys_write.quad sys_open

当用户程序触发系统调用后,内核根据调用号(保存在寄存器中)查表找到实际执行函数。


四、用户态与内核态的切换机制

4.1 切换指令:int 0x80 与 syscall

指令架构说明
int 0x80x86(32 位)软中断,早期实现
syscallx86-64新指令,更高效
sysenterIntel x86特定快速调用方式

x86-64 上,glibc 封装函数使用 syscall 指令:

mov $60, %rax       ; syscall号:exit
mov $0, %rdi        ; 参数1:返回码
syscall             ; 进入内核
  • 系统调用号存入 %rax
  • 参数存入 %rdi, %rsi, %rdx, %r10, %r8, %r9
  • 返回值存入 %rax

五、系统调用的内核路径:从入口到处理函数

以 64 位系统为例,系统调用进入路径如下:

5.1 系统调用入口

// arch/x86/entry/entry_64.S
entry_SYSCALL_64:...call do_syscall_64

5.2 调用处理函数

// arch/x86/kernel/syscall.c
asmlinkage __visible void do_syscall_64(struct pt_regs *regs)
{syscall_nr = regs->orig_rax;...syscall_fn = syscall_table[syscall_nr];return syscall_fn(...);
}

5.3 参数获取与返回

  • 参数从 regs 中提取;
  • 执行调用逻辑;
  • 结果写回 %rax

六、内核中定义系统调用

6.1 定义系统调用函数

// kernel/sys.c
SYSCALL_DEFINE3(read, unsigned int, fd, char __user *, buf, size_t, count)
{// 实现细节
}
  • SYSCALL_DEFINEn 宏自动生成封装函数,处理参数验证与展开;
  • 宏展开后生成 sys_read()、参数提取与类型转换逻辑。

6.2 注册系统调用

系统调用在构建过程中自动注册进 sys_call_table

sys_call_table:.quad sys_read.quad sys_write

修改或添加系统调用需更新 unistd.hsyscall_table.S 等。


七、系统调用与安全性机制

系统调用是用户空间进入内核的唯一合法入口,内核必须防止以下安全风险:

7.1 用户空间指针校验

  • copy_from_user()
  • copy_to_user()

防止内核直接访问非法用户地址。

7.2 访问控制

  • 文件权限检查;
  • 信号发送需检查目标进程权限;
  • 特权系统调用如 mount() 要求 CAP_SYS_ADMIN;

7.3 seccomp 限制调用集

prctl(PR_SET_SECCOMP, SECCOMP_MODE_STRICT);

或使用 BPF 定义调用白名单:

struct sock_filter prog[] = {BPF_STMT(BPF_LD + BPF_W + BPF_ABS, syscall_nr_offset),BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, __NR_write, 0, 1),BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_KILL)
};

八、系统调用的性能优化

8.1 syscall vs 用户空间函数

系统调用涉及:

  • 用户态到内核态切换;
  • TLB 刷新;
  • 中断门上下文保护。

因此较 memcpy() 等纯用户函数慢数十倍。

8.2 减少系统调用开销的方法

  • 合并调用(如 readv()/writev());
  • 避免频繁 gettimeofday()
  • 使用 mmap() 替代频繁读写;
  • 使用 epoll() 替代反复 poll()

九、系统调用与 glibc 的关系

glibc 是用户程序的标准 C 库,它通过封装系统调用提供 API 接口:

ssize_t read(int fd, void *buf, size_t count) {return syscall(SYS_read, fd, buf, count);
}

glibc 可提供缓存(如 malloc())、错误处理、异步支持。

一些函数并非系统调用,而是用户空间实现(如 printf())。


十、系统调用调试与分析工具

工具用途
strace捕捉系统调用及其参数、返回值
perf trace性能事件与系统调用时间分析
ltrace跟踪动态库函数调用
gdb可设置断点在 syscall 封装层或内核
/proc/<pid>/syscall显示进程当前正在执行的系统调用
BPF + bcc 工具内核层系统调用跟踪

十一、Linux 的系统调用分类

类型说明示例函数
进程管理创建、终止、等待、执行fork(), execve(), wait()
文件系统打开、读写、关闭、seekopen(), read(), close()
内存管理分配、映射、调整mmap(), brk(), mprotect()
网络通信套接字、连接、接收发送socket(), send(), recv()
IPC管道、共享内存、信号、消息队列pipe(), shmget(), kill()
时间计时、延迟nanosleep(), gettimeofday()
特权操作装载模块、挂载文件系统mount(), reboot()

十二、系统调用兼容性与体系结构差异

Linux 针对不同体系结构定义不同调用号及参数寄存器规范:

架构系统调用号寄存器参数传递顺序
x86-64raxrdi, rsi, rdx, r10, r8, r9
x86-32eaxebx, ecx, edx, esi, edi, ebp
ARMr7r0-r6

不同架构维护各自的 syscall 表和入口代码。


十三、自定义系统调用实验建议(内核开发者)

  1. 修改 arch/x86/entry/syscalls/syscall_64.tbl 添加自定义 syscall 编号;
  2. kernel/sys.c 添加实现函数(SYSCALL_DEFINEx);
  3. 编译内核并加载;
  4. 使用内核模块或测试程序调用 syscall;
  5. 使用 strace 或 BPF 验证调用行为;

十四、与中断/异常/陷阱机制的关系

系统调用本质上是一种用户主动触发的陷阱(trap):

  • 与硬件异常(page fault)不同,系统调用是显式行为;
  • 使用 int 0x80syscall 指令建立陷阱门;
  • 进入中断门时自动保存上下文并切换内核栈。

十五、总结与对比表

项目描述
定义方式使用 SYSCALL_DEFINE() 宏定义内核函数
注册机制添加到 sys_call_table 映射中
调用方式通过特定 CPU 指令触发陷阱进入内核
参数传递方式寄存器传参(架构相关)
安全检查检查用户空间指针、权限、合法性等
性能特点上下文切换、用户态-内核态来回切换
扩展机制可用 BPF 或 seccomp 进行控制或过滤
http://www.dtcms.com/a/265951.html

相关文章:

  • 贝叶斯深度学习:赋予AI不确定性感知的认知革命
  • 【Oracle学习笔记】8.函数(Function)
  • 湖北理元理律师事务所的债务管理方法论
  • 算法刷题打卡(1)—— 快速排序
  • 睿尔曼系列机器人——以创新驱动未来,重塑智能协作新生态(上)
  • 【python】OOP:Object-Oriented Programming
  • 数字人分身+矩阵系统聚合+碰一碰发视频: 源码搭建-支持OEM
  • AI开发平台:从技术壁垒到全民创新,AI 开发平台如何重构产业生态?
  • C++ 标准模板库算法之 transform 用法
  • STC8G 8051内核单片机开发 (中断)
  • 在 UniApp 项目中巧用开发工具与 AI 插件:全面提升开发到部署的效率
  • 【时间序列数据处理的噩梦与救赎:一次复杂数据可视化问题的深度复盘】
  • 运维服务部初级服务工程师面招聘笔试题和答案
  • PROFINET转MODBUS TCP网关在机械臂通信操作中的应用研究
  • 微信小程序——skyline版本问题
  • 2025年金融创新与计算机视觉国际会议(FICV 2025)
  • 【网络协议】WebSocket简介
  • Web 服务器架构选择深度解析
  • HTTP-Postman的安装及其使用
  • 电脑CPU使用率占用100%怎么办 解决步骤指南
  • 【数字后端】- 衡量design的congestion情况
  • HTTP各版本变化详解
  • C# 线程同步(一)同步概念介绍
  • 基于Anything LLM的本地知识库系统远程访问实现路径
  • react-打包和本地预览 ——打包优化
  • 基于CNN的人脸关键点检测
  • 强实时运动控制内核MotionRT750(一):驱动安装、内核配置与使用
  • 【科普】Cygwin与wsl与ssh连接ubuntu有什么区别?DIY机器人工房
  • 【大模型学习】项目练习:文档对话助手
  • 零碳园区如何建设,微电网系统来助力