仿照著寫個bootloader 一

2021-06-27 06:21:53 字數 3023 閱讀 5044

前陣子找到本書其實,于淵大神諾幹年前也寫過類似的書《自己動手寫作業系統》(現在再版叫 orange作業系統的實現),何奈,當時惰性較大,書買來後一直是壓箱底狀態,這回連這本書也一起找了出來,相互對照著看。

我的virtualbox在win7上不能載入vhd檔案,只能直接用bochs觀察結果,雖然沒什麼區別,但還是覺得有點可惜。

進入正文,雖然作者提供了原始碼,但是直接抄下來還發為原創有點說不過去,只能自己寫了,所以標題是仿照著寫bootloader。

先貼**,預期是在螢幕左上角輸出"hello world"

section code align=16 vstart=0x7c00

jmp entry

string db 'hello world',0

length db 0

entry:

;程式從0x7c00開始執行

mov ax,0xb800

mov es,ax

mov ax,cs

mov ds,ax

;xor cx,cx

mov cx,length-string

xor si,si

xor di,di

mov bx,string

lab1:

mov ax,[ds:bx+di]

mov [es:si],ax

mov byte [es:si+1],0x07

inc di

add si,2

loop lab1

jmp $

times 510-($-$$) db 0

db 0x55,0xaa

整個程式只有乙個**段,用string保留的13位元組也在**段中,偏離+0x03這可以從編譯產生的lst檔案以及bochs除錯來觀察。

程式剛啟動時cs:ip停留在邏輯位址f0000:fff0(實體地址ffff0,整個能訪問的記憶體才到0xfffff,好在這個地方安排了乙個跳轉指令跳到f000:e05b,要不然都不夠用的)。從f0000-fffff是bios的空間,程式跳到fe05b處執行一些初始化,這個就不管了直接在0x7c00處下斷點,畢竟這是bootloader的入口點

恢復執行後,程式在0x7c00處停下。其實,前面下斷點時,我就想看下0x7c00處的記憶體是不是被改為0xcc不過啥都沒看到,看來int3還是軟體處理的異常。。。

看下0x7c00處的記憶體情況

lst檔案符合閱讀順序,從左往右位元組以此增加;bochs xp檢視雙字記憶體,每個雙字最右邊是低位元組,最左邊是高位元組。因此,bochs輸出的0x000de9對應lst檔案最開始的e90d00(jmp entry指令);隨後的0x68 0x6f6c6c65對應了lst檔案+0x03開始的68656c6c,對照ascii,是"hell"

hello world最終要輸出到bochs的螢幕上,8086可訪問的1m記憶體中,b8000-bffff對應螢幕顯示區,看下指令剛執行到0x7c00時,這塊區域的值是什麼

b8000開始的記憶體以此為50b06c0b650b780b,按p50頁上描述,「螢幕上的每個字元對應視訊記憶體中的兩個連續的位元組,前乙個是ascii位元組,後乙個是字元顯示屬性」,來看一下,到底視訊記憶體裡存了什麼ascii碼:506c6578對照ascii表以此是plex。好吧,看下現在螢幕上顯示的內容:

前4個字母的確是plex。

最後,讓程式全速,最終輸出:

左上角已經看到hello world輸出了。

好吧,先寫到這,下線後再除錯一會,總結後面再補上。有了這個開頭,真希望自己能繼續下去。

1)有效的主引導扇區,總大小為512b,最後兩位元組為0x55,0xaa。系統加點引導後,bios將該扇區載入到邏輯位址0x0000:0x7c00處,然後jmp 0x0000:0x7c00繼續執行;(p45)

2) 8086可以訪問1m記憶體。0x00000-0x9ffff屬於常規記憶體,由記憶體條提供;0xf0000-0xfffff由rom-bios提供(剛復位時,cs:ip指向0xffff0);從0xa0000-0xeffff由外部裝置提供,其中視訊記憶體佔據了0xb8000-0xbffff這段物理區域。(p48)。程式開始時,

mov ax,0xb800

mov es,ax

使es指向0xb800段

3) 在上面**中有一句:mov bx,string 經過彙編,在lst檔案中顯示的內容為:bb[0300],機器指令中哪來這種東西,感覺有點像重定位,於是加了幾句無關的**:

mov ax,string

lea ax,[string]

mov ax,entry

編譯後在lst檔案中對應的內容為:

00000010 b8[0300]                mov ax,string

00000013 8d06[0300]              lea ax,[string]

00000017 b8[1a00]                mov ax,entry

把這個新生成的bin檔案燒入,啟動bochs再次除錯,並在入口**處反彙編:

距離0x7c00偏移0x10 0x13 0x17處的幾條指令取的偏移值已經和lst檔案中顯示的不同了,因此可以確定確實經過了一次重定位,把指令中引用彙編位址的地方全部修改為載入位址