深入理解系统调用

一.实验要求:

1.找一个系统调用,系统调用号为学号最后2位相同的系统调用

2.通过汇编指令触发该系统调用

3.通过gdb跟踪该系统调用的内核处理过程

4.重点阅读分析系统调用入口的保存现场、恢复现场和系统调用返回,以及重点关注系统调用过程中内核堆栈状态的变化

二.配置实验环境:

1,下载工具、Linux内核源码

sudo apt install build-essential libncurses-dev bison flex libssl-dev libelf-dev
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

2.配置内核编译选项

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)

 3.编译运行内核

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错误,因为没有文件系统。

4.制作内存根文件系统

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>

将init脚本放入该目录下,然后执行:

 a打包成内存根文件系统镜像

b测试挂载根文件系统,看内核启动完成后是否执行init脚本!

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

 看到Wellcome os!说明成功执行了init脚本

三.用汇编代码编写系统调用程序

1.学号后两位为44,查看syscall_64.tbl对应系统调用为sendto,如下图所示;

 sendto系统调用用于向指定的目的地址发送数据

2.这里写一个test_sendto.c文件,调用44号系统调用:

#include<stdio.h>
int main()
{
    asm volatile(
    "movl $0x2c,%eax
	" //使⽤EAX传递系统调⽤号44
    "syscall
	" //触发系统调⽤ 
    );
    printf("sendto
");
    return 0;
}

3.用gcc静态编译,生成可执行文件

gcc -o test_sendto test_sendto.c -static

4.将文件放至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

四.gdb调试

1.启动qemu

qemu-system-x86_64 -kernel linux-5.4.34/arch/x86/boot/bzImage -initrd rootfs.cpio.gz -s -S

2.新打开一个终端命令分别执行如下步骤

cd linux-5.4.34/ # 切到对应的文件夹
gdb vmlinux
(gdb) target remote:1234

3.根据前面提到的,44号系统调用的内核处理函数为__x64_sys_sendto,因此我们给它打上断点: b __x64_sys_sendto,如下图

4.保存现场:

可以看到保存现场使用了特殊的swapgs,加快了系统调用的速度,swapgs之后push了一堆寄存器,将其入内核堆栈,然后转换成pt_regs结构体

5.现场恢复

 执行了一个宏USERGS_SYSRET64, 在linux5.4.34/arch/x86/include/asm/irqflags.h中有他的如下定义

swapgs——恢复现场和sysretq——系统调用返回。

 五.总结

应用程序调用API,然后trap陷入,进入系统调用,进入内核态,保存现场执行中断处理程序 然后恢复现场返回用户态。其中保存现场和恢复现场都是通过操作内核的堆栈实现的

原文地址:https://www.cnblogs.com/wwwxuexi/p/12977234.html