学号198,原创作品转载请注明出处
本实验来源 https://github.com/mengning/linuxkernel/
实验环境
Ubuntu 18.04 虚拟机
VMware Workstation Pro 15.0.2 for Windows
实验要求
举例跟踪分析Linux内核5.0系统调用处理过程
编译内核5.0
qemu -kernel linux-5.0.1/arch/x86/boot/bzImage -initrd rootfs.img
选择系统调用号后两位与您的学号后两位相同的系统调用进行跟踪分析
https://github.com/mengning/menu
给出相关关键源代码及实验截图,撰写一篇博客(署真实姓名或学号最后3位编号),并在博客文章中注明“原创作品转载请注明出处 + https://github.com/mengning/linuxkernel/ ”,博客内容的具体要求如下:
题目自拟,内容围绕系统调用进行;
博客中需要使用实验截图
博客内容中需要仔细分析系统调用、保护现场与恢复现场、系统调用号及参数传递过程
总结部分需要阐明自己对系统调用工作机制的理解。
实验步骤:
编译内核5.0
- 下载linux5.0
wget https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.0.tar.xz//使用wget命令下载linux5.0
下载完成后解压切换到解压后文件夹
安装flex与bison
sudo apt-get install flex
sudo apt-get install bison
编译文件
make i386_defconfig
make
制作根文件系统
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
编译
qemu -kernel linux-5.0/arch/x86/boot/bzImage -initrd rootfs.img -s -S -append nokaslr
进行内核跟踪调试,需要重新编译Linux内核
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
选择系统调用进行跟踪分析
找到我的学号对应的调用号98.
#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即可使程序继续执行:
在每一次从用户态进入内核态的过程中,都会有上下文切换的过程存在,而每次切换的过程都需要先把用户态寄存器上下文保存起来,每次的进行中需要保存上下文时都会先进行压栈,再结束过程中需要恢复上下文时再进行出栈,以此来保护原函数的运行现场,再最后寄存器集体出栈时恢复。 恢复现场就是进入中断服务程序后,恢复之前保存的寄存器数据。
系统调用通过系统调用号来给这些system_call来编号,不同功能给予不同的功能号,通过这样一种方式让系统明确知道用户想要执行的是哪个系统调用。而用户态和内核态,两者的栈堆不一样,他们之间通过寄存器来进行传递值,也就是ebx、ecx、edx、esi和edi寄存器中。
实验总结
系统调用是一个用户态->内核态->用户态进行切换的一个过程
系统中断的调用有三层分别是API、system_call、system_service。
系统调用是Linux内核中设置的一组用于实现各种系统功能的子程序。系统调用和普通的函数调用区别在于,系统调用由操作系统核心提供,运行于核心态;而普通的函数调用由函数库或用户自己提供,运行于用户态。系统调用号是内核为每个系统调用分配标识,用户态进程必须明确的指定使用的系统调用号,来使内核确定使用的服务。