编号后三位 411,参考孟宁老师 https://github.com/mengning/linuxkernel
wget http://mirrors.ustc.edu.cn/kernel.org/linux/kernel/v5.x/linux-5.0.2.tar.gz
tar -xzvf linux-5.0.3.tar.gz
sudo apt install flex bison libssl-dev
make i386_defconfig
# make
make -j8
#include
int main()
{
int i;
while(0 < 1)
{
scanf("%d", &i);
printf("you input %d\n", i);
}
}
gcc -o init init.c -m32 -static
mkdir rootfs
cp init rootfs/
cd rootfs
ls | cpio -o -Hnewc | gzip -9 > ../rootfs.img
qemu-system-i386 -kernel linux-5.0.2/arch/x86/boot/bzImage -initrd rootfs.img
可以看到以下执行效果
使用以下命令重新编译内核,为内核启用调试选项
# 安装依赖
sudo apt install libncurses-dev
# 生成编译配置
make menuconfig
# 启动编译
make -j6
我的编号后两位是11,因此测试11号API
#define __NR_execve 11
查资料了解到这个系统调用的功能是启动一个可执行程序,因此我需要至少两个可执行程序,一个包含execve调用,另一个被启动。
我编写了以下两个程序。
#include
int main()
{
printf("\nHello world!\n");
return 0;
}
#include
#include
int main()
{
int temp;
char *argv_execve[]={"helloworld", NULL};
char *envp[]={"PATH=/", "USER=coolxxy", "STATUS=testing", NULL};
printf("Starting systemcall execve......\n");
if(fork() == 0)
{
if(execve("./helloworld", argv_execve, envp) < 0)
{
perror("Error on execve");
}
printf("Stoped systemcall execve......\n");
}
while(0 < 1)
{
scanf("%d",&temp);
}
}
前一个输出简单的 helloworld 信息,后一个包含系统调用,用于启动 helloworld 程序。
我还编写了汇编形式的系统调用,但由于gdb可以单步调试汇编,因此这里不作为主要测试代码。
gcc -o init init.c -m32 -static
gcc -o helloworld helloworld.c -m32 -static
cp init rootfs/
cp helloworld rootfs/
cd rootfs
ls | cpio -o -Hnewc | gzip -9 > ../rootfs.img
qemu-system-i386 -kernel linux-5.0.2/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 linux-5.0.2
gdb vmlinux
可以看到如下调试界面
调试 start_kernel 函数, 使用以下 gdb 命令调试
b start_kernel // 设置断点
c // 执行到第一个断点
display /i $pc //显示汇编代码
l // 显示当前c代码
s // 单步执行
s // 单步执行
为了调试方便,我将之前编写的init程序直接在Ubuntu上进行调试,着重分析系统调用过程
gcc init.c -o init -m32 -g
gdb ./init
可以看到,此处的系统调用通过sysenter进入内核,然后启动了 helloworld 程序,调用过程为:
ecx 寄存器压栈 -> edx 寄存器压栈 -> ebp 寄存器压栈 -> mov esp 到 ebp -> sysenter (此处执行了helloworld程序)-> ebp 寄存器出栈 -> edx 寄存器出栈 -> ecx出栈