学号505
原创作品转载请注明出处 + https://github.com/mengning/linuxkernel/
实验环境
ubuntu 16.04
实验过程
内核编译
1.下载Linux5.0.2源码 https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.0.2.tar.xz
输入如下命令来编译内核
mkdir kernel
wget https://mirrors.edge.kernel.org/pub/linux/kernel/v5.x/linux-5.0.1.tar.xz
tar -xvf linux-5.0.1.tar
cd linux-5.0.1
make menuconfig
make
二:制作根文件系统
输入如下命令
cd ..
mkdir rootfs
git clone https://github.com/mengning/menu.git
cd menu
sudo apt install gcc-multilib
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
启动Menu os
cd ~/Documents/linux-5.0.1
qemu-system-i386 -kernel arch/x86/boot/bzImage -initrd rootfs.img
跟踪调试内核启动
qemu-system-i386 -kernel linux-5.0.1/arch/x86/boot/bzImage -initrd rootfs.img -S -s -append nokaslr
启动gdb
cd ~
gdb
(gdb) file linux-5.0.2/vmlinux
(gdb) target remote:1234
增加系统调用
根据学号后两位05,去system_call_table(位于/usr/include/asm/unistd_32.h)中查找
#define __NR_sethostname 05
在test.c中增加SetHostName函数,再重新编译rootfs.img
int SetHostName(int argc,char *argv[])
{
char oldname[NAME_MAX];
char name[NAME_MAX];
char * newname = "ZGJ-PC";
gethostname(oldname, NAME_MAX);
printf("show oldname = %s\n",oldname);
int ret;
asm volatile(
"movl %1,%%ebx\n\t"
"movl %2,%%ecx\n\t"
"movl $0x05,%%eax\n\t"
"int $0x80\n\t"
"movl %%eax,%0\n\t"
: "=m" (ret)
: "b"(newname),"n"(NAME_MAX)
);
if(ret == -1)
perror("sethostname");
gethostname(name, NAME_MAX);
printf("show newname = %s\n",name);
return 0;
}
重新编译rootfs.img
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
跟踪调用
六、实验总结
本实验让我学会了如何编译内核,并在内核中增加系统调用,当客户程序执行系统调用时,内核此时就会产生0x80号中断,并且由用户态切换到内核态中。内核态中维护一张表,这张表对应着相应的系统调用与系统调用号,即系统调用表,记录函数入口地址。用户在进入内核态前会将对应的系统调用号,通过寄存器eax传入给内核态。然后内核空间根据系统调用号和系统调用表相对应,调用相应的系统调用对应的函数执行完以后,再由内核态切换到用户态。