Linux内核源码解析 | system call part 2
摘要
- 回顾: 应用程序如何调用 system call
- 初始化 system calls table
2. 回顾
- 应用程序必须首先将 对应的
system call
在 系统调用表中对应的编号 存入rax
寄存器,然后以正确的顺序 将正确的system call
参数值填充通用寄存器 rdi ,rsi,rdx ,rcx ,r8 中,并使用syscall
指令进行实际的系统调用 - 由
syscall
指令,系统 将跳入 存储在 MSR_LSTAR Model specific register(Long system target address register)中的地址,在该地址, 存有一个 system call 全局处理函数entry_SYSCALL_64
, entry_SYSCALL_64
负责根据rax 寄存器的值 调用内核中对应的 system call hanler function.
3.初始化 system calls table
3.1 为什莫要 初始化 system calls table? 这个表是干什么的?
当在执行 entry_SYSCALL_64
时, entry_SYSCALL_64
需要根据rax
中对应的 system call
的编号,调用对应的 system call handler function。但是Linux内核如何搜索该system call
所对应系统调用处理程序的地址呢? Linux内核包含一个特殊的表,称为system calls table
。系统调用表由sys_call_table
数组表示,entry_SYSCALL_64
将通过该数组,找到 该system call 所对应的处理函数的地址,并调用该处理函数完成 system call。
3.2 如何初始化 system calls table
system calls table
由Linux内核中的sys_call_table
数组表示,该数组在arch / x86 / entry / syscall_64.c源代码文件中定义。让我们看一下它的实现
asmlinkage const sys_call_ptr_t sys_call_table[__NR_syscall_max+1] = {
[0 ... __NR_syscall_max] = &sys_ni_syscall,
#include <asm/syscalls_64.h>
};
sys_call_table
是长度为__NR_syscall_max + 1
的数组,其中__NR_syscall_max
宏表示给定体系结构的最大系统调用数。在 x86_64 体系结构下 共有 547个 系统调用(#define __NR_syscall_max 547),与之对应,在 系统调用表中也有相同数量的 system call
3.2.1 the sys_call_table array 的 类型 是什么?
sys_call_ptr_t
表示指向system call table
的指针。它被定义为用于不返回任何内容且不接受参数的函数指针:
typedef void (*sys_call_ptr_t)(void);
3.2.2 初始化 sys_call_table array
- 首先 数组中所有的元素,即 指向
system call handler function
的指针 指向了sys_ni_syscall
.sys_ni_syscall
函数表示未实现的系统调用。 这跟 初始化 int 变量类似,仅仅是为了使该变量在内存空间中占有一个“位置”。sys_ni_syscall
仅仅是一个返回 -errno 的函数:
asmlinkage long sys_ni_syscall(void)
{
return -ENOSYS; //ENOSY tell us Function not implemented (POSIX.1)