实验内容
- 找一个系统调用,系统调用号为学号最后2位相同的系统调用
- 通过汇编指令触发该系统调用
- 通过gdb跟踪该系统调用的内核处理过程
- 重点阅读分析系统调用入口的保存现场、恢复现场和系统调用返回,以及重点关注系统调用过程中内核堆栈状态的变化
环境配置
继续在上次的实验环境下进行安装和配置。还是用的之前linux-5.4.34源码,只是不再打补丁。
1 make defconfig 2 make menuconfig
打开debug相关选项
关闭KASLR,否则会导致打断点失败
编译和运行内核
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
接下来制作内存根文件系统
下载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
修改编译选项,要编译成静态链接,不用动态链接库。
然后编译安装,默认会安装到 _install 目录中。
make -j$(nproc) && make install
制作内存根文件系统镜像,在 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
实验过程
打开/linux-5.4.34/arch/x86/entry/syscalls/syscall_64.tbl
并找到对应中断,本人学号后两位为67,查得为shmdt
查资料得知shmdt系统调用主要用在共享内存操作结束时:
共享存储允许两个或多个进程共享一个给定的存储区,是进程间通信最快的一种方式。不要同时对共享存储空间进行写操作,通常,信号量用于同步共享存储访问。
最简单的共享内存的使用流程:①ftok函数生成键值 ②shmget函数创建共享内存空间 ③shmat函数获取第一个可用共享内存空间的地址 ④shmdt函数进行分离(对共享存储段操作结束时的步骤,并不是从系统中删除共享内存和结构)⑤shmctl函数进行删除共享存储空间
由此可知shmdt调用发生在shmat之后,进程结束后,调用shmdt函数进行从共享内存分离(detach)
所需头文件:#include
函数原型: int shmdt(const void *addr);
addr为shmat函数返回的地址指针,即指向共享内存第一个字节的指针
返回值:成功返回0;错误返回-1
编写测试代码test.c
编译运行
编写对应的汇编代码
将该文件放在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
系统调用入口
运行过程
在创建了一个共享内存区域后,还要将它映射到进程地址空间,系统调用shmat()完成此项功能,并返回一个共享内存地址。当进程使用完毕之后,通过do_syscall_64执行系统调用内容,触发相应函数shmdt,进入内核态,完成进程与共享空间的分离,完成之后返回用户空间
实验总结
通过本次实验接触到了linux更深层的源码,了解了内联汇编的写法,gdb的调试,文件系统的建立和编译,以及系统调用时用户态和内核态的切换。
本次实验还有诸多不足,希望下次能做的更好。