LinuxLab2---深入理解Linux系统调用

Posted USTC老虞

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LinuxLab2---深入理解Linux系统调用相关的知识,希望对你有一定的参考价值。

一、实验要求

1.学号末尾为59,故采用59号系统调用execve。

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

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

4.重点阅读分析系统调用入口的保存现场和恢复现场

 

二、环境准备

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
4 sudo apt install axel

2. 下载linux5.4.34源码

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

3. 配置内核编译选项

 1 make defconfig #Default configuration is based on \'x86_64_defconfig\' 
 2 make menuconfig
 3 #打开debug相关选项
 4 Kernel hacking --->
 5     Compile-time checks and compiler options --->
 6         [*] Compile the kernel with debug info
 7         [*] Provide GDB scripts for kernel debugging [*] Kernel debugging
 8 #关闭KASLR,否则会导致打断点失败
 9 Processor type and features ---->
10     [] Randomize the address of the kernel image (KASLR)

4. 编译内核

1 make -j$(nproc)
2 # 测试一下内核能不能正常加载运行,因为没有文件系统最终会kernel panic
3 qemu-system-x86_64 -kernel arch/x86/boot/bzImage

5. 制作根文件系统

下载

1 axel -n 20 https://busybox.net/downloads/busybox-1.31.1.tar.bz2
2 tar -jxvf busybox-1.31.1.tar.bz2
3 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

6. 制作内存根文件系统镜像

1 mkdir rootfs
2 cd rootfs
3 cp ../busybox-1.31.1/_install/* ./ -rf
4 mkdir dev proc sys home
5 sudo cp -a /dev/{null,console,tty,tty1,tty2,tty3,tty4} dev/

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

1 #!/bin/sh
2 mount -t proc none /proc mount -t sysfs none /sys
3 echo "Wellcome MengningOS!" echo "--------------------"
4 cd home
5 /bin/sh
给init脚本添加可执行权限
1 chmod +x init
打包成内存根文件系统镜像
1 find . -print0 | cpio --null -ov --format=newc | gzip -9 > ../rootfs.cpio.gz
测试挂载根文件系统,看内核启动完成后是否执行init脚本
1 qemu-system-x86_64 -kernel linux-5.4.34/arch/x86/boot/bzImage -initrd rootfs.cpio.gz

 

 

 

三、查看系统调用并编写调用汇编代码

1. 打开/linux-5.4.34/arch/x86/entry/syscalls/syscall_64.tbl

 

 

 

2. 编写普通汇编调用代码

在rootfs/home目录下编写代码

因为execve需要调用其他的程序,因此编写了一个Helloworld程序供调用。

hello.c

1 #include<stdio.h>
2 
3 int main() {
4     printf("Hello World\\n");
5 }

execve.c (execve正常运行无返回值)

 1 #include <stdio.h>
 2 #include <unistd.h>
 3 int main()
 4 {
 5     char *data[2];
 6     data[0] = "./hello";
 7     data[1] = NULL;
 8     char * const* null = NULL;
 9     int res;
10     //execve(data[0], data, null);
11     asm volatile(
12         "movq %3, %%rdx\\n\\t"  // 参数3
13         "movq %2, %%rsi\\n\\t"   //  参数2
14         "movq %1, %%rdi\\n\\t"  //  参数1 
15         "movl $0x3B,%%eax\\n\\t" //  传递系统调用号
16         "syscall\\n\\t"          //  系统调用
17         "movq %%rax,%0\\n\\t"    //  结果存到%0 就是str_len中
18         :"=m"(res) // 输出
19         :"a"(data[0]),"b"(data),"c"(null)
20 
21     );
22     //printf("%d", res);
23 }

gcc编译(这里需要静态编译)

gcc hello.c -o hello -static
gcc execve.c -o execve -static

 

 

3. 重新制作根文件系统

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

 

四、gdb调试

1. 纯命令行启动qemu

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

此时停留在以下界面

 

 

 2. 打开另一个终端

在linux源码目录下运行

1 gdb vmlinux

 

 

 

在gdb中运行

1 target remote:1234

 

 

 给对应的系统调用打上断点

 

 

 

输入c(continue)继续运行,因为系统启动过程中也会多次调用execve,因此需要多次输入c

 

 

 运行编写好的调用系统调用的代码

 

 

 gdb单步调试

 

 五、 结果分析

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

 

 

 

 2. 跳转获得系统调用号,执行系统调用的内容

 

 3. 后续关键调用

 

 

 

 

 

 

4. 调用结束,恢复到用户态执行syscall_return_slowpath 函数要为恢复现场做准备。

 

 

 

 

 

 

以上是关于LinuxLab2---深入理解Linux系统调用的主要内容,如果未能解决你的问题,请参考以下文章

深入理解Linux系统调用

深入理解Linux系统调用

深入理解系统调用

深入理解系统调用

深入理解系统调用

深入理解系统调用