学号239
原创作品,转载请注明出处。
本实验资源来源: https://github.com/mengning/linuxkernel/
一、 实验环境
Ubuntu 18
VMware workstation
实验要求:https://github.com/mengning/linuxkernel/blob/master/2019.md
二、linux5.0内核编译
1.下载linux5.0内核并解压
mkdir linuxkernel
cd linuxkernel
wget https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.0.2tar.xz
xz -d linux-5.0.2.tar.xz
tar -xvf linux-5.0.2.tar
2.配置并编译Linux内核
cd linux-5.0.2
make i386_defconfig #这步很重要
make menuconfig
此时出现问题
安装
sudo apt-get install ncurses-dev
之后再出现问题
安装
sudo apt-get install flex
出现问题
安装
sudo apt-get install bison
之后make menuconfig,找到kernel hacking,->Compile-time checks and compiler options,选择 [*]compile the kernel with debug info
然后make -j8,缺什么装什么
3.制作根文件系统
cd ~/Documents/linux-5.0.2
mkdir rootfs
git clone https://github.com/mengning/menu.git
cd menu
gcc -o init linktable.c menu.c test.c -m32 -static –lpthread
cd ../rootfs
cp ../menu/init ./
find . | cpio -o -Hnewc |gzip -9 > ../rootfs.img
启动Menu os
cd ~/Documents/linux-5.0.2
qemu-system-i386 -kernel arch/x86/boot/bzImage -initrd rootfs.img
4.跟踪调试内核启动
qemu-system-i386 -kernel linux-5.0.2/arch/x86/boot/bzImage -initrd rootfs.img -S -s -append nokaslr
打开一个新的终端输入
cd linuxkernel/linux-5.0.2
gdb vmlinux
(gdb) target remote:1234
可以看到内核被成功启动
三、跟踪系统调用
1.增加系统调用
学号后两位39,在/usr/include/asm/unistd_32.h中可查得#define __NR_mkdir 39,mkdir系统调用作用是新建一个目录
函数原型:
#include <sys/stat.h>
int mkdir(const char *pathname, mode_t mode);
mkdir()函数以mode方式创建一个以参数pathname命名的目录,mode定义新创建目录的权限。
更改menu-master/main.c代码:
int _mkdir(int argc, char *argv[])
{
int returnValue = 0;
char *dirName = "new dirAsm";
mode_t mode = S_IRWXU;
asm
(
"movl $39, %%eax\r\n" /*将39号系统调用号放到eax寄存器中*/
"movl %1, %%ebx\r\n"/*将第一个参数文件名的地址,存入ebx寄存器*/
"movl %2, %%ecx\r\n"/*将第二个参数文件夹的访问权限存入ecx寄存器*/
"int $0x80\r\n"
"movl %%eax, %0"/*最后将返回值放入returnValue变量中*/
:"=m"(returnValue)
:"d"(dirName),"D"(mode)/*使用edx寄存器保存dirName的地址,edi保存mode*/
);
printf("%d\n",returnValue);
return 0;
}
int main()
{
...
...
MenuConfig("mkdir","creat new catalogue",_mkdir);
}
重新编译制作rootfs.img,并启动
qemu -kernel linux-5.0.2/arch/x86/boot/bzImage -initrd rootfs.img -s -S -append nokaslr
可以看到创建了一个新目录new dirAsm
2.跟踪系统调用
qemu-system-i386 -kernel linux-5.0.2/arch/x86/boot/bzImage -initrd rootfs.img -S -s -append nokaslr
打开一个新的终端输入
cd linuxkernel/linux-5.0.2
gdb vmlinux
(gdb) target remote:1234
(gdb)b sys_mkdir
(gdb)c
可以看出,当调用一个系统调用时,CPU从用户态切换到内核态并开始执行一个system_call和系统调用内核函数。在Linux中通过执行int 0x80来触发系统调用,内核为每个系统调用分配一个系统调用号,用户态进程必须明确指明系统调用号,需要使用EAX寄存器来传递。
mkdir系统调用的流程是:
(1) 首先用户调用mkdir API
(2) 在API的具体实现里面会调用39号系统调用,使用int $80软中断进入内核态
(3) 此时会压入用户的栈顶地址,当前状态字,和CS:EIP。
(4) 然后使用SAVE ALL保存现场,内核进程根据用户的系统调用号,查找系统调用表(sys_call_table),找到中断处理子程序的地址,并且进入内核函数
(5) 完成调用中断处理子程序后,使用RESTORE ALL还原现场,返回调用的用户态空间
四、总结
1.系统调用是一个用户态到内核态再到用户态的过程
2. Linux内核中设置了一组用于实现各种系统功能的子程序,称为系统调用。用户可以通过系统调用命令在自己的应用程序中调用它们。从某种角度来看,系统调用和普通的函数调用非常相似。区别仅仅在于,系统调用由操作系统核心提供,运行于核心态;而普通的函数调用由函数库或用户自己提供,运行于用户态。