深入理解Linux系统调用
实验目的
1.找一个系统调用,系统调用号为学号最后2位相同的系统调用,我学号最后两位为90。
2.通过汇编指令触发该系统调用。
3.通过gdb跟踪该系统调用的内核处理过程。
4.重点阅读分析系统调用入口的保存现场、恢复现场和系统调用返回,以及重点关注系统调用过程中内核堆栈状态的变化。
首先下载必要工具
sudo apt install build-essential libncurses-dev bison flex libssl-dev libelf-dev
下载linux源码
sudo apt install axel axel -n 20 https://mirrors.edge.kernel.org/pub/linux/kernel/v5.x/ linux-5.4.34.tar.xz
xz -d linux-5.4.34.tar.xz tar -xvf linux-5.4.34.tar
配置内核编译选项
make defconfig # Default configuration is based on 'x86_64_defconfig' make menuconfig # 打开debug相关选项 Kernel hacking ---> Compile-time checks and compiler options ---> [*] Compile the kernel with debug info [*] Provide GDB scripts for kernel debugging [*] Kernel debugging # 关闭KASLR,否则会导致打断点失败 Processor type and features ----> [] Randomize the address of the kernel image (KASLR)


编译和运行内核
make -j$(nproc) # nproc gives the number of CPU cores/threads available # 测试⼀下内核能不能正常加载运⾏,因为没有⽂件系统终会kernel panic qemu-system-x86_64 -kernel arch/x86/boot/bzImage # 此时应该不能正常运行,会报kernel pannic错误,因为没有文件系统。
制作内存根文件系统
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/<br>
touch init创建脚本文件init在目录下,并且输入:
mount -t proc none /procmount -t sysfs none /sysecho "Wellcome OS!"echo "--------------------"cd home/bin/sh制作内存根文件系统的过程
step1 : 打包成内存根文件系统镜像
find . -print0 | cpio --null -ov --format=newc | gzip -9 > ../rootfs.cpio.gz
step2 : 测试挂载根文件系统,看内核启动完成后是否执行init脚本!
qemu-system-x86_64 -kernel linux-5.4.34/arch/x86/boot/bzImage -initrd rootfs.cpio.gz

可见脚本Wellcome OS 已经执行 ,则可以进行下一步
用汇编代码编写系统调用程序
学号后两位是90,对应的系统调用为chmod

编写test_chmod.c程序,调用90号系统调用。
#include<stdio.h>
int main() { asm volatile( "movl $0x5A,%eax\n\t" //使⽤EAX传递系统调⽤号90 "syscall\n\t" //触发系统调⽤ ); printf("-----------chmod---------------\n"); return 0; }
用gcc静态编译,生成可执行文件
gcc -o test_chmod test_chmod.c -static
执行可执行文件,输出
![]()
将文件放至rootfs/home路径下,重新执行如下两条语句:
find . -print0 | cpio --null -ov --format=newc | gzip -9 > ../rootfs.cpio.gz
qemu-system-x86_64 -kernel linux-5.4.34/arch/x86/boot/bzImage -initrd rootfs.cpio.gz

可以看到test_chmod可执行文件已经在文件系统中了
gdb调试
step1 : 用如下命令行启动qemu
qemu-system-x86_64 -kernel linux-5.4.34/arch/x86/boot/bzImage -initrd rootfs.cpio.gz -s -S
step2 : 新开一个terminal,启动gdb
cd linux-5.4.34/ # 切到对应的文件夹 gdb vmlinux
step3 : 在__x64_sys_chmod系统调用打断点
(gdb) target remote:1234 (gdb) b __x64_sys_chmod

这个时候qemu是黑屏,这个时候输入c ,qemu开始执行。

然后在qemu中执行test_chmod,在gdb中可以捕获到断点.

可以使用bt来观察方法的堆栈从而知道 entry_SYSCALL_64是系统调用的入口,它在系统调用之前已经初始化了该方法对应的内核堆栈

使用n 进行单步执行进行debug调试,可以看到保存现场信息的步骤:

继续调试 直到最后结束,可以看到恢复现场以及系统调用返回,以及从内核态返回用户态的步骤:

实验总结
本次实验从调试源码的角度,调试了linux内核系统调用的过程,深刻理解了入口的保存现场、恢复现场和系统调用返回的过程,以及系统调用过程中内核堆栈状态的变化。
总而言之:应用程序调用API,然后trap陷入,进入系统迪用,进入内核态,保存现场执行中断处理程序 然后恢复现场返回用户态。其中保存现场和恢复现场都是通过操作内核的堆栈实现的。同时,这次实验也告诉我们,学习一门技术应该深入底层进行了解和实践,眼见为实,而不能只学习理论,这样是不够扎实的。

浙公网安备 33010602011771号