深入理解Linux系统调用

时间:2020-05-26
本文章向大家介绍深入理解Linux系统调用,主要包括深入理解Linux系统调用使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

一、实验环境配置

系统环境:Ubuntu16.04

实验说明:本人学号末两位70,对应__64x_sys_msgrcv系统调用

注:不能在上次实验的基础上做,要重新下载解压linux-5.4.34文件

1、安装开发工具

1 sudo apt install build-essential 
2 sudo apt install qemu # install QEMU 
3 sudo apt install libncurses5-dev bison flex libssl-dev libelf-dev

2、下载内核源码

1 sudo apt install axel 
2 axel -n 20 https://mirrors.edge.kernel.org/pub/linux/kernel/v5.x/
3 linux-5.4.34.tar.xz 
4 xz -d linux-5.4.34.tar.xz 
5 tar -xvf linux-5.4.34.tar 
6 cd linux-5.4.34

3、配置内核选项

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)

4、编译和运行内核

1 make -j$(nproc) # nproc gives the number of CPU cores/threads 
2 available 
3 # 测试⼀下内核能不能正常加载运⾏,因为没有⽂件系统最终会kernel panic 
4 qemu-system-x86_64 -kernel arch/x86/boot/bzImage

5、制作根文件系统

1 ⾸先从https://www.busybox.net下载 busybox源代码解压,解压完成后,跟内核⼀样先配置编译,并安装。
2 axel -n 20 https://busybox.net/downloads/busybox-1.31.1.tar.bz2 
3 tar -jxvf busybox-1.31.1.tar.bz2 
4 cd busybox-1.31.1
1 make menuconfig 
2 记得要编译成静态链接,不⽤动态链接库。
3 Settings ---> 
4     [*] Build static binary (no shared libs) 
5 然后编译安装,默认会安装到源码⽬录下的 _install ⽬录中。
6 make -j$(nproc) && make install
1 然后制作内存根⽂件系统镜像,⼤致过程如下:
2 mkdir rootfs 
3 cd rootfs 
4 cp ../busybox-1.31.1/_install/* ./ -rf
5 mkdir dev proc sys home 
6 sudo cp -a /dev/{null,console,tty,tty1,tty2,tty3,tty4} dev/
 1 准备init脚本⽂件放在根⽂件系统跟⽬录下(rootfs/init),添加如下内容到init⽂件。
 2 #!/bin/sh 
 3 mount -t proc none /proc 
 4 mount -t sysfs none /sys 
 5 echo "Wellcome MengningOS!" 
 6 echo "--------------------" 
 7 cd home 
 8 /bin/sh 
 9 给init脚本添加可执⾏权限
10 chmod +x init
1 打包成内存根⽂件系统镜像(rootfs目录下)
2 find . -print0 | cpio --null -ov --format=newc | gzip -9 > ../rootfs.cpio.gz 
3 测试挂载根⽂件系统,看内核启动完成后是否执⾏init脚本
4 qemu-system-x86_64 -kernel linux-5.4.34/arch/x86/boot/bzImage -initrd rootfs.cpio.gz

可以看到init脚本已被执行

二、使用gdb跟踪调试

1、gdb问题处理

在用gdb打断点的时候,出现Remote ‘g’ packet reply is too long错误,查询得到参考解决办法https://blog.csdn.net/superking3188/article/details/8477574

改完代码后进行重新编译和安装

./configure
make
make install

2、验证内核初始化

启动虚拟机
qemu-system-x86_64 -kernel linux-5.4.34/arch/x86/boot/bzImage -initrd rootfs.cpio.gz -S -s
在linux-5.4.34目录下启动gdb
gdb vmlinux
target remote:1234

在start_kernel、trap_init、cou_init、syscall_init位置打上断点

依次执行,可以清晰的看出系统内核初始化的顺序为start_kernel->trap_init->cou_init->syscall_init

3、跟踪70号系统调用

在linux-5.4.34/arch/x86/entry/syscalls/syscall_64.tbl文件中可以查看70对应的系统调用为__64x_sys_msgrcv

 为了观察该系统调用,在rootfs/home目录下写一个程序来触发系统调用

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

对该程序进行静态编译

gcc testSys.c -o testSys -static

重新打包内存跟文件系统镜像

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

在linux-5.4.34目录下启动gdb调试

gdb vmlinux
target remote:1234
b __64x_sys_msgrcv
c

此时可以看到home目录下已经存在我们刚刚生成的可执行文件,执行该文件即可触发70号系统调用

获取到了70号系统调用的返回信息

使用bt命令查看栈信息

 可以看到该系统调用涉及到do_syscall_64和entry_SYSCALL_64两个内核函数。

三、系统调用的保存和恢复现场

系统调用入口为entry_SYSCALL_64,其中使用了swapgs这一方法来快照式的保存现场,加快了系统调用,随后对一些相关寄存器进行压栈操作。

随后执行了do_syscall_64函数

在do_syscall_64函数中,获取到系统调用号所对应的入口,跳转执行。

随后便执行相关的系统调用

调用结束后恢复现场

 四、总结

本次实验中,学习了gdb工具,使用gdb断点调试完成了内核初始化顺序的验证;查看了70号系统调用的调用过程,详细了解了系统调用的保存和恢复现场。

原文地址:https://www.cnblogs.com/awesomeluxu/p/12965167.html