一步步编写操作系统 45 用c语言编写内核2
在linux下用于鏈接的程序是ld,鏈接有一個好處,可以指定最終生成的可執行文件的起始虛擬地址。它是用-Ttext參數來指定的,所以咱們可以執行以下命令完成鏈接:
ld kernel/main.o -Ttext 0xc0001500 -e main -o kernel/kernel.bin
從左到右說一下參數,-Ttext 指定起始虛擬地址為0xc0001500,這個地址是設計好的,為什么用這個地址,咱們將來在加載內核時會告訴大家,在此大伙兒先淡定一下。其中 –o的意義也是指定輸出的文件名,至于-e,還是要看一下官方幫助。
ld –help回車后,輸出的信息太多,咱們只看下面的-e參數:
-e ADDRESS, --entry ADDRESS Set start address
-e和--entry一樣,字面上的意思是用來指定程序的起始地址。注意,不要被迷惑了,雖然說是指定起始地址,但參數不僅可以是數字形式的地址,而且可以是符號名,這和匯編中的標號也是地址是一樣的道理。總之它是用來指定程序從哪里開始執行。
為了讓大家更清楚-e的意思,咱們不加-e參數試試,如圖
經過這樣的鏈接操作,ld報錯發出了警告,提示找不到入口符號(entry symbol)_start,默認地址為00000000c0001500。這個_start是什么呢?一個程序總該有個入口地址,這個地址表示的是程序將從哪里開始執行。要知道,并不是程序體中的第一個字節就是程序的起始地址,因為在程序的開頭可能有函數聲明或數據定義,想想咱們的匯編文件loader.S,它最前面的部分可不是指令而是一堆數據,而我們在設計它的時候,知道它的入口地址不在程序開始處,所以在mbr中直接跳入了loader.S的loader_start標號處,跨過了程序開頭的數據部分。這還僅僅是由一個loader.S生成loader.bin,并且是我們提前知道入口地址的情況,如果當多個文件拼合成一個可執行文件時,計算機如何知道程序的入口在哪里呢?也就編譯后的程序應該從哪句代碼開始執行呢?這入口代碼可說不準是哪一個了。由于程序內的地址是在鏈接階段編排(也就是重定位)的,所以在鏈接階段必須要明確入口地址才行,于是鏈接器規定,默認只把名為_start的函數做為程序的入口地址,即默認的entry symbol是_start,除非另行指定。
大家看到了,代碼中并沒有_start這個符號,鏈接器ld找不到該起始地址,所以發出了警告。既然缺少_start符號,那現在把主函數main改成_start試試,代碼如下:
1 //int main(void) { 2 int _start(void) { 3 while(1); 4 return 0; 5 }好啦,編譯鏈接一氣呵成,整個過程沒出任何問題,如圖:
上圖中,我們還用file命令查看了最終生成的kernel.bin文件,您看,它已經是executable啦,即可執行文件。悄悄提示一下,該文件放到虛擬機上運行也是沒問題的。
本節內容摘自《操作系統真象還原》
總結
以上是生活随笔為你收集整理的一步步编写操作系统 45 用c语言编写内核2的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 准备开始买买买!V社发布Steam夏促宣
- 下一篇: 京东618前夕手机品类爆发:最猛还是iP