深入理解Linux系统调用

一、实验内容

1.学号末尾为14,故采用14号系统调用

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

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

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

二、环境准备

安装开发工具

sudo apt install build-essential
sudo apt install qemu # install QEMU 
sudo apt install libncurses5-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 
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) # nproc gives the number of CPU cores/threads available
# 测试⼀下内核能不能正常加载运⾏,因为没有⽂件系统终会kernel panic 
qemu-system-x86_64 -kernel arch/x86/boot/bzImage  #  此时应该不能正常运行

制作根文件系统

#下载
axel -n 20 https://busybox.net/downloads/busybox-1.31.1.tar.bz2
tar -jxvf busybox-1.31.1.tar.bz2
cd busybox-1.31.1

#制作根文件系统
make menuconfig 
#记得要编译成静态链接,不⽤动态链接库。
Settings  --->
    [*] Build static binary (no shared libs) 
#然后编译安装,默认会安装到源码⽬录下的 _install ⽬录中。 
make -j$(nproc) && make install

制作内存根文件系统镜像

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/

准备init脚本文件放在根文件系统跟目录下(rootfs/init),添加如下内容到init文件。

#!/bin/sh
 mount -t proc none /proc 
 mount -t sysfs none /sys
 echo "Welcome to SSE_314 OS!"
 echo "--------------------" 
 cd home
 /bin/sh 

给init脚本添加可执⾏权限

chmod +x init
#打包成内存根⽂件系统镜像 
find . -print0 | cpio --null -ov --format=newc | gzip -9 > ../rootfs.cpio.gz 
#测试挂载根⽂件系统,看内核启动完成后是否执⾏init脚本 
qemu-system-x86_64 -kernel linux-5.4.34/arch/x86/boot/bzImage -initrd rootfs.cpio.gz

 

三、查看系统调用表和汇编改写

打开  linux-5.4.34/arch/x86/entry/syscalls/syscall_64.tbl,查看要选择进行实验的系统调用。

找到进行实验的系统调用--14号系统调用

14号系统调用为 rt_sigprocmask。对应的内核处理函数为 __x64_sys_rt_sigprocmask。作用:设定对信号屏蔽集内的信号的处理方式(阻塞或不阻塞)。使用内联汇编小程序new_test.c如下:

int main()
{
    asm volatile(
    "movl $0x0E,%eax
	" //使⽤EAX传递系统调⽤号14
    "syscall
	" //触发系统调⽤ 
    );
    return 0;
}

由于我们搭建的系统不支持动态链接,因此这里我们在使用gcc编译时要用-static静态编译参数):gcc -o test test.c -static

然后将生成的可执行文件文件拷贝至rootfs/home文件夹下

由于我们对系统做了修改,需要重新打包成内存根文件系统镜像。因此要再次使用命令:

find . -print0 | cpio --null -ov --format=newc | gzip -9 > ../rootfs.cpio.gz

打包完毕后,我们的构建系统的根目录下应该已经有test这一可执行文件了,用qemu运行,检查一下。如下图所示: 

接下来我们首先需要检查是否成功触发了14号系统调用,然后逐步跟踪了解内核的处理过程、系统调用入口的保存现场、恢复现场和系统调用返回等流程

四、gdb调试

纯命令行下启动虚拟机

qemu-system-x86_64 -kernel linux-5.4.34/arch/x86/boot/bzImage -initrd rootfs.cpio.gz -S -s -nographic -append "console=ttyS0"

此时虚拟机会停在启动界面,如图

在另一个terminal中开启gdb调试

gdb捕获到了断点 : __x64_sys_rt_sigprocmask 函数,14号系统调用触发成功。如下图

gdb输入命令c,使得虚拟机继续执行,到初始界面

在虚拟机中执行 ./test 会卡住,在gdb界面查看断点分析,

使用 l 命令查看代码情况, n 命令单步执行, step 命令进入函数内部 bt查看堆栈

 

 查看此时堆栈情况,有4层

第一层   __x64_sys_rt_sigprocmask 系统调用函数所在

第二层  do_syscall_64  获取系统调用号, 前往系统调用函数

第三层  entry_SYSCALL_64 ()  中断入口,做保存线程工作,调用 do_syscall_64 

 

gdb单步调试过程

执行完这个函数,发现回到了函数堆栈上一层的 do_syscall_64中 接下来要执行的 syscall_return_slowpath(regs) 函数要为恢复现场做准备。

 

继续执行,发现再次回到了函数堆栈的上一层  entry_SYSCALL_64 ()   接下来执行的是用于恢复现场的汇编指令

 

最后伴随着两个 pop 指令 恢复了 rdi 和 rsp 寄存器。系统调用完成。

五、总结

整理一下整个系统调用的过程:

1.汇编指令syscall 触发系统调用,通过MSR寄存器找到了中断函数入口,此时,代码执行到 

/home/sy/linux_lesson/linux-5.4.34/arch/x86/entry/entry_64.S 目录下的 ENTRY(entry_SYSCALL_64) 入口  后开始通过  swapgs 和 压栈动作 保存现场

ENTRY(entry_SYSCALL_64) 是X64系统调用入口

swapgs 是快照保存

call    do_syscall_64           /* returns with IRQs disabled */  是中断向量表查找系统调用号

2.然后跳转到了 home/sy/linux_lesson/linux-5.4.34/arch/x86/entry/common.c 中的 do_syscall_64 函数  在ax寄存器中获取到系统调用号,然后去执行系统调用内容

regs->ax = x32_sys_call_table[nr](regs) ;// 从sys_call_table 获得系统调用号

3.然后程序跳转到 linux-5.4.34/rootfs/home/test.c函数 ,开始执行

4.函数执行完后回到步骤3中的 syscall_return_slowpath(regs)  准备进行现场恢复操作,

5.接着程序再次回到 arch/x86/entry/entry_64.S  执行现场的恢复,最后两句,完成了堆栈的切换

popq    %rdi
popq    %rsp
原文地址:https://www.cnblogs.com/ustc314/p/12962042.html