深入理解系统调用

深入理解系统调用

一、实验要求 


  • 找一个系统调用,系统调用号为学号最后2位相同的系统调用
  • 通过汇编指令触发该系统调用
  • 通过gdb跟踪该系统调用的内核处理过程
  • 重点阅读分析系统调用入口的保存现场、恢复现场和系统调用返回,以及重点关注系统调用过程中内核堆栈状态的变化

二、配置实验环境

1.配置内核选项

1 make menuconfig

 

  • Kernel hacking > Compile-time check and compiler options > Provide GDB scripts for kernel debugging  打开
  • 返回上一页勾选Kernel debugging
  • 返回首页,选中Processor type and features ---->Randomize the address of the kernel image (KASLR)   关闭

重新编译和运行内核

1 make -j$(nproc)
2 qemu-system-x86_64 -kernel arch/x86/boot/bzImage

 

2. 制作根文件系统

2.1安装编译busybox

axel -n 20 https://busybox.net/downloads/busybox-1.31.1.tar.bz2
tar -jxvf busybox-1.31.1.tar.bz2
cd busybox-1.31.1
make menuconfig
Settings  ---> [*] Build static binary (no shared libs)
make -j$(nproc) && make install

2.2制作根文件目录

返回到~/目录下,创建根文件目录

 mkdir rootfs
 cd rootfs
 cp ../busybox-1.31.1/_install/* ./ -rf
 mkdir dev proc sys home 
 sudo cp -a /dev/{null,console,tty,tty1,tty2,tty3,tty4} dev/

在rootfs目录下制作init脚本

touch init
vim init
 #!/bin/sh
 mount -t proc none /proc 
 mount -t sysfs none /sys
 echo "Wellcome MyOS!"
 echo "--------------------" 
 cd home
 /bin/sh 
给init脚本添加执行权限
chmod +x init

最后在rootfs目录下打包镜像文件

find . -print0 | cpio --null -ov --format=newc | gzip -9 > ../ rootfs.cpio.gz 
#测试挂载根⽂件系统,看内核启动完成后是否执⾏init脚本 
qemu-system-x86_64 -kernel linux-5.4.34/arch/x86/boot/bzImage -initrd rootfs.cpio.gz

 

三、编写测试程序

1. 我的学号后两位是53,因此找到系统调用号为53的系统调用:socketpair

1 cd ~/linux-5.4.34/arch/x86/entry/syscalls
2 vi syscall_64.tbl

 

2.socketpair的功能介绍

  • 功能描述: 建立一对已连接上的套接字,并已数组的形式返回套接字描述词
  • 用法:   

    #include <sys/types.h>

    #include <sys/socket.h>

    int socketpair(int d, int type, int protocol, int sv[2]);

  • 参数:

    d:通信域,用于选择地址族。

    type:套接字类型。

    protocol:通信协议。

    sv:存放返回值的数组。

  • 返回说明:   成功执行时,返回新套接字的文件描述词。失败返回-1,errno被设为以下的某个值 

    EAFNOSUPPORT:指定的地址族不被支持

    EFAULT:sv指向的内存并非有效的一部分进程地址空间

    EMFILE:进程文件表溢出

    ENFILE:已达到系统限制的打开总文件数

    EOPNOTSUPP:指定协议不支持建立套接字对的操作

    EPROTONOSUPPORT:通信域不支持指定的协议

3.编写用于调用socketpair的测试程序

 1 /*socketpair.c*/
 2 #include <sys/types.h>
 3 #include <sys/socket.h>
 4 #include <stdlib.h>
 5 #include <stdio.h>
 6 #include <errno.h>
 7 #include <unistd.h>
 8 
 9 int main ()
10 {
11     int sv[2];
12     int result = socketpair(AF_UNIX, SOCK_STREAM, 0, sv);
13     if (result < 0){
14         exit(1);
15     }
16     printf("sv[0] is : %d \n", sv[0]);   
17     printf("sv[1] is : %d \n", sv[1]);
18     pid_t pid;
19     pid = fork();
20     if (pid > 0){ /* 父进程 */
21         int val = 0;
22         close(sv[1]);    //父进程关闭sv[1]的读写权限
23         while (1){          
24             ++val;
25             printf("father send message: %d\n", val);   
26             write(sv[0], &val, sizeof(val));            //父进程向管道里写数据
27             sleep(1);
28         }
29     }else if(pid == 0){  /*子进程*/
30         int val = 0;
31         close(sv[0]); //字进程关闭sv[0]的读写权限
32         while(1){
33             read(sv[1], &val, sizeof(val));            //字进程从管道中取数据
34             printf("son receive message: %d\n",val);
35         }
36     }else{ /*没有创建成功*/
37         exit(1);
38     }
39 }

 

 编译并且执行

1 gcc -o socketpair socketpair.c -static 
2 ./socketpair

 

 

 4.对测试代码反汇编

1 objdump -S socketpair > socketpair.S

5.将socketpair 和 socketpair.c移动到~/rootfs/home 目录下

6.重新打包镜像文件

find . -print0 | cpio --null -ov --format=newc | gzip -9 > ../ rootfs.cpio.gz 

 

四、使用gdb跟踪该系统调用的内核处理过程

1、启动qemu:

1 qemu-system-x86_64 -kernel ~/lab2-linux-5.4.34/arch/x86/boot/bzImage -initrd ~/rootfs.cpio.gz -S -s -nographic -append "console=ttyS0"

此时终端界面会停止

 

 2开启一个新的终端,设置断点

1 cd lab2-linux-5.4.34
2 gdb vmlinux
3 target remote:1234
4 b __x64_sys_socketpair
5 c            

 

 

 在之前停止的终端下执行socketpair

在设置的断点处停下

接下来进行单步调试:可以看到有系统调用entry_SYSCALL_64()

 

 

 

五、总结

系统调⽤的执⾏,也就是⽤户程序触发系统调⽤之后,CPU及内核执⾏系统调⽤的过程

32位中:int $0x80是CPU压栈⼀些关键寄存器,接着内核负责保存现场,系统调⽤内核 函数处理完后恢复现场,最后通过iret出栈哪些CPU压栈的关键寄存器。

64位中:sysenter和syscall都借助CPU内部的MSR寄存器来查找系统调⽤处理⼊⼝,可 以快速切换CPU的指令指针(eip/rip)到系统调⽤处理⼊⼝,但本质上还是中 断处理的思路,压栈关键寄存器、保存现场、恢复现场,最后系统调⽤返回。

x86-64引⼊了swapgs指令,类似快照的⽅式将保存现场和恢复现场时的CPU寄 存器也通过CPU内部的存储器快速保存和恢复,近⼀步加快了系统调⽤

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

posted @ 2020-05-25 13:24  小国旗  阅读(251)  评论(0)    收藏  举报