深入理解系统调用
配置环境
1.安装编译工具和qemu虚拟机
sudo apt install build-essential libncurses-dev bison flex libssl-dev libelf-dev
sudo apt install qemu
sudo apt install axel
2.下载内核源码和busybox,分别解压
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
axel -n 20 https://busybox.net/downloads/busybox-1.31.1.tar.bz2 tar -jxvf busybox-1.31.1.tar.bz2
3.配置编译内核生成bzImage文件
cd linux-5.4.34
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)
4.制作根文件系统
cd busybox-1.31.1
make menuconfig #记得要编译成静态链接,不⽤动态链接库。 Settings ---> [*] Build static binary (no shared libs) #然后编译安装,默认会安装到源码⽬录下的 _install ⽬录中。 make -j$(nproc)
make install
5.制作根文件系统镜像
cd ..
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/
在roofs根目录下创建init文件,init文件内容如下:
#!/bin/sh mount -t proc none /proc mount -t sysfs none /sys echo "Welcome My OS!" echo "-------------------" cd home /bin/sh 复制代码
给init脚本添加可执行权限
chmod +x init
将根文件系统打包为镜像
find . -print0 | cpio --null -ov --format=newc | gzip -9 > ../rootfs.cpio.gz
此时运行qemu,测试挂载根⽂件系统,看内核启动完成后是否执⾏init脚本
qemu-system-x86_64 -kernel linux-5.4.34/arch/x86/boot/bzImage -initrd rootfs.cpio.gz
运行成功,环境就此搭建完成
编写系统调用测试程序,放入根文件系统中,重新打包镜像
我的学号最后两位是12,到linux-shiyan2/linux-5.4.34/arch/x86/entry/syscalls中的syscall_64.tbl文件中查看系统调用号12的系统调用
12对应brk系统调用,brk用于实现虚拟内存到内存的映射,在roofs/home下创建test.c文件,测试代码如下:
#include<stdio.h> #include<unistd.h> int main() { int *p = sbrk(0); brk(p+1);/* 3 使用brk分配空间 */ *p = 1; printf("%d\n",*p); brk(p); /*4 使用brk释放空间 */ *p = 2; printf("%d\n",*p); return 0; }
静态编译test.c,生成test
gcc -o test test.c -static
返回到roofs目录下,重新打包镜像文件,启动qemu,可以看到test.c和test
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 -S -s
进行gdb调试
执行下面命令
qemu-system-x86_64 -kernel linux-5.4.34/arch/x86/boot/bzImage -initrd rootfs.cpio.gz -S -s -nographic -append "console=ttyS0"
打开一个新的中断,执行命令,打上断点,进行单步调试
cd linux-5.4.34 gdb vmlinux target remote:1234 b __x64_sys_brk
可以看到函数调用过程,__x64_sys_brk ---> do_syscall_64 --->entry_SYSCALL_64 --->syscall_return_via_sysret