系统调用

系统调用

系统调用是什么:   系统调用是用户在编程时调用的操作系统功能。

系统调用的作用:   系统调用是操作系统提供给编程人员的唯一接口;使CPU状态从用户态陷入内核态的唯一途径。

典型系统调用举例:每个操作系统都提供几百种系统调用(进程控制、进程通信、文件使用、目录操作、设备管理、信息维护等)。

系统调用、库函数、API、内核函数的关系

  

 如图所示,应用程序当然可以直接使用系统调用,但是通常情况下,都是在应用程序中先去加载C函数库或者API接口,由这两个东西去申请系统调用。然后系统调用由内核封装而成,并不是每个内核函数都能被系统调用,有些是被禁止的。

每个C函数库最终使用的系统调用可能有多个,也有可能多个C函数对应一个系统调用,呈现一对多、多对一的情况。

系统调用机制的设计

  1. 中断/异常机制 -- 支持系统调用服务的实现
  2. 选择一条特殊指令:陷入指令(亦称访管指令) 。引发异常,完成用户态向内核态的切换
  3. 系统调用号和参数:因为存在很多的系统调用,为了区分,每个系统调用都事先给定一个编号(系统调用功能号),也会有一些参数。
  4. 系统调用表:存放系统调用服务例程的入口地址

参数传递过程的问题

一般的函数调用都是通过栈来传递参数的,但是用户程序不能把参数推到系统的栈里去,这是不允许的。那我们如何将用户调用函数的参数传递给内核呢?

常用的3种实现方法:

 

系统调用举例

转变成的汇编语言:

movl $4,$eax    //这是一条x86架构下的汇编指令,它的作用是将立即数4(即常数4)移动到寄存器eax中。是write()的系统调用功能号。
int $0x80    //用于在x86架构的处理器上触发系统调用(System Call)。系统调用是一种特殊的操作,允许用户程序请求操作系统提供的服务和资源,如文件操作、进程管理等。

解释该陷入指令的含义:

  • int: 这是x86汇编指令中的"interrupt"指令,用于触发中断。
  • $0x80: 这是一个立即数操作数,表示中断向量号。在x86架构中,中断向量号0x80(十进制为128)是用于系统调用的。

当执行int $0x80指令时,处理器会切换到内核模式,进入内核中的系统调用处理程序。内核会根据寄存器中的信息,确定用户程序请求的服务类型和参数,并执行相应的系统调用。系统调用完成后,处理器会从内核态切换回用户态,继续执行用户程序的下一条指令。

 

系统调用的执行过程

当CPU执行到特殊的陷入指令时:

  • 中断/异常机制:硬件保护现场;通过查中断向量表来将CPU控制权转给系统调用总入口程序。
  • 系统调用总入口程序:保存现场;将参数保存在内核的堆栈里;通过查系统调用表把控制权转给相应的内核函数或者是系统调用的处理程序。
  • 执行系统调用例
  • 恢复现场,返回用户程序

 

Linux系统调用执行流程

  1.  用户态下调用C库的库函数,比如write()。
  2. 封装后的write()先做好参数传递工作,然后使用int 0x80指令产生一次中断/异常。
  3. 然后就陷入了内核态, CPU通过0x80号在IDT(中断描述符表)找到对应的服务例程system_call(),并调用之,这个是总的系统调用的入口地址。
  4. 然后其实在陷入之前,已经做好了一些压栈工作,比如一些重要的寄存器,用户栈的信息,EFLAGS信息和返回地址(不然系统调用结束后不知道怎么返回)。但是陷入之后呢,system_call这个主控程序还要把eax再压栈,再把剩余的其他寄存器的内容全部压栈(SAVE_ALL)。

     system_call():将参数保存在内核栈;根据系统调用号(系统功能号)索引系统调用表,找到系统调用程序入口,比如sys_write()。

    5. sys_write()执行完后,经过ret_from_sys_call()例程返回到用户程序。

 

posted @ 2023-08-05 16:51  C++杀我  阅读(109)  评论(0编辑  收藏  举报