跟踪分析Linux5.0系统调用过程

学号210 原创作品转载请注明出处 + https://github.com/mengning/linuxkernel/

一.实验要求

二.实验环境

Ubuntu18

gcc 7

三.编译环境

1.mkdir LinuxKernel

2.下载内核源码Linux5.0source code

Wget https:mirrors.edge.kernel.org/pub/linux/kernel/v5.x/linux-5.0.1.tar.xz

3.xz -d linux-5.0.1.tar.xz

4.tar -xvf linux-5.0.1.tar

5.cd LinuxKernel

 cd linux-5.0.1

6.Make i386_defconfig

实验中所遇到的问题:

主要是缺什么,就补什么。

Sudo apt install gcc

Sudo apt install bison

Sudo apt install flex

sudo apt install libssl-dev

7.make i386_defconfig //32位的qemu,因此kernel需要同为32位的;

8.make menuconfig //然后kernel hacking,->Compile-time checks and compiler options,选择 [*]compile the kernel with debug info。效果如下图:

9.make

 

制作根文件系统

在linux5.0.1的文件下:

1.cd ~/LinuxKernel/

2.mkdir rootfs

3.git clone https://github.com/mengning/menu.git

4.cd menu

5.gcc -pthread -o init linktable.c menu.c test.c -m32 -static

遇到问题:

解决方法:

sudo apt-get install gcc-multilib

gcc -pthread -o init linktable.c menu.c test.c -m32 -static

cd ../rootfs

find . | cpio -o -Hnewc |gzip -9 > ../rootfs.img

 启动MenuOS

qemu-system-i386 -kernel linux-5.0.1/arch/x86/boot/bzImage -initrd rootfs.img

四.跟踪调试内核启动

1.cd LinuxKernel/linux-5.0.1

(gdb) file vmlinux

(gdb)target remote:1234

(gdb)break start_kernel

(gdb)c

(gdb)l

2.

3.

内核编译成功。

五.选择系统调用后两位与学号后两位进行跟踪编译

1.学号后两位10 对应的系统调用为unlink

功能描述:

从文件系统中删除一个名称。如果名称是文件的最后一个连接,并且没有其它进程将文件打开,名称对应的文件会实际被删除。

用法:int unlink(const char *pathname);

参数:pathname:指向需解除连接的文件名。

2.编写210.c文件,调用系统函数

编译文件,输入命令gcc -g 210.c -o 210 -m32

每一个文件,都可以通过一个struct stat的结构体来获得文件信息,其中一个成员st_nlink代表文件的链接数。通常open一个已存在的文件不会影响文件的链接数。open的作用只是使调用进程与文件之间建立一种访问关系,link函数创建一个新目录项,并且增加一个链接数。unlink函数删除目录项,并且减少一个链接数。如果链接数达到0并且没有任何进程打开该文件,该文件内容才被真正删除。如果在unlilnk之前没有close,那么依旧可以访问文件内容。
  综上所诉,真正影响链接数的操作是link、unlink以及open的创建。

跟踪调试

gbq -q

file 210

b unlink(设置断点)

r

ni

info r(查看寄存器的值)

ni

info r

 

应用程序 ( application program )与 库函数 ( libc )之间, 系统调用处理函数 ( system call handler )与 系统调用服务例程 ( system call service routine )之间, 均是普通函数调用,应该不难理解。 而 库函数 与 系统调用处理函数 之间,由于涉及用户态与内核态的切换,要复杂一些。

Linux 通过 软中断 实现从 用户态 到 内核态 的切换。 用户态 与 内核态 是独立的执行流,因此在切换时,需要准备 执行栈 并保存 寄存器 。

内核实现了很多不同的系统调用(提供不同功能),而 系统调用处理函数 只有一个。 因此,用户进程必须传递一个参数用于区分,这便是 系统调用号 ( system call number )。 在 Linux 中, 系统调用号 一般通过 eax 寄存器 来传递。

总结起来, 执行态切换 过程如下:

  1. 应用程序 在 用户态 准备好调用参数,执行 int 指令触发 软中断 ,中断号为 0x80 ;
  2. CPU 被软中断打断后,执行对应的 中断处理函数 ,这时便已进入 内核态 ;
  3. 系统调用处理函数 准备 内核执行栈 ,并保存所有 寄存器 (一般用汇编语言实现);
  4. 系统调用处理函数 根据 系统调用号 调用对应的 C 函数—— 系统调用服务例程 ;
  5. 系统调用处理函数 准备 返回值 并从 内核栈 中恢复 寄存器 ;
  6. 系统调用处理函数 执行 ret 指令切换回 用户态 ;

 

 

posted @ 2019-03-19 23:42  深于黑  阅读(191)  评论(0编辑  收藏  举报