深入理解系统调用

实验内容

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

环境配置

  继续在上次的实验环境下进行安装和配置。还是用的之前linux-5.4.34源码,只是不再打补丁。

1 make defconfig
2 make menuconfig

  打开debug相关选项

 深入理解系统调用_第1张图片

 

 

  关闭KASLR,否则会导致打断点失败

 深入理解系统调用_第2张图片

 

 

   编译和运行内核

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

  测试内核能否加载,因为没有文件系统最终会 kernel panic

qemu-system-x86_64 -kernel arch/x86/boot/bzImage

 深入理解系统调用_第3张图片

 

  接下来制作内存根文件系统

  下载busybox,执行时提示太多重定向?直接在宿主机下好了复制进虚拟机

1 axel -n 20 https://busybox.net/downloads/busybox-1.31.1.tar.bz2
2 tar -jxvf busybox-1.31.1.tar.bz2
3 cd busybox-1.31.1

  修改编译选项,要编译成静态链接,不用动态链接库。

  深入理解系统调用_第4张图片

  然后编译安装,默认会安装到 _install 目录中。

make -j$(nproc) && make install

  深入理解系统调用_第5张图片

  制作内存根文件系统镜像,在 linux-5.4.34 目录下创建 rootfs 文件夹,将 _install 内容复制过来,创建其他所需的文件

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

  准备 init 脚本文件放在根文件系统根目录下(rootfs/init),新建名为 init 的文件,写入:

#!/bin/sh
mount -t proc none /proc
mount -t sysfs none /sys
echo "Wellcome WallenOS!"
echo "--------------------"
cd home
/bin/sh

  给init脚本添加可执行权限

chmod +x init

  打包成内存根文件系统镜像,返回到 linux-5.4.34目录下,启动qemu测试挂载根文件系统

1 find . -print0 | cpio --null -ov --format=newc | gzip -9 > ../rootfs.cpio.gz
2 qemu-system-x86_64 -kernel arch/x86/boot/bzImage -initrd rootfs.cpio.gz

深入理解系统调用_第6张图片

 

 

 

实验过程

  打开/linux-5.4.34/arch/x86/entry/syscalls/syscall_64.tbl并找到对应中断,本人学号后两位为67,查得为shmdt

深入理解系统调用_第7张图片

  

  查资料得知shmdt系统调用主要用在共享内存操作结束时:

  共享存储允许两个或多个进程共享一个给定的存储区,是进程间通信最快的一种方式。不要同时对共享存储空间进行写操作,通常,信号量用于同步共享存储访问。

  最简单的共享内存的使用流程:①ftok函数生成键值   ②shmget函数创建共享内存空间   ③shmat函数获取第一个可用共享内存空间的地址   ④shmdt函数进行分离(对共享存储段操作结束时的步骤,并不是从系统中删除共享内存和结构)⑤shmctl函数进行删除共享存储空间

  由此可知shmdt调用发生在shmat之后,进程结束后,调用shmdt函数进行从共享内存分离(detach)

  所需头文件:#include  #include

  函数原型: int shmdt(const void *addr);

  addr为shmat函数返回的地址指针,即指向共享内存第一个字节的指针   

  返回值:成功返回0;错误返回-1   

  

  编写测试代码test.c

      深入理解系统调用_第8张图片

  编译运行

     

 

 

  编写对应的汇编代码

 深入理解系统调用_第9张图片

 

 

   将该文件放在rootfs/home目录下,进行静态编译,重新打包

1 gcc test.c -o test -static
2 find . -print0 | cpio --null -ov --format=newc | gzip -9 > ../rootfs.cpio.gz
3 qemu-system-x86_64 -kernel arch/x86/boot/bzImage -initrd rootfs.cpio.gz -S -s -nographic -append "console=ttyS0"

  启动系统后,在一个新的终端开启gdb开始调试, 打上断点

1 cd linux-5.4.34/
2 gdb vmlinux
3 target remote:1234
4 b __x64_sys_shmdt

 系统调用入口

深入理解系统调用_第10张图片

 

 

 运行过程

深入理解系统调用_第11张图片

 

 

 深入理解系统调用_第12张图片

在创建了一个共享内存区域后,还要将它映射到进程地址空间,系统调用shmat()完成此项功能,并返回一个共享内存地址。当进程使用完毕之后,通过do_syscall_64执行系统调用内容,触发相应函数shmdt,进入内核态,完成进程与共享空间的分离,完成之后返回用户空间

实验总结

通过本次实验接触到了linux更深层的源码,了解了内联汇编的写法,gdb的调试,文件系统的建立和编译,以及系统调用时用户态和内核态的切换。

本次实验还有诸多不足,希望下次能做的更好。

 

你可能感兴趣的:(深入理解系统调用)