学号274
原创作品转载请注明出处 + https://github.com/mengning/linuxkernel/
一、编译Linux内核5.0.1
1.下载内核源码并解压
xz -d linux-5.0.1.tar.xz
tar -xvf linux-5.0.1.tar
2.编译
make i386_defconfig
make -j8
可能会出现缺少相关依赖的问题,使用
sudo apt-get install (缺少的依赖)
安装即可
3.制作根文件系统
先安装相关工具
sudo apt install gcc-4.8 gcc-4.8-multilib g++-4.8 g++-4.8-multilib
按如下步骤制作根文件系统
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
4.启动内核
qemu -kernel linux-5.0.1/arch/x86/boot/bzImage -initrd rootfs.img
5.进行内核跟踪调试
qemu-system-i386 -kernel linux-5.0.1/arch/x86/boot/bzImage -initrd rootfs.img -S -s -append nokaslr
在终端中输入:
gdb
(gdb)file linux-5.0.1/vmlinux
(gdb)target remote:1234
二、跟踪系统调用
选取74号系统调用进行跟踪分析
int sethostname(const char* name, size_t len)
参数name是要设置的主机名;len是name的长度;调用后返回0表示成功,返回-1表示失败。
修改test.c,增加SetHostName()函数,如下:
重新生成rootfs.img,并用qemu启动内核
重新使用qemu启动内核并进行跟踪调试
设置断点1:start_kernel
断点2:sys_sethostname
三、实验分析
Linux下的系统调用是通过软中断0x80实现的,每个系统调用都有相应的系统调用号作为唯一的标识,内核维护一张系统调用表sys_call_table,表中的元素是系统调用函数的起始地址,而系统调用号就是系统调用在调用表的偏移量。在x86上,系统调用号是通过eax寄存器传递给内核的。
首先,用户程序为系统调用设置参数。其中一个参数是系统调用编号。参数设置完成后,程序执行“系统调用”指令。x86系统上的软中断由int产生。这个指令会导致一个异常:产生一个事件,这个事件会致使处理器切换到内核态并跳转到一个新的地址,并开始执行那里的异常处理程序。此时的异常处理程序实际上就是系统调用处理程序。它与硬件体系结构紧密相关。新地址的指令会保存程序的状态,计算出应该调用哪个系统调用,调用内核中实现那个系统调用的函数,恢复用户程序状态,然后将控制权返还给用户程序。系统调用是设备驱动程序中定义的函数最终被调用的一种方式。