一。配置内核选项

 

 

 

 

测试挂载根⽂件系统,看内核启动完成后是否执⾏init脚本

 

 

二、查找系统调用号

我的学号后两位为57,所以查表为fork

 

 

 

 在rootfs/home目录下创建test.c文件

 

gcc -o test test.c -static和objdump -S test > test.S命令

 

反汇编代码中main如下:

 

将系统调用号57存入eax寄存器

 文件系统改变再次编译

find . -print0|cpio --null -ov --format=newc|gzip -9>../rootfs.cpio.gz

qemu-system-x86_64 -kernel arch/x86/boot/bzImage -initrd rootfs.cpio.gz -S -s

再次打开窗口终端启动gdb

进行连接:(gdb) target remote:1234

打上断点:(gdb)b  __x64_sys_fork

 

 

 三、重点阅读分析系统调用入口的保存现场、恢复现场和系统调用返回,以及重点关注系统调用过程中内核堆栈状态的变化

系统调⽤实质上是⼀种特殊的中断,int $0x80指令触发系统调⽤会在内核堆栈上保存⼀些寄存器的值,会保存系统调⽤发⽣时当前执⾏程序的栈顶地址(SS:ESP)、当时的状态字(EFlags)、当时 的 CS:EIP的值。同时会将当前进程内核堆栈的栈顶地址、内核的状态字等放⼊ CPU 对应的寄存 器,并且 CS:EIP 寄存器的值会指向中断处理程序的⼊⼝,对于系统调⽤来讲是指向系统调⽤处理 的⼊⼝。

更⼀般地来看,中断发⽣时CPU第⼀时间就是保存当前CPU执⾏的关键上下⽂(栈顶指针寄存器、 标志寄存器、指令指针寄存器等),然后保存现场就是把其他寄存器的值也保存起来,当中断处理 程序结束时恢复现场并中断返回,也就是负责把中断时保存的“现场”恢复到当前的 CPU ⾥⾯。

最后的 iret 与中断信号(包括 int 指令)发⽣时的 CPU 做的动作正好相反,之前是保存,这⾥就是 恢复。