Day6-系统调用

今天的内容相对比较少,之前也有基础,除了寄存器的东西还是看不懂,其他基本以前就会。

什么是系统调用?以下是chatGPT的答案:

在Linux操作系统中,系统调用(System Call)是应用程序与内核交互的一种机制。它是应用程序通过特定函数请求内核提供某些服务或执行某些操作的接口。

Linux系统调用提供了一种标准化的接口,使得应用程序能够访问底层的操作系统功能,例如文件操作、进程管理、网络通信等。通过系统调用,应用程序可以向内核发出请求,获取所需的资源或执行特定的操作。

系统调用有助于实现应用程序与操作系统之间的交互和通信。它们通过提供抽象和封装,隐藏了内核的复杂性,使得应用程序开发者能够更加方便地编写跨平台的软件,并且能够利用操作系统提供的各种功能。

一些常见的Linux系统调用包括:

  1. 文件相关的系统调用:例如open(打开文件)、read(读取文件)、write(写入文件)、close(关闭文件)等。
  2. 进程管理相关的系统调用:例如fork(创建子进程)、exec(执行新程序)、exit(退出进程)等。
  3. 网络通信相关的系统调用:例如socket(创建套接字)、connect(建立连接)、send(发送数据)、recv(接收数据)等。
  4. 内存管理相关的系统调用:例如malloc(分配内存)、free(释放内存)、mmap(映射文件到内存)等。

需要注意的是,系统调用是在用户态和内核态之间进行切换的开销比较大的操作,因此在设计应用程序时需要谨慎使用系统调用,并尽量减少不必要的系统调用次数,以提高程序的性能。

开胃小菜

Linux存在用户空间和内核空间,同样的CPU也划分系统调用(System Call)是用户态程序使用内核态服务的接口。为什么用户态调用内核态的能力需要有专门的接口呢?这进而在暗示我们,用户态和内核态有一些本质区别。那么这个本质区别是什么呢?以x86为例,CPU时刻处于4个ring中的某一个,称之为Current Privilege Level (CPL)。

Linux使用了ring 0和ring 3,其中内核态为ring0,用户态为ring3。

ring0可以做一切事情。比如,内核态的代码具有硬件的所有访问权限,所有内核态的代码共享一个虚拟地址空间等。

在ring3状态下,属于用户态,能做的非常有限,其主要原因就是防止用户态的进程

什么是系统调用?

系统调用就是操作系统提供给用户程序调用系统服务(硬件设备)的一组"特殊"接口。

系统调用可被看成是一个内核与用户空间程序交互的接口——它好比一个信使,把用户进程的请求传达给内核,待内核把请求处理完毕后再将处理结果送回给用户空间。

为什么需要系统调用

在开胃小菜里面其实也提到过几点了。

第一,把用户从底层的硬件编程中解放出来,与具体的硬件完全隔离,用户不需要面向具体的硬件编码,降低了开发的复杂度和难度。

第二,极大的提高了系统的安全性。将用户进程隔离,实现内核"保护",用户进程不允许访问内核数据,也无法使用内核函数。用户访问内核的路径是事先规定好的,只能从规定位置进入内核,而不允许肆意跳入内核。有了这样的内核访问路径限制,才能保证内核安全无误。

第三,使用户程序具有可移植性,实现不同平台不同硬件的程序移植。

系统调用过程

系统调用并不是让用户程序直接使用的,用户程序应该使用标准C库来享受系统调用提供的服务。这种系统调用和标准C库的混合所最终呈现出的接口就是我们说的Linux API(也即C库中和系统调用相关的API)。

用户态应用程序调用System Call的过程是:

  • 应用程序调用C库函数(Linux API);
  • C库函数(Linux API) 将系统调用号存入 EAX;
  • C库函数(Linux API) 把函数参数存入其它通用寄存器(%rdi、%rsi、%rdx、%r10、%r8、%r9);
  • C库函数(Linux API) 通过中断调用使系统进入内核态:x86上触发0x80 号中断(int 0x80),x86-64上触发syscall/sysenter;
  • 内核中的中断处理函数根据系统调用号,调用对应的内核函数(系统调用);
  • 内核函数(系统调用)完成相应功能,将返回值存入 EAX,返回到内核中的中断处理函数;
  • 内核中的中断处理函数返回到C库函数(Linux API) 中;
  • C库函数(Linux API) 将 EAX 返回给应用程序。

最后的syscall就是用来触发系统调用,syscall会导致如下的步骤:

  • 将syscall后面的指令的地址保存到RCX寄存器;
  • MSR_LSTAR(Model Specific Register_Long System Target Address Register)的值装载到RIP寄存器;这个寄存器上的值正是entry_SYSCALL_64函数的地址;
  • 从rax寄存器读到$1,知道是write系统调用;
  • 从rdi、rsi、rdx分别读到此次系统调用的三个参数:分别是File descriptor(gemfield.S中是$1,也就是标准输出stdout)、字符串的地址、字符串的长度;
  • 执行完该系统调用后,我们又将进入下一个系统调用;
  • 从rax寄存器读到$60,知道是exit系统调用;
  • rdi读到此次系统调用的一个参数:返回值30。

系统调用号

每个系统调用被赋予一个系统调用号,与具体的系统调用相关联。

系统调用表

内核维护系统调用表,保存系统调用函数的起始位置,系统调用号对应该系统调用在调用表中的偏移量。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值