【從頭到腳品讀 Linux 0.11 源碼】第一回 最開始的兩行代碼
從這一篇開始,您就將跟著我一起進(jìn)入這操作系統(tǒng)的夢(mèng)幻之旅!
別擔(dān)心,每一章的內(nèi)容會(huì)非常的少,而且你也不要抱著很大的負(fù)擔(dān)去學(xué)習(xí),只需要像讀小說(shuō)一樣,跟著我一章一章讀下去就好。
話不多說(shuō),直奔主題。當(dāng)你按下開機(jī)鍵的那一刻,在主板上提前寫死的固件程序 BIOS 會(huì)將硬盤中啟動(dòng)區(qū)的 512 字節(jié)的數(shù)據(jù),原封不動(dòng)復(fù)制到內(nèi)存中的 0x7c00 這個(gè)位置,并跳轉(zhuǎn)到那個(gè)位置進(jìn)行執(zhí)行。

啟動(dòng)區(qū)的定義非常簡(jiǎn)單,只要硬盤中的 0 盤 0 道 1 扇區(qū)的 512 個(gè)字節(jié)的最后兩個(gè)字節(jié)分別是 0x55 和 0xaa,那么 BIOS 就會(huì)認(rèn)為它是個(gè)啟動(dòng)區(qū)。
所以對(duì)于我們理解操作系統(tǒng)而言,此時(shí)的 BIOS 僅僅就是個(gè)代碼搬運(yùn)工,把 512 字節(jié)的二進(jìn)制數(shù)據(jù)從硬盤搬運(yùn)到了內(nèi)存中而已。所以作為操作系統(tǒng)的開發(fā)人員,僅僅需要把操作系統(tǒng)最開始的那段代碼,編譯并存儲(chǔ)在硬盤的 0 盤 0 道 1 扇區(qū)即可。之后 BIOS 會(huì)幫我們把它放到內(nèi)存里,并且跳過(guò)去執(zhí)行。
而 Linux-0.11 的最開始的代碼,就是這個(gè)用匯編語(yǔ)言寫的 bootsect.s,位于 boot 文件夾下。

通過(guò)編譯,這個(gè) bootsect.s 會(huì)被編譯成二進(jìn)制文件,存放在啟動(dòng)區(qū)的第一扇區(qū)。

隨后就會(huì)如剛剛所說(shuō),由 BIOS 搬運(yùn)到內(nèi)存的 0x7c00 這個(gè)位置,而 CPU 也會(huì)從這個(gè)位置開始,不斷往后一條一條語(yǔ)句無(wú)腦地執(zhí)行下去。
那我們的夢(mèng)幻之旅,就從這個(gè)文件的第一行代碼開始啦!
mov ax,0x07c0 mov ds,ax
好吧,先連續(xù)看兩行。
這段代碼是用匯編語(yǔ)言寫的,含義是把 0x07c0 這個(gè)值復(fù)制到 ax 寄存器里,再將 ax 寄存器里的值復(fù)制到 ds 寄存器里。那其實(shí)這一番折騰的結(jié)果就是,讓 ds 這個(gè)寄存器里的值變成了 0x07c0。

ds 是一個(gè) 16 位的段寄存器,具體表示數(shù)據(jù)段寄存器,在內(nèi)存尋址時(shí)充當(dāng)段基址的作用。啥意思呢?就是當(dāng)我們之后用匯編語(yǔ)言寫一個(gè)內(nèi)存地址時(shí),實(shí)際上僅僅是寫了偏移地址,比如:
mov ax, [0x0001]
實(shí)際上相當(dāng)于
mov ax, [ds:0x0001]
ds 是默認(rèn)加上的,表示在 ds 這個(gè)段基址處,往后再偏移 0x0001 單位,將這個(gè)位置的內(nèi)存數(shù)據(jù),復(fù)制到 ax 寄存器中。
形象地比喻一下就是,你和朋友商量去哪玩比較好,你說(shuō)天安門、南鑼鼓巷、頤和園等等,實(shí)際上都是偏移地址,省略了北京市這個(gè)基址。
當(dāng)然你完全可以說(shuō)北京天安門、北京南鑼鼓巷這樣,每次都加上北京這個(gè)前綴。不過(guò)如果你事先和朋友說(shuō)好,以下我說(shuō)的地方都是北京市里的哈,之后你就不用每次都帶著北京市這個(gè)詞了,是不是很方便?
那 ds 這個(gè)數(shù)據(jù)段寄存器的作用就是如此,方便了描述一個(gè)內(nèi)存地址時(shí),可以省略一個(gè)基址,沒什么神奇之處。
ds : 0x0001
北京市 : 南鑼鼓巷
再看,這個(gè) ds 被賦值為了 0x07c0,由于 x86 為了讓自己在 16 位這個(gè)實(shí)模式下能訪問(wèn)到 20 位的地址線這個(gè)歷史因素(不了解這個(gè)的就先別糾結(jié)為啥了),所以段基址要先左移四位。那 0x07c0 左移四位就是 0x7c00,那這就剛好和這段代碼被 BIOS 加載到的內(nèi)存地址 0x7c00 一樣了。
也就是說(shuō),之后再寫的代碼,里面訪問(wèn)的數(shù)據(jù)的內(nèi)存地址,都先默認(rèn)加上 0x7c00,再去內(nèi)存中尋址。
為啥統(tǒng)一加上 0x7c00 這個(gè)數(shù)呢?這很好解釋,BIOS 規(guī)定死了把操作系統(tǒng)代碼加載到內(nèi)存 0x7c00,那么里面的各種數(shù)據(jù)自然就全都被偏移了這么多,所以把數(shù)據(jù)段寄存器 ds 設(shè)置為這個(gè)值,方便了以后通過(guò)這種基址的方式訪問(wèn)內(nèi)存里的數(shù)據(jù)。

OK,趕緊消化掉前面的知識(shí),那本篇就到此為止,只講了兩行代碼,知識(shí)量很少,我沒騙你吧。
希望你能做到,對(duì) BIOS 將操作系統(tǒng)代碼加載到內(nèi)存 0x7c00,以及我們通過(guò) mov 指令將默認(rèn)的數(shù)據(jù)段寄存器 ds 寄存器的值改為 0x07c0 方便以后的基址尋址方式,這兩件事在心里認(rèn)可,并且沒有疑惑,這才方便后面繼續(xù)進(jìn)行。
后面的世界越來(lái)越精彩,欲知后事如何,且聽下回分解。
------- 本回?cái)U(kuò)展資料 -------
有關(guān)寄存器的詳細(xì)信息,可以參考 Intel 手冊(cè):
Volume 1 Chapter 3.2 OVERVIEW OF THE BASIC EXECUTION ENVIRONMEN
有關(guān)計(jì)算機(jī)啟動(dòng)部分的原理如果還不清楚,可以看我之前的一篇文章了解一下:
如果想了解計(jì)算機(jī)啟動(dòng)時(shí)詳細(xì)的初始化過(guò)程,還是得參考 Intel 手冊(cè):
Volume 3A Chapter 9 PROCESSOR MANAGEMENT AND INITIALIZATION
------- 關(guān)于本系列 -------
本系列的開篇詞看這
本系列的擴(kuò)展資料看這,這里有很多有趣的資料、答疑、互動(dòng)參與項(xiàng)目,持續(xù)更新中,希望有你的參與。
https://github.com/sunym1993/flash-linux0.11-talk
本系列全局視角

最后,祝大家都能追更到系列結(jié)束,只要你敢持續(xù)追更,并且把每一回的內(nèi)容搞懂,我就敢讓你在系列結(jié)束后說(shuō)一句,我對(duì) Linux 0.11 很熟悉。
另外,本系列完全免費(fèi),希望大家能多多傳播給同樣喜歡的人,同時(shí)給我的 GitHub 項(xiàng)目點(diǎn)個(gè) star,這些就足夠讓我堅(jiān)持寫下去了!我們下回見。
公眾號(hào) - 低并發(fā)編程

浙公網(wǎng)安備 33010602011771號(hào)