3分钟了解syscall系统调用|详细易懂的流程

syscall

1.简介

系统调用(syscall)是操作系统提供给程序以请求内核服务的一种机制。和int 0x80提供相同的服务。

2.详细解释

在计算机系统中,操作系统控制着对硬件资源的访问。应用程序不能直接操作硬件,而是需要通过操作系统提供的接口。系统调用就是这些接口之一,允许应用程序执行诸如读写文件、发送网络请求、创建进程等操作。系统调用作为用户空间(应用程序执行的地方)和内核空间(操作系统核心部分执行的地方)之间的桥梁,确保资源使用的安全性和有效性。

3.具体举例

以Linux操作系统中的read()系统调用为例。当一个程序想要从文件中读取数据时,它会执行以下步骤:

  1. 程序调用read()函数,并提供文件描述符(文件的唯一标识)、存放数据的缓冲区地址和要读取的字节数。
  2. read()函数将这些参数传递给操作系统内核。
  3. 内核检查参数的有效性,然后从文件系统中读取数据到缓冲区。
  4. 读取完成后,控制返回给程序,程序可以使用缓冲区中的数据。

4.比喻解释

可以将系统调用比作餐厅里的服务员。就像顾客不能直接进入厨房取菜,而需要通过服务员传达他们的需求一样,应用程序也不能直接访问硬件资源,而需要通过系统调用来请求操作系统执行特定的任务。

5.作用

系统调用使应用程序能够执行文件操作、进程控制、通信等操作,同时确保了操作系统能够控制和管理资源访问,保证系统的稳定性和安全性。

6.优点

安全性: 隔离用户程序和内核,防止直接的硬件访问导致的安全问题。
易用性: 提供了标准化的接口,简化了程序对硬件的操作。
兼容性: 应用程序通过系统调用与操作系统交互,减少了对特定硬件的依赖。

7.总结

系统调用是操作系统提供给应用程序的一种重要接口,它使得程序能够安全、有效地执行需要操作系统干预的操作,如文件处理、进程管理等。尽管系统调用引入了一定的性能开销,但它的安全性和易用性使得它成为操作系统设计中不可或缺的一部分。

syscall和int 0x80有什么不同?

1. 上下文切换效率

INT 80h:指令 INT 80h 触发软件中断。执行时,CPU 需要在处理中断之前保存程序的当前状态,包括各种寄存器。此过程是一个上下文切换,它涉及大量开销,因为 CPU 实质上是在暂停一个任务以启动另一个任务。

syscall: 该 syscall 指令旨在最大限度地减少需要保存和恢复的状态量,从而减少上下文切换开销。这是从用户模式到内核模式的更直接的过渡,需要更少的 CPU 时间和资源使用

2. 指令执行流程

INT 80h: 使用 INT 80h ,中断处理机制更复杂。CPU 必须跳转到中断向量,然后中断向量指向相应的内核例程。这会增加额外的步骤并增加指令的路径长度。
syscall: syscall 提供更直接的路径。它使用特殊的 CPU 寄存器直接跳转到内核中的系统调用处理程序。这种较短的路径意味着仅向内核发送系统调用请求所花费的 CPU 周期更少。

3. 兼容性

虽然 syscall 效率更高,但只能用于特定的CPU体系架构。INT 80h具有向后兼容性,对于不可以使用syscall的机器或旧软件上尤为重要。

总结

SYSCALL减少了上下文切换和简化了指令执行流程,性能更高,但对旧机器的兼容性不如int 80h.

syscall 具体流程

当执行系统调用的时候,具体的执行流程如下。
请添加图片描述

1. 用户空间准备

在用户空间中,在执行 syscall 指令之前,应用程序会设置系统调用号及其参数。这通常是通过将系统调用号放在寄存器中(对于 x86-64 体系结构)并将参数放在其他 RAX 寄存器(如 RDI, RSI, RDX, R10, R8 和 R9 )中来完成的。

2. 执行syscall指令

应用程序执行syscall CPU 指令。和add,mov一样,这是专为转换到内核模式以执行系统调用而设计的 CPU 指令。读取到该指令后,CPU就会依次完成下面工作。

3. 切换到内核态

CPU从用户态(ring 3)切换到内核模式(ring 0),以获得更高的执行权限。
这一步步骤的具体流程

1. 最小的上下文保存
a). CPU 自动将指令指针RIP保存到寄存器中 RCXRIP 指向应用程序中应在系统调用完成后执行的指令
b). 将包含 CPU 当前状态的 RFLAGS 寄存器保存到寄存器中R11 。这包括中断启用/禁用标志等标志。

这种最小的上下文保存是提升INT 80h 效率的关键改进之一。

2. 直接跳转到系统调用处理程序
CPU载入模型特定寄存器(MSR)IA32_LSTAR,其中包含内核中系统调用入口点的地址直接跳转到系统调用处理程序。这种直接跳转是相对于 INT 80h 方法的另一个效率改进,INT 80h 方法需要遍历中断描述符表。

至此,完成了内核态的切换,下面开始在内核模式下执行系统调用的程序。

4. 内核模式下执行系统调用

1. 执行调度程序
CPU 现在处于内核模式,在IA32_LSTAR 指向的地址处执行代码。这是Linux 内核中的系统调用调度程序。

调度程序从 RAX 寄存器中读取系统调用号。根据该调用号,从内核系统调用表中查找到相应的内核函数

调度程序调用系统调用号对应的函数。该函数的参数取自寄存器(RDI、RSI、RDX、R10、R8、R9)。

2. 执行内核函数
内核函数执行。这可能涉及各种操作,例如访问文件、创建进程或修改系统设置,具体取决于调用的系统调用。
完成后,内核函数通常会返回一个结果,该结果将放置在寄存器中 RAX

5. 返回用户空间

处理完系统调用后,内核需要将控制权交还给用户空间中的应用程序。
CPU执行sysret 指令。此指令针对从系统调用返回进行了优化。
sysret 恢复 CPU 的用户模式操作状态。它从 RCX 寄存器加载 RIP,从 R11 寄存器加载 RFLAGS,有效地返回到执行syscall之前的状态。
CPU 切换回用户模式,并在原始系统调用指令之后立即在应用程序中继续执行。

  • 19
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
新增系统调用需要进行以下步骤: 1. 编写系统调用的 C 语言函数。 2. 在内核源代码中添加系统调用的处理函数。 3. 在系统调用表中注册新的系统调用号。 4. 更新系统调用头文件。 5. 编译内核并安装。 下面分别给出每个步骤的详细方法: 1. 编写系统调用的 C 语言函数 新的系统调用需要编写对应的 C 语言函数。例如,假设我们要新增一个名为 `my_syscall` 的系统调用函数,可以在一个新的文件中编写该函数的代码: ```c #include <linux/kernel.h> asmlinkage long my_syscall(void) { printk(KERN_INFO "my_syscall is called\n"); return 0; } ``` 该函数的返回值类型为 `long`,使用 `asmlinkage` 关键字表示其是一个内核态函数。在函数内部,可以编写对应的系统调用处理代码。在本例中,我们只是简单地打印一条信息,并返回 0。 2. 在内核源代码中添加系统调用的处理函数 在内核源代码中,需要添加一个新的系统调用处理函数,来处理新增的系统调用。具体来说,需要在 `sys.c` 文件中添加对应的代码,例如: ```c asmlinkage long sys_my_syscall(void) { return my_syscall(); } ``` 在这个函数中,我们只是简单地调用之前编写的 `my_syscall` 函数,并返回其返回值。 3. 在系统调用表中注册新的系统调用号 在 Linux 内核中,系统调用号是通过一个系统调用表来管理的。新增的系统调用需要在该表中注册对应的系统调用号。在 `arch/x86/entry/syscalls/syscall_64.tbl` 文件中,添加如下行: ``` 333 common my_syscall __x64_sys_my_syscall ``` 其中,第一列是系统调用号,第二列是调用约定(通常使用 `common`),第三列是系统调用的名称,最后一列是内核处理函数的名称。 4. 更新系统调用头文件 需要在系统调用头文件中添加对应的声明。在 `include/linux/syscalls.h` 文件中,添加如下行: ```c asmlinkage long sys_my_syscall(void); ``` 5. 编译内核并安装 最后,需要重新编译内核,并安装到系统中。具体来说,可以按照以下步骤进行: (1)下载并解压内核源代码: ```bash wget https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.10.60.tar.xz tar -xvf linux-5.10.60.tar.xz ``` (2)进入内核源代码目录,并进行配置: ```bash cd linux-5.10.60 make menuconfig ``` 在配置界面中,需要将新增的系统调用选项打开,以便编译器能够正确地编译内核。 (3)进行编译: ```bash make -j4 ``` 这里的 `-j4` 表示使用 4 个线程进行编译,可以根据实际情况进行调整。 (4)安装内核: ```bash make modules_install make install ``` 这将会安装编译好的内核到系统中。 (5)重启系统: ```bash reboot ``` 系统重启后,就可以使用新增的系统调用了。可以使用 `strace` 命令来检查系统调用的使用情况,例如: ```bash strace -e my_syscall ls / ``` 这将会在执行 `ls` 命令时调用新增的 `my_syscall` 系统调用

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值