深入理解系统调用

深入理解系统调用

  一、实验要求

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

  二、配置实验环境

   1.配置内核选项

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

   2. 安装编译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

   3. 制作根文件目录

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/

    4. 在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

    5. 在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. 在arch/x86/entry/syscalls/syscall_64.tbl中,查找尾号为73的系统调用

73    common    flock            __x64_sys_flock
173    common    ioperm            __x64_sys_ioperm
273    64    set_robust_list        __x64_sys_set_robust_list

  2. 编译一个简单的C语言文件执行系统调用

#include<stdio.h>
#include<sys/file.h>
# include <fcntl.h>
#include <unistd.h>
int main(void){
    int fd;
    fd=open("test.txt",O_WRONLY|O_CREAT);
    printf("The fd value is : %d \n", fd);
    int ret = flock(fd,1);
    printf("The return value is : %d \n", ret);
    close(fd);
    return 0;
}            

  3. 查看flock系统调用的汇编代码

#include<sys/file.h>
# include <fcntl.h>
#include <unistd.h>
int main(void){
    int fd;
    int ret;
    fd=open("test.txt",O_WRONLY|O_CREAT);
    asm volatile(
        "movl $0x1, %%esi\n\t"    //esi寄存器用于传递参数
         "movl $0x3, %%edi\n\t" //edi寄存器用于传递参数
        "mov $0x49, %%eax\n\t" //eax寄存器用于传递系统调用号
        "syscall\n\t"
        "movq %%rax,%0\n\t"      //保存返回值
        :"=m"(ret)
    );
    printf("The return value is : %d \n", ret);
    close(fd);
    return 0;
}

  返回值为0,说明系统调用成功

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

  1,启动qemu

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

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

  3,进行单步调试:可以看到有系统调用entry_SYSCALL_64()

  五、总结

  1,触发系统调用后,代码执行了/linux-5.4.34/arch/x86/entry/entry_64.S 目录下的ENTRY(entry_SYSCALL_64)入口,然后开始通过swapgs 和压栈动作保存现场:

   2,然后跳转到了/linux-5.4.34/arch/x86/entry/common.c 目录下的 do_syscall_64 函数,在ax寄存器中获取到系统调用号,然后去执行系统调用内容

posted @ 2020-05-27 17:21  下饭java学习者  阅读(195)  评论(0)    收藏  举报