深入理解系统调用
深入理解系统调用
一、实验要求
- 找一个系统调用,系统调用号为学号最后2位相同的系统调用(我的学号尾号为66,故记录66号调用)
- 通过汇编指令触发该系统调用
- 通过gdb跟踪该系统调用的内核处理过程
- 重点阅读分析系统调用入口的保存现场、恢复现场和系统调用返回,以及重点关注系统调用过程中内核堆栈状态的变化
二、配置实验环境
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寄存器中获取到系统调用号,然后去执行系统调用内容

浙公网安备 33010602011771号