深入理解系统调用
一、实验内容
1.学号末尾为51,故采用151号系统调用
2.通过汇编指令触发系统调用
3.通过gdb跟踪该系统调用的内核处理过程
4.阅读分析系统调用入口的保存现场、恢复现场和系统调用返回,以及关注系统调用过程中内核堆栈状态的变化
二、环境准备
1. 环境楼
2.所采用的内核为linux-3.18.6
三、查看系统调用,编写汇编代码
我选择的是151号系统调用sys_mlockall。它的作用是将进程使用的部分或者全部的地址空间锁定在物理内存中,防止其被交换到swap空间。
有些对时间敏感的应用会希望全部使用物理内存,以提高数据访问和操作的效率。其相关函数如下,可以采用三种形式中的一种来进行系统调用。
int mlock(const void *addr, size_t len); int munlock(const void *addr, size_t len); int munlockall(void);
采用第二种方法来编写c程序。
#include<sys/mman.h> int lockall(){ int o=mlockall(MCL_CURRENT); return 0; }
其对应的汇编程序为。具体编写对应汇编代码的方法
通过追踪C库函数time的反汇编代码,可以发现32位和64位x86中分别使⽤int $0x80和syscall汇编指令触发time系统调⽤。由于是通过EAX寄存器传递系统调⽤号,分析静态编译汇编代码可以发现32位x86Linux系统中time系统调⽤号为0xd(13),64位x86 Linux系统中time系统调⽤号为0xc9(201),通过查阅Linux源代码中arch/x86/entry/syscalls/syscall_32.tbl可以找到13号time系统调⽤对应的内核处理函数为sys_time,在arch/x86/entry/syscalls/syscall_64.tbl 可以找到201号time系统调⽤对应的内核处理函数为__x64_sys_time
#include<sys/mman.h> int main(){ int o; int in; asm volatile( "movq $0x1, %%rdi\n\t" "movl $0x97, %%eax\n\t" "syscall\n\t" "movq %%rax, %0\n\t" :"=m"(o) :"g"(in) );return 0; }
之后,将这段代码放入menu/test.c中,如下图所示
并且还需要修改test.c主函数,给操作系统添加mlockall命令,我们就可以之后通过这条命令执行这个方法。
四、gdb调试与分析
使用qemu来启动操作系统内核
qemu-system-x86_64 -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img -S -s
使用gdb vmlinux来启动gdb,在启动gdb的同时,还可以将符号表加载进gdb中。
gdb vmlinux
其中,在sys_mlockall处设置断点,当操作系统加载完毕时,我们可以通过命令行调用test.c中mlockall方法来启动系统调用。但是在具体实验中出现了一些误差,其中
无法将对test.c的修改应用到rootfs.img中。
五.系统调用分析
触发系统调用后,通过调用swapgs和压栈保存了现场,然后通过do_syscall_64
函数,在ax寄存器中得到系统调用号,然后去执行系统调用。再完成执行现场的恢复,然后出栈指令恢复原 rdi 和 rsp的内容,也就是完成了堆栈的切换。