举例跟踪分析Linux内核5.0系统调用处理过程

学号最后三位:010
原创作品转载请注明出处 https://github.com/mengning/linuxkernel/

使用Ubuntu 16.04.6编译Linux内核5.0.1

首先下载Linux源码:

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

解压:

xz -d linux-5.0.1.tar.xz
tar -xvf linux-5.0.1.tar

安装内核编译⼯工具

sudo apt install build-essential flex bison libssl-dev libelf-dev libncurses-dev

切换目录并生成32位x86文件,make -j8即可多线程编译,加快编译速度

cd linux-5.0.1
make i386_defconfig
make -j8

可使用文本菜单进行选项设置

make menuconfig

在这里插入图片描述
选择Kernel hacking——>Compile-time checks and compiler options——>Compile the kernel with debug info
经过半个多小时,内核编译成功。

制作根文件系统

生成目录,从github下载源码,并进行32位编译,生成镜像

mkdir rootfs
git clone https://github.com/mengning/menu.git
cd menu
gcc -pthread -o init linktable.c menu.c test.c -m32 -static
cd ../rootfs
cp ../menu/init ./
find . | cpio -o -Hnewc |gzip -9 > ../rootfs.img

启动MenuOS

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

在这里插入图片描述

进行跟踪调试

qemu-system-i386 -kernel linux-5.0.1/arch/i386/boot/bzImage -initrd linux-5.0.1/rootfs.img -S -s -append nokaslr

新开一个shell终端进行gdb调试

cd /linux-5.0.1
gdb
(gdb)file vmlinux 
(gdb)target remote:1234 
(gdb)break start_kernel
  (gdb) c

在这里插入图片描述
调试端口号为1234,在start_kernel设置断点,使用n为单步调试,使用l可查看源代码,c为继续运行
在这里插入图片描述

选择系统调用进行跟踪分析

学号为10,查阅linux5.0.1/arch/x86/include/generated/uapi/asm/unistd_32.h文件可知,对应的系统调用为unlink
在这里插入图片描述
关于unlink函数的介绍:
头文件
#include<unistd.h>
函数原型
int unlink(const char *pathname);
函数介绍
unlink()函数功能即为删除文件。执行unlink()函数会删除所给参数指定的文件。
注意:执行unlink()函数并不一定会真正的删除文件,它先会检查文件系统中此文件的连接数是否为1,如果不是1说明此文件还有其他链接对象,因此只对此文件的连接数进行减1操作。若连接数为1,并且在此时没有任何进程打开该文件,此内容才会真正地被删除掉。在有进程打开此文件的情况下,则暂时不会删除,直到所有打开该文件的进程都结束时文件就会被删除。

在MenuOS中添加系统调用函数

在menu/test.c中添加Unlink函数与UnlinkAsm函数,并在main函数中添加menu选项
在这里插入图片描述
在这里插入图片描述
修改保存后,再次编译MenuOS并添加调试

qemu-system-i386 -kernel linux-5.0.1/arch/i386/boot/bzImage -initrd linux-5.0.1/rootfs.img -S -s -append nokaslr

在这里插入图片描述
break sys_unlink设置断点在unlink系统调用处,Unlink以及UnlinkAsm运行图
在这里插入图片描述

总结

Linux中处理系统调用的方式与中断类似。每个系统调用都有相应的系统调用号作为唯一的标识,内核维护一张系统调用表,表中的元素是系统调用函数的起始地址,而系统调用号就是系统调用在调用表的偏移量。在进行系统调用是只要指定对应的系统调用号,就可以明确的要调用哪个系统调用,这就完成了系统调用的函数名称的转换。
Linux中是通过寄存器%eax传递系统调用号,所以首先将系统调用号0x0a存入%eax中。
系统调用的参数传递是通过寄存器完成的,Linux最多允许向系统调用传递6个参数,分别依次由%ebx,%ecx,%edx,%esi,%edi和%ebp这个6个寄存器完成。
本例中删除文件名参数test1.txt传递给%ebx。
然后使用int 0x80触发中断,中断处理程序保存现场,用户进程陷入内核态,即可调用相应的系统调用。当从用户栈切换到内核栈时,将保存%esp以及相关寄存器的值(%ebx,%ecx…),并将%esp设置成内核栈的相应值。处于内核态时,首先执行system_call函数,接着根据eax中的值在系统调用表中找到对应的系统调用服务例程sys_unlink(),执行该例程。而从内核栈切换会用户栈时,需要恢复用户栈的%esp及相关寄存器的值以及保存内核栈的信息。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值