0%

《趣谈linux操作系统》小结(七)-系统调用流程

系统调用流程

32位的系统调用的过程,首先保存参数、系统调用号到寄存器,然后触发中断int80 ,调用中断处理服务函数,然后取到寄存器里的参数,根据系统调用号获取执行函数,传入参数执行。执行完成后,iret恢复用户态执行上下文,继续执行。

图片替换文本

64位系统调用流程和32位的有区别,他是通过syscall指令,而不是中断来触发调用的,相应的寄存器也不相同了。syscall使用了特殊的模块寄存器MSR,用来保存64位系统调用函数的地址。syscall指令会从MSR中读取函数地址来执行系统调用号对应的函数, 地址是在初始化的时候写入的start_kernel–>cpu_init–>syscall_init。

1
wrmsrl(MSR_LSTAR, (unsigned long)entry_SYSCALL_64);

最后调用sysiretq 恢复用户态执行上下文,继续执行。

图片替换文本

系统调用表

系统调用函数都是从系统调用表中根据系统调用号找到的。那么系统调用表sys_call_table是个什么鬼呢?

32 位的系统调用表定义在 arch/x86/entry/syscalls/syscall_32.tbl 文件里。64 位的系统调用定义在另一个文件 arch/x86/entry/syscalls/syscall_64.tbl 里。

系统调用在内核中的实现函数要有一个声明。声明往往在 include/linux/syscalls.h 文件中。例如 sys_open 是这样声明的:

1
2
3
4

asmlinkage long sys_open(const char __user *filename,
int flags, umode_t mode);

一般程序调用glibc封装的系统调用, 比如open函数的一个调用流程如图:

图片替换文本

行动,才不会被动!

欢迎关注个人公众号 微信 -> 搜索 -> fishmwei,沟通交流。