林弋力
224
原创作品转载请注明出处 + https://github.com/mengning/linuxkernel/
实验目的
选择系统调用进行分析
理解系统调用工作机制
实验步骤
下载并编译内核
wget 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
git clone https://github.com/mengning/menu.git
安装编译工具
sudo apt install build-essential flex bison libssl-dev libelf-dev libncurses-dev
配置内核
cd linux-5.0.2
make i386_defconfig
make menuconfig
make -j 8
cd ../menu
进入Menu目录,修改Makefile文件
将内核版本改为对应的版本
编译make rootfs 生成一个镜像文件 rootfs.img
启动该镜像
qemu-system-i386 -kernel arch/x86/boot/bzImage -initrd rootfs.img
跟踪系统调用分析
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
(gdb)vmlinux
(gdb) target remote:1234
跟踪分析的系统调用为24:getuid
跟踪测试函数
//getuid.c
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
int main(int argc, char const *agrv[])
{
uid_t uid;
uid=getuid();
printf("The current user ID:%d\n",uid);
return 0;
}
测试结果:
使用嵌入汇编的方式把系统调用展示如图:
可以看出,系统调用执行了内核的封装例程。
用户进程只需要把相应的调用号放入eax寄存器,内核就在内核态完成相应的计算,把用户所要求的结果返给用户进程,参与其他运算。
实验总结
当调用一个系统调用时,CPU从用户态切换到内核态并执行一个system_call和系统调用内核函数。在Linux中通过执行int 0x80来触发系统调用,内核为每个系统调用分配一个系统调用号,用户态进程必须明确指明系统调用号,并使用EAX寄存器来传递。
系统调用可能需要参数,但是不能通过像用户态进程函数中将参数压栈的方式传递,因为用户态和内核态有不同的堆栈,必须使用寄存器EBX、ECX、EDX、ESI、EDI、EBP来传递参数。若参数较多,则把指向内存的指针存入寄存器。