优秀的编程知识分享平台

网站首页 > 技术文章 正文

Linux系统调用源码分析(二)

nanyue 2024-11-22 18:34:49 技术文章 2 ℃

Linux系统调用是内核提供服务的接口函数,进程通过它完成自身所需的全部功能,每个平台都有自己的实现方式。我们以ARMv8为例讲解此调用的过程,包括程序调用C库的open函数,C库执行svc进入CPU异常模式,然后内核找到系统调用函数并执行它,最后返回到用户空间的一个过程。它就好比我们要建造一个房子,程序代码就是设计图纸,内核就是建筑工人,我们委托建筑工人根据图纸建好整个房子的过程。

一、程序调用C库执行open系统调用

假设程序已经创建并运行了一段时间,这时,程序要打开一个文件进行读写就需要执行open系统调用。系统调用的代码已经封装在C库里,程序只需调用C库的接口函数就可以实现全部功能。我们先来写一个模拟程序,看看如何实现的,如下图:

执行编译命令:

  • aarch64-none-linux-gnu-gcc sys_call_open.c -o sys_call_open --static

执行反汇编命令:

  • aarch64-none-linux-gnu-objdump -D sys_call_open > asm

得到汇编指令如下:

从上图得知,C库把fopen自动转换成了对openat的系统调用(前文讲了openat与open的区别),并把系统调用的参数写在x1,x2,x3寄存器里。

24160行,设置x8寄存器为系统调用号0x38(openat的系统调用号0x38)。

24161行,程序执行svc #immed指令将触发CPU进入异常模式,svc的立即数并没有被Linux使用,而是把系统调用号放到了x8寄存器里。执行完系统调用后,程序将会回到执行svc的下一行代码处继续执行。接下来,我们看一下CPU进入异常模式后是如何运行的。

二、CPU进入异常模式

程序执行C库svc指令后,CPU进入异常模式。内核根据异常类型及中断向量表里的地址,调用同步异常处理例程(中断设置我们另文再说),现在看看同步异常处理例程el0_sync的代码。

592行, kernel_entry是一个汇编宏代码,做进入系统调用前的准备工作,包括保存程序执行的现场,载入与CPU核相关的线程数据,保存异常返回地址等。打个比方就像建筑工人建房子到一半,需要回家办点事情,这时需要把图纸放下,把工衣脱掉,换好西装体面的回去。

593行,读取系统寄存器esr_el1的值。异常不单单只有系统调用会触发,内存缺页、指令错误等也会触发,因此,esr_el1[26:31]就保存了异常发生的原因。

594行,取出esr_el1中产生异常的原因,保存在x24里。

595行,ARM定义系统调用的原因为ESR_ELx_EC_SVC64,把它与x24与比较,如果相等则执行系统调用的代码,如果不相等则需继续往下走,表明异常是由其他原因触发的,比如内存缺页等。

596行,执行el0_svc系统调用的代码。

三、找到系统调用函数并执行它

el0_syc函数是用来处理系统调用的,首先从系统全局唯一的系统调用表里,取得C库调用svc时准备的系统调用号,然后根据调用号索引找到系统调用表里相应的函数地址,最后执行它。

892行,载入全局系统调用列表sys_call_table的地址。

893行,取出系统调用号(w8即是x8的低32位寄存器),保存到scno(x26)里。系统调用号是C库代码在每个系统调用前写入x8寄存器里的。

894行,获得全部系统调用的最大值并保存到sc_nr(x25)里。

907行,比较系统调用号与最大值,结果保存在状态寄存器里。

908行,比较的结果大于最大值,则跳到ni_sys处执行错误处理。

909行,把系统调用号作为索引,取出sys_call_table表中相应的函数地址,这里保存的就是sys_open的地址。sys_open函数地址如何设置到sys_call_table表里请参考前一篇文章。

910行,调用sys_open函数,完成此系统调用的功能。

四、返回用户空间

程序调用完sys_open函数后,系统调用的功能就执行完毕了,剩下的任务就是返回到程序的用户空间里,继续执行剩下的代码。就像建筑工人从家里回来继续工作时,要穿回工衣,拿回图纸,继续砌砖了。

ret_fast_syscall函数,执行流返回到的用户空间里去。

826行,关闭中断

827行,系统调用的返回值保存进堆栈里。

838行,kernel_exit是一个汇编宏与kernel_entry相对应,恢复之前程序执行的现场,设置异常返回地址,执行eret指令,返回到用户空间里去。

以上就是系统调用流程的代码分析。

相关文章连接:

Linux系统调用源码分析


最后放一张好看的风景照,表示想到那里去休息一下。梦想还是要有的,万一实现了呢!


最近发表
标签列表