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

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

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

1.实验目标

1.编译内核5.0
2.选择系统调用进行跟踪分析

2.实验环境

VMware Workstation Pro
Ubuntu 18.04 虚拟机

3.编译内核5.0

  1. 下载linux5.0
wget https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.0.tar.xz//使用wget命令下载linux5.0

在这里插入图片描述

  1. 解压并编译
xz -d linux-5.0.1.tar.xz
tar -xvf linux-5.0.1.tar
cd linux-5.0.1
make i386_defconfig

这里出现了问题
在这里插入图片描述
在这里插入图片描述
于是安装flex与bison

sudo apt-get install flex
sudo apt-get install bison

编译文件

make i386_defconfig
make 

出现的问题
在这里插入图片描述
这里好像是有一个libssl-dev没有安装
那么来安装

sudo apt-get install libssl-dev
  1. 制作根文件系统

sudo apt-get install gcc-multilib//这一步是必要的,不然会报错,需要安装gcc编译器

cd ..
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
  1. 编译
qemu -kernel linux-5.0/arch/x86/boot/bzImage -initrd rootfs.img -s -S -append nokaslr

在这里插入图片描述

  1. 进行内核跟踪调试,需要重新编译Linux内核
make menuconfig

在这里插入图片描述
这里如果窗口太小可能会报错

qemu -kernel linux-5.0/arch/x86/boot/bzImage -initrd rootfs.img -s -S -append nokaslr

跟踪调试内核启动
在这里插入图片描述
使用gdb打开调试工具

gdb 
(gdb)file linux-5.0/vmlinux 
(gdb)target remote:1234 

在这里插入图片描述

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

我的学号后三位是029 所以找第29位系统调用号进行使用
在这里插入图片描述
函数说明:pause()会令目前的进程暂停(进入睡眠状态),直至信号(signal)所中断。
返回值:只返回-1
于是修改test.c中的代码,添加一个调用pause的代码

#include <signal.h>
#include <unistd.h>



void sigl_name(int num)
{
    printf("receive the signal %d.\n", num);
    alarm(2);
}
 
int Pause_test(int argc, char *argv[])
{
    signal(SIGALRM, sigl_name);
 
    alarm(2);
 
    while(1){
        pause();
        printf("pause is over.\n");
    }
 
    return 0;
}
int main()
{
    PrintMenuOS();
    SetPrompt("MenuOS>>");
    MenuConfig("version","MenuOS V1.0(Based on Linux 3.18.6)",NULL);
    MenuConfig("quit","Quit from MenuOS",Quit);
    MenuConfig("time","Show System Time",Time);
    MenuConfig("time-asm","Show System Time(asm)",TimeAsm);
    MenuConfig("pause","Show pause",Pause_test);
    ExecuteMenu();
}

为了方便观看断点设置,循环了代码,当程序运行时,pause会使当前的进程进入睡眠状态,直到我们由定时器alarm向该 signal发送SIGALRM信号,进程才会被唤醒,并处理信号,处理完信号后pause函数才返回,并继续运行该程序,具体情况如下图所示:
用b sys_pause设置断点,c继续执行
在这里插入图片描述
使用n不断进行一步一步进行调试,发现在QEMU界面发生了输出,pause暂停了进程,然后由于alarm发送的发送的SIGALRM信号给signal让程序重新执行
在这里插入图片描述
有一步步执行下来可以看出具体流程sys_pause->schedule->sys_pause->do_fast_syscall_32
->entry_sysenter_32->entry_int80_32
再细看,分析sys_pause的具体运行,使用disass与info r
在这里插入图片描述
在这里插入图片描述
可以看出在每一次从用户态进入内核态,都会有上下文切换的问题,那么就要把用户态寄存器上下文保存起来,从运行结果disass显示出来的可以看出,再每次的进行中都会先进行压栈,再结束过程中再进行出栈,以此来保护原函数的运行现场,再最后寄存器集体出栈时恢复。也就是说保护现场就是进入中断服务程序之前,保存使用的寄存器值,也就是说进行压栈操作; 恢复现场就是进入中断服务程序后,恢复之前保存的寄存器数据,也就是进行出栈操作

系统调用分析:
系统中的调用,就是通过系统调用号来给这些system_call来编号,不同功能给予不同的功能号,如这次使用的就是29号 Pause功能,通过这样让系统明确知道用户想要执行的是哪个系统调用。而这之间的传递主要是通过eax寄存器来传递。
除了系统调用号外,系统调用也可能需要传递参数,系统调用由于是从用户态到内核态,两者的栈堆不一样,所以他们之间只能由寄存器来进行传递值,也就是ebx、ecx、edx、esi和edi寄存器中。

5.总结

系统调用主要就是一种用户态到内核态最后再到用户态的一种过程,用户态可以说成间接操作内存的程序,而内核态也就是通过汇编代码直接操作内存,而他们再转换过程中,由于涉及上下文的切换问题,所以需要对内容进行保护,所以再进入中断程序前,将内核态寄存器的值放入栈中,在程序结束后再进行出栈。
而且由于用户态与内核态的栈堆不同,所以他们之间只能使用寄存器来传递值,也就是eax,ebx、ecx、edx、esi和edi寄存器中,其中eax主要是存放系统调用号,以及调用的返回值,而其他的五个寄存器主要是存放系统调用的参数。
系统调用号是内核为每个系统调用分配的相当于id的事务,用户态进程必须明确的指定使用的系统调用号,来使内核确定使用的服务。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值