系统调用

glibc 对系统调用的封装

  在用户态进程里调用open函数 【 int open(const char *pathname, int flags, mode_t mode)  】 

在glibc 源代码中有个文件 syscalls.list  , 里面咧着所有glibc 的函数对应的系统调用。 另外还有一个脚本 make-syscall.sh ,可根据配置文件,对于每个封装好的系统调用,生成一个文件。 另外还有一个文件 syscall-template.S  使用上面这个宏,定义系统调用的调用方式。

对于任何一个系统调用,会调用 DO_CALL 。 这个宏32位和64位定义不同。

在源代码注释中, int 就是interrupt 。中断的意思。 int $0x80 就是触发一个软中断,通过它就可以陷入(trap) 内核。

  在内核启动时,其中会有一个软中断的陷入门,当接收到一个系统调用的时候,相应的文件就会被调用,然后通过 push 和 SAVE_ALL 将当前用户态的寄存器,保存在 pt_regs 结构中。 进入内核前,会保持所有的寄存器,然后调用 do_syscall_32_irqs_on 。在这里,将系统调用号从eax里面取出来,然后根据系统调用号,在系统调用表中找到相应的函数进行调用。并将找出来的参数取出来,作为函数参数。且参数对于的寄存器与linux 的注释是一样的。

当系统调用结束后会接着调用 INRRUPT_RETURN 。定义的是 iret。 此iret指令会将原来的用户态保持的现场恢复回来,包含代码段,指令指针寄存器等。用户态进程恢复执行

 

 

 

64位系统调用过程

  将系统调用名称转换为系统调用号,放在寄存器rax ,此时是真正进行调用,不中断了。 改用syscall 指令。并且传递参数的寄存器也变了。  syscall 指令使用了特殊的寄存器,叫特殊模块寄存器(Model Specific Registers 。简称 MSR ) 

系统初始化时,trap_init 除了初始化上面的中断模式,还会调用 cpu_init -> syscall_init  其中rdmsr 和 wrmsr 是用来读写特殊模块寄存器的。 MSR_LSTAR 就是这样的一个特殊的寄存器。 当 sys call 指令调用的时候,会从寄存器里面拿出函数的地址调用( entry_SYSCALL_64)

并且在 arch/x86/entry/entry.64.S 中定义了 entry_SYSCALL_64。 里面保持了很多的寄存器到 pt_regs 结构里面。列入用户态的代码段,数据段,保存参数的寄存器。 然后调用 entry_SYSCALL64_slow_pat -> do_syscall_64  。在此调用里,从rax 里面拿出系统调用号,根据系统调用号在系统调用表 sys_call_table 中找到相应的函数进行调用,并将寄存器中保存的参数取出来,作为函数参数。 这些参数所对应的寄存器,与Linux 的注释又是一样的。

  所以,无论是32位,还是64位,都会到系统调用表 sys_call_table 这里来,64位系统调用返回的时候,执行的是 USERGS_SYSRET64 ,返回用户态的指令变成了 sysretq  。

 

系统调用表

  系统调用表 sys_call_table 的形成: 

      32位的系统调用表定义在面 arch/x86/entry/syscalls/syscall_32.tbl 文件里 

      64位的系统调用表定义在面 arch/x86/entry/syscalls/syscall_64.tbl 文件里

系统调用在内核中的实现函数有一个声明, 声明在 include/linux/syscalls.h 文件中 ,真正的实现这个系统调用,一般在一个 .c 的文件里面。 列如 sys_open 的实现在 fs/open.c 里面。 其中 SYSCALL_DEFINE3 是一个宏系统调用最多六个参数,会根据参数的数目选择宏。至此,声明和实现都好了,接下来编译的过程中,需要根据 syscall_32.tbl 和 syscall_64.tbl 生成自己的 unistd_32.h 和 unistd_64.h 。 生成方式在 arch/x86/entry/syscalls/Makefile 中。 会使用两个脚本,第一个脚本 arch/x86/entry/syscalls/syscallhdr.sh , 会在文件中生成 #define_NR_open; 第二个脚本 arch/x86/entry/syscalls/syscalltbl.sh ,  会在文件中生成 _SYSCALL(_NR_open,sys_open) 。 这样, unistd_32.h 和 unistd_64.h 是对应的系统调用号和系统调用实现函数之间的对应关系。

    在 arch/x86/entry/syscall_32.c 定义了一个表,里面 include 了这个头文件,从而所有的 sys_ 系统调用都在这个表里面了。 同理,在文件 arch/x86/entry.syscall_64.c 文件里也是一样的定义,sys_系统调用也都在这个表里面 

 

转载于:https://www.cnblogs.com/JaPer/p/10810096.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值