接上一篇
kernel.img由startup.S以及一堆c文件編譯而成。這是一個ELF格式的文件。(其實前面的boot.img、 diskboot.img、lzma_decomPRess.img本來也都是ELF格式文件,但是經過了精簡。)
kernel.img鏈接時,目標裝載地址是0x9000,這是在Makefile.core.dep中定義的:
i386_pc_ldflags= '$(TARGET_IMG_BASE_LDOPT),0x9000';
但是現在kernel.img被加載到了0x100000,startup.S里的代碼開始執行。所以開頭的幾個指令首先是把startup_raw.S中通過寄存器傳過來的幾個參數保存起來,然后就立即把kernel.img代碼段開頭到數據段結尾(_edata)從0x100000復制到0x9000開始的內存區域,接著一個跳轉:
jmp *%esi /* LOCAL(cont): */
巧妙地跳到了復制后代碼的地址,接下去代碼執行應該就變正常了。
然后對bss段進行清0,并對存放在bss段的grub_boot_device賦值。bss段(Block Started by Symbol)存放的是未初始化的符號(變量)。通常一個程序執行前要對bss進行清0,這樣未初始化的符號值默認為0。這項工作由GRUB自己完成。
接著執行:
call EXT_C(grub_main)/* void grub_main (void) __attribute__ ((noreturn)); */
這是在一個c文件kern/main.c中的函數,也就是GRUB kernel的主函數。grub_main不會返回,于是這條指令相當于一個跳轉。
至此startup.S的代碼執行完畢。
新聞熱點
疑難解答