内核主程序相当于应用程序的主函数。负责调用各个系统模块的初始化函数,在这些模块初始化结束后,它会创建处系统的第一个init进程,并将控制权交给init进程。
当前主程序不具备任何功能,只是为了让内核执行头程序有目标跳转而已。
start_kernel函数实现:
1 2 3 4 5
| void start_kernel(void) { while (1) { ; } }
|
编译脚本:
1 2
| $(BUILD_KERNEL)/main.o: $(KERNEL)/main.c gcc -mcmodel=large -fno-builtin -m64 -c $< -o $@
|
使用kernel.lds负责将编译生成的main.o文件和header.o文件链接成可执行程序,输出名为system。
1 2 3
| $(BUILD_KERNEL)/system: $(BUILD_KERNEL)/header.o \ $(BUILD_KERNEL)/main.o ld -b elf64-x86-64 -o $@ $^ -T $(KERNEL)/kernel.lds
|
经过编译后生成的文件system依然不是最终的内核程序,还需要将system文件中的二进制提取出来:
1 2
| $(BUILD_KERNEL)/kernel.bin: $(BUILD_KERNEL)/system objcopy -I elf64-x86-64 -S -R ".eh_frame" -R ".comment" -O binary $< $@
|
此段Makefile脚本命令的作用是剔除system程序中多余的段信息,并提取出二进制程序段数据(text、data、bss段等)。
反汇编system文件:
必须反编译system,只有这个文件记录内核程序的各个段信息。
可看到start_kernel的信息如下:
1 2 3 4 5 6 7 8 9 10
| ...... ffff800000104000 <start_kernel>: ffff800000104000: 55 push %rbp ffff800000104001: 48 89 e5 mov %rsp,%rbp ffff800000104004: 48 8d 05 f9 ff ff ff lea -0x7(%rip),%rax # ffff800000104004 <start_kernel+0x4> ffff80000010400b: 49 bb 94 11 00 00 00 movabs $0x1194,%r11 ffff800000104012: 00 00 00 ffff800000104015: 4c 01 d8 add %r11,%rax ffff800000104018: eb fe jmp ffff800000104018 <start_kernel+0x18> ......
|
jmp ffff800000104018这条指令是一个死循环语句。
使用bochs虚拟机运行后,输出寄存器信息如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| ...... 00567966634i[CPU0 ] CPU is in long mode (active) 00567966634i[CPU0 ] CS.mode = 64 bit 00567966634i[CPU0 ] SS.mode = 64 bit 00567966634i[CPU0 ] EFER = 0x00000500 00567966634i[CPU0 ] | RAX=ffff800000105198 RBX=0000000000000000 00567966634i[CPU0 ] | RCX=00000000c0000080 RDX=0000000000000000 00567966634i[CPU0 ] | RSP=ffff800000007df8 RBP=ffff800000007df8 00567966634i[CPU0 ] | RSI=00000000000080ae RDI=000000000000c800 00567966634i[CPU0 ] | R8=0000000000000000 R9=0000000000000000 00567966634i[CPU0 ] | R10=0000000000000000 R11=0000000000001194 00567966634i[CPU0 ] | R12=0000000000000000 R13=0000000000000000 00567966634i[CPU0 ] | R14=0000000000000000 R15=0000000000000000 00567966634i[CPU0 ] | IOPL=0 id vip vif ac vm rf nt of df if tf SF zf af pf cf 00567966634i[CPU0 ] | SEG sltr(index|ti|rpl) base limit G D 00567966634i[CPU0 ] | CS:0008( 0001| 0| 0) 00000000 00000000 0 0 00567966634i[CPU0 ] | DS:0010( 0002| 0| 0) 00000000 00000000 0 0 00567966634i[CPU0 ] | SS:0010( 0002| 0| 0) 00000000 00000000 0 0 00567966634i[CPU0 ] | ES:0010( 0002| 0| 0) 00000000 00000000 0 0 00567966634i[CPU0 ] | FS:0010( 0002| 0| 0) 00000000 00000000 0 0 00567966634i[CPU0 ] | GS:0010( 0002| 0| 0) 00000000 00000000 0 0 00567966634i[CPU0 ] | MSR_FS_BASE:0000000000000000 00567966634i[CPU0 ] | MSR_GS_BASE:0000000000000000 00567966634i[CPU0 ] | RIP=ffff800000104018 (ffff800000104018) 00567966634i[CPU0 ] | CR0=0xe0000011 CR2=0x0000000000000000 00567966634i[CPU0 ] | CR3=0x0000000000101000 CR4=0x00000020 ......
|
RIP=ffff800000104018记录RIP寄存器的值,与编译处的jmp ffff800000104018指令地址一致。