走進程序世界的田園 ——引導扇區釋疑

<script language="javascript" type="text/javascript"> </script>
  編輯部的故事  |  聯絡  |  聚合   |  登錄
  10 篇文章  |   1 篇收藏   |   114 個評論   |   1 個Trackbacks

走進程序世界的田園
——引導扇區釋疑


什麼?又是醬雞翅?!你眉頭皺起——公司的工作餐怎麼就不能出點新的花樣?吹着空調還會出汗的大熱的天卻還要忍受這份油膩,此刻的你顯然更需要西芹百合!這就如同你曾深深癡迷的這份工作,其實你是多麼懷念在黑色背景上敲出一行命令之後屏幕嘩嘩捲動的景象,多麼自豪於曾經用匯編在屏幕上繪出的彩色的圖案,而如今,虛擬機,API等等新鮮玩意讓你總感覺彷彿想親吻女友的手時卻親到了手套,沒有親密感,也許,你不僅僅需要Java、.NET這樣的高樓大廈,你同樣需要清新的田園,比如你每天都在使用卻可能一知半解的——計算機如何引導。
那麼,現在就讓我們一起走進這田園,看看計算機究竟是如何引導的。

計算機的啓動過程

如果你買來新的計算機,硬盤上還是一片空白的時候,你按下power鍵,仍然可以看到許許多多字符和圖案,這顯然不是操作系統的一部分,而是BIOS的程序在工作。當然,最後你能看到一行字,提示你插入引導盤。是的,BIOS在尋找一個可供引導的磁盤,找到之後,便會加載盤上的引導模塊,並交出控制權,將接力棒傳遞給操作系統。
我們考慮最簡單最易學習的情況,那就是軟盤。
如果你將一張非引導磁盤插入軟驅的話,BIOS仍然會報錯,提示你插入一張系統盤,這說明BIOS並非來者不拒全部試圖加載執行的,那麼它選擇的標準是什麼呢?實際上很簡單,它會去檢查軟盤的0面0磁道1扇區(大小爲512字節),如果發現它以55AA結束,則BIOS認爲它是一個引導扇區,也就是我們說的Boot Sector。當然,一個正確的Boot Sector只有55AA這個結束標誌是沒有意義的,它還應該包含一段少於512字節的執行碼,以便能被放在一個扇區內並正確運行。
一旦BIOS發現了Boot Sector,它就會將這512字節的整個扇區內容裝載到內存的0:7c00處,然後跳轉到0:7c00處將控制權徹底交給這段引導代碼。到此爲止,計算機不再有BIOS中固有的程序來控制,而變成由操作系統的一部分來控制。

馬上實踐——一個最小的引導扇區

準備工作:
硬件
一臺計算機(Windows操作系統)
一張空白軟盤
軟件
彙編編譯器NASM。最新版本可以在此鏈接處獲得:http://sourceforge.net/projects/nasm。(此刻你可能會有疑問,爲什麼是NASM,而不是MASM或者TASM,對於這一點我稍候再來解釋)
軟盤絕對扇區讀寫工具。其實你完全可以自己寫一個,用CreateFile和WriteFile這兩個API就搞定了,非常容易。我就是這樣做的,省去了在網上尋找工具的時間。
最好有一個虛擬機比如VirtualPC,可以在試驗的時候不必重啓自己的計算機。


代碼
我們來看這一段代碼:
org 07c00h  ;告訴編譯器程序加載到7c00處
jmp $  ;無限循環
times 510-($-$$) db 0 ;填充剩下的空間,使生成的二進制代      碼恰好爲512字節
dw  0aa55h   ;引導扇區需要以55AA結束

在對程序進行解釋之前,爲了儘快看到效果有初步的感性認識,請先隨我來做以下操作:
首先用NASM編譯一下:

nasm boot.asm -o boot.bin


我們就得到了一個512字節大小的boot.bin,使用軟盤絕對扇區讀寫工具將這個文件寫到一張空白軟盤的第一個扇區,好了,這張軟盤已經是一個引導盤了。
然後把它放到你的軟驅中重新啓動計算機,或者使用VirtualPC模擬啓動過程,從軟盤引導,你看到了什麼?
答案是什麼令人驚喜的結果也沒有出現,這倒容易理解,因爲我們的程序第一個語句就是一個死循環。我們除了讓程序停滯在那裏,其餘什麼也沒做。
這顯然並不令人滿意,我們得看到些效果才行,讓我們將代碼稍作修改:

org 07c00h   ; 告訴編譯器程序加載到7c00處
mov ax, 0b800h
mov es, ax   ; 設置 es 以便直接寫顯存
mov byte [es:0], 'a' ; 在顯存第一個字節寫入字符‘a’
mov byte [es:1], 0ch ; 在顯存第二個字節寫入十六        進制值C,表示黑底紅字
jmp $   ; 無限循環
times 510-($-$$) db 0 ; 填充剩下的空間,使生成的        二進制代碼恰好爲512字節
dw  0aa55h    ; 引導扇區需要以55AA結束

我們在程序無限循環之前插入了四行,目的是讓我們的引導程序能顯示一個紅色的字符‘a’。插入的這四行比較易懂,效果是在B800:0000處寫入了兩個字節:'a'和0Ch。我們知道,B800:0000恰好是顯存的首地址。
同樣的方法編譯,寫入磁盤並重啓,你看到了什麼?
你看到紅色的字符a了!
多麼令人激動啊,這表明我們的程序正確運行了,進一步,這說明我們自己編寫的引導扇區試驗成功了!
如果你用的是VirtualPC,出現的應該是這樣的景象(局部):

r_07-扇區釋疑01%20copy.jpg

這簡直是太妙了,因爲有了這樣的開頭,就意味着你可以在此基礎上做出任意的擴展,甚至寫出自己的操作系統!這一步邁出來的確並不難,但卻具有歷史意義!

爲什麼是NASM
你可能感到很奇怪,爲什麼居然有人用NASM這樣東西,而不是你從前使用的MASM或者TASM,實際上這有點涉及到個人喜好,但是事實是,我從開始無意中接觸到NASM開始,就決定從此徹底拋棄MASM了。因爲它具備以下幾個主要特點:
1、代碼清晰,避免了MASM中容易混淆的語法。
這項特點在NASM多個細節都有體現,這裏我僅舉兩例。
第一,在NASM中,任何不被方括號[]括起來的標籤或變量名都將被認爲是地址,訪問標籤中的內容必須使用[]。所以,mov ax, Message將會把Message對應字符串的首地址傳給寄存器ax。又比如:
如果有:foo dw 1則mov ax, foo將把foo的地址傳給ax,而mov bx, [foo]將把bx的值賦成爲1。
實際上,在NASM中,變量和標籤是一樣的,也就是說,

foo dw 1 ≡ foo: dw 1

而且你會發現,offset這個東東在NASM也是不需要的。因爲不加方括號時表示的就是offset。
我個人認爲這是NASM的一大優點,要地址就不加方括號,也不必額外的offset,想要訪問地址中的內容就必須加上方括號,代碼規則非常鮮明,一目瞭然。
第二,既然所有標籤都是地址,使得NASM具有另外一個特點,就是不記憶變量類型,所以在給變量賦值的時候,必須加上賦值的類型,比如:

mov byte [var1], 'a'

2、 可以在不同平臺中使用
如果你想學習一次就可以在不同平臺下使用的話,NASM幾乎是唯一的選擇。如果你想進行完全的代碼移植,NASM是完美的工具。因爲不管在Dos,Windows還是Linux,NASM都是可用的,而且用法完全相同。
3、 免費
可能這項特性已經不足以吸引你的眼球,但的確是它的一個可愛的特性。
本文不是專門的NASM介紹文章,但是我認爲它的確是一個值得推薦的工具,尤其是,如果你不想僅僅瞭解引導扇區的寫法,而是在此基礎上深究下去,進行操作系統的研究,我保證你會越來越體會到NASM這一工具的優點。

關鍵代碼解釋

上面兩段代碼的註釋已經寫得比較清晰,在這裏對幾個問題着重強調一下。
1、org的使用
org的作用是告訴編譯器,這個程序將來被加載到內存的哪個位置。我們在稍後的例子中會使用到常量,編譯器就是以org指定的這個地址爲基準來確定常量的地址。
2、關於$和$$
$表示當前行被彙編後的地址。這好像不太好理解,不要緊,我們把剛剛生成的二進制代碼文件反彙編來看看:

ndisasmw -o 0x7c00 boot.bin >> a.asm

打開a.asm,你會發現這樣一行:

00007C09  EBFE              jmp short 0x7c09

$在這裏的意思原來就是0x7c09(在加載到內存之後)。
那麼$$表示什麼?它表示一個節(section)的開始處被彙編後的地址。在這裏,我們的程序只有一個節,所以$$實際上就表示程序被編譯後的開始地址,也就是0x7c00。
在寫程序的過程中,“$-$$”可能會被經常用到,它表示本行距離程序開始處的相對距離。現在,你應該明白510-($-$$)表示什麼意思了吧?times  510-($-$$) db 0表示將0這個字節重複510-($-$$)遍,也即在剩下的空間中不停地填充0,直到程序有510字節爲止,這樣,加上結束標誌55AA佔用的兩個字節,恰好是512個字節。
3、 55AA還是AA55
初學者經常被這個問題搞得非常頭痛,總也搞不清楚到底誰在前誰在後,其實歸根到底還是沒把本質弄明白。
IBMPC的原則是“高位在高字節”。舉個例子,如果有一個DWORD類型的數0x12345678放在內存中,看起來會是這樣:

L ———> H
78 56 34 12

因爲78處在數字的低位,於是也會被放到內存的低位。
這裏有一點需要思考一下,就是計算機只知道數字,不知道類型,所以,從內存的某個地址取出一個數,必須在指明類型的情況下才是有意義的,比如已知有這樣的內存映像:

L ———> H
78 56 34 12

若想取出一個BYTE,你會得到0x78;若想取出一個WORD,你會得到0x5678;若想取出一個DWORD,你會得到0x12345678。
回頭看看我們的代碼:

dw  0aa55h

我們指定把0aa55h這個WORD類型數字放在引導扇區最末端,aa處在數字的高位,會被放到內存的高位,於是它在內存中的映像應該是:

L———>H
55 aa

很簡單,也很明瞭不是嗎?

再作擴充——一個變一行

只顯示一個字符顯然是不夠的,我們想要更進一步的成就感,比如顯示一個字符串。可是如果顯示每一個字符都要兩行代碼來實現的話,難免顯得笨拙而低效。是的,你一定想到了,我們可以使用BIOS中斷。
請看代碼:

org 07c00h   ; 程序會被加載到7c00處,所以需要這一句
 mov ax, cs
 mov ds, ax
 mov es, ax
 Call DispStr   ; 調用顯示字符串例程
 jmp $   ; 無限循環
DispStr:
 mov ax, BootMessage
 mov bp, ax   ; ES:BP = 串地址
 mov cx, 16   ; CX = 串長度
 mov ax, 01301h  ; AH = 13,  AL = 01h
 mov bx, 000ch  ; 頁號爲0(BH = 0) 黑底
         紅字(BL = 0Ch,高亮)
 mov dl, 0
 int 10h   ; int 10h
 ret
BootMessage:   db    " Hello, OS world!"
 times 510-($-$$) db   0 ;填充剩下的空間,使生成的二
      進制代碼恰好爲512字節
 dw  0aa55h   ; 引導扇區需要以55AA結束

這段代碼看上去長了許多,但實際上主體框架只有5行(從第2行到第6行),其中調用了一個顯示字符串的子程序。程序的第2、3、4行是三個mov指令,使ds和es兩個段寄存器指向與cs相同的段,以便在以後進行數據操作的時候能定位到正確的位置。第5行調用子程序顯示字符串,然後jmp $讓程序無限循環下去。
我們來試驗一下,編譯,寫入磁盤,啓動:

r_07-扇區釋疑02%20copy.jpg

成功!
來來來,下面泡一杯咖啡,然後靠在椅背上靜靜欣賞一下自己的成果吧,讓你的屏幕暫時停在這一刻。這是一件多麼有趣的作品!雖然我們的代碼很短,卻已經涉及到了如此多的技術細節,我們甚至使用了BIOS中斷,在中斷例程的幫助下,我們幾乎是無所不能的,想象一下吧,最振奮人心的一點是,你可以進行磁盤操作,將更多的程序加載到內存中並且執行,這意味着你真的已經可以在這個小東西的基礎上一點點擴充,甚至建造操作系統的大廈!

之所以這是田園,因爲這裏離泥土最近

你可能很久都沒有過如此透徹地瞭解一件事,就好像你又看到泥土中生長出綠色的植物。這是一種迴歸自然的感覺,那麼,就請盡情享受這一刻爽快的感受吧,忘掉Java,.NET,還有那討厭的醬雞翅。

發表於 2004年07月27日 4:49 PM
rel="pingback" href="http://editblog.csdn.net/programmer/Services/Pingback.aspx">

評論

# 回覆:2004年7月《程序員》試讀文章“程序世界的田園”系列之一 2004-07-28 11:20 AM 野比
不知道那個絕對扇區讀寫程序哪裏有下?
希望提供連接~
文章不錯,我很喜歡。

# 回覆:2004年7月《程序員》試讀文章“程序世界的田園”系列之一 2004-07-28 12:20 PM 微軟小子
暈~程序員雜誌上的文章。。白買了。。。汗。。

# 回覆:2004年7月《程序員》試讀文章“程序世界的田園”系列之一 2004-07-28 12:32 PM t608
暈~程序員雜誌上的文章。。白買了。。。汗。。


# 回覆:2004年7月《程序員》試讀文章“程序世界的田園”系列之一 2004-07-28 12:55 PM garbage
白買了,,亂搞~

# 回覆:2004年7月《程序員》試讀文章“程序世界的田園”系列之一 2004-07-28 5:16 PM 77
靠!不就一篇,上面幾位叫什麼叫

# 回覆:2004年7月《程序員》試讀文章“程序世界的田園”系列之一 2004-07-28 7:05 PM 野比
嘎嘎,多放幾篇~
等我回去寫一個那個程序的……

# 回覆:2004年7月《程序員》試讀文章“程序世界的田園”系列之一 2004-07-28 10:46 PM 果蜾
呵呵,不懂的東西叫知識。好文章

# 可操作性的文章最受歡迎 2004-07-29 8:17 AM Andy Pan
這是我近期最喜歡的一篇技術文章,也是我認爲最適合《程序員》定位的文章,我個人覺得《程序員》有一些技術文章過於抽象,集中在很多模式以及開發理論上,雖然編程技巧的文章有“雕蟲小技”之嫌,但是此類可操作性強的文章很適合《程序員》雜誌80%的讀者。深入淺出,易於學習,對雜誌讀者很重要。擁有這些的作者也體現了《程序員》雜誌是中國開發類雜誌的第一品牌。

# 回覆:2004年7月《程序員》試讀文章“程序世界的田園”系列之一 2004-07-29 8:45 AM java
看了這篇文章,這期的程序員,咱是不會買了。怎麼辦得象電腦報這樣的入門刊物

# 回覆:2004年7月《程序員》試讀文章“程序世界的田園”系列之一 2004-07-29 9:16 AM ft
to java: 看了這篇文章,這期的程序員,咱是不會買了。怎麼辦得象電腦報這樣的入門刊物
這位仁兄看來是高手!入門刊物的東西不知道你懂得透徹不透徹?
不過買不買倒是你的權利。

# 回覆:2004年7月《程序員》試讀文章“程序世界的田園”系列之一 2004-07-29 9:39 AM bob
無所謂的文章一篇,看看也就是了,何必要大鼓地說呢,搞的大家真的以爲是什麼“妙文”,《程序員》也太沒有眼光了,這樣的文章最多是瞄一眼罷了,何必要說什麼“妙文”。太幽默了。

# 回覆:2004年7月《程序員》試讀文章“程序世界的田園”系列之一 2004-07-29 9:50 AM notyy
好文

# 回覆:2004年7月《程序員》試讀文章“程序世界的田園”系列之一 2004-07-29 10:17 AM 吃人
說實在的 這個實在是沒有技術含量.....
會點匯編的瞭解boot block架構的大概都可以寫出來這樣的東西..
這個是比較低層的東西了.....
太簡單...應該再深再深...... 再擴展再擴展...
而不是簡單的一個低層應用

# 回覆:2004年7月《程序員》試讀文章“程序世界的田園”系列之一 2004-07-29 10:52 AM Hehe
這篇文章的惟一用處就是讓我 想起十幾年前的事情

# 回覆:2004年7月《程序員》試讀文章“程序世界的田園”系列之一 2004-07-29 1:00 PM 態度決定一切
每個程序員都有自己的要求,有人java .net 有人 asm,這都不是重要的,寫好自己的東東纔是重要的。

# 各取所需而已 2004-07-29 4:36 PM jacky
對於boot我還是非常不瞭解,所以這篇文章給我增長見識,感謝作者。

# 回覆:2004年7月《程序員》試讀文章“程序世界的田園”系列之一 2004-07-29 5:30 PM ascender
推薦文章應該更有檔次才行吧?

# 回覆:2004年7月《程序員》試讀文章“程序世界的田園”系列之一 2004-07-29 5:49 PM 小貴子
以上功能能否用C語言實現?

# 回覆:2004年7月《程序員》試讀文章“程序世界的田園”系列之一 2004-07-29 6:14 PM kwest
暈,就那麼一點啓動代碼....IBM兼容機..呵呵....

# 回覆:2004年7月《程序員》試讀文章“程序世界的田園”系列之一 2004-07-30 1:04 AM icelover
我覺得這篇文章講的非常好,比起那些抽象的鼕鼕更能吸引人

# 回覆:2004年7月《程序員》試讀文章“程序世界的田園”系列之一 2004-07-30 8:55 AM 春困
好文,我喜歡

# 回覆:2004年7月《程序員》試讀文章“程序世界的田園”系列之一 2004-07-30 9:23 AM captain
是的,非常懷念產DOS時代,一個一切由自已說了算的時代。。。
但是自由是用代價換來的。如果從底層開發,需要更長的週期,更多的測試,當然,更多的Bug是不可避免的了:)
所以,DOS適合有興趣的人自已玩。。。

# 回覆:2004年7月《程序員》試讀文章“程序世界的田園”系列之一 2004-07-31 11:55 AM ylhyh
我覺得是不錯,我喜歡DOS
不喜歡只寫代碼而不關心繫統的程序員

# 回覆:2004年7月《程序員》試讀文章“程序世界的田園”系列之一 2004-07-31 8:11 PM welman
城市的喧囂不適合田園的牧歌,權當消遣吧..........

但確實不錯,是吧.

# 回覆:2004年7月《程序員》試讀文章“程序世界的田園”系列之一 2004-08-01 10:36 PM FOCL
我就覺得很好,樓上的 “無所謂的文章一篇,看看也就是了,何必要大鼓地說呢,搞的大家真的以爲是什麼“妙文”,《程序員》也太沒有眼光了,這樣的文章最多是瞄一眼罷了,何必要說什麼“妙文”。太幽默了。 ” ,你的觀點是不是太偏激了?!

# 回覆:2004年7月《程序員》試讀文章“程序世界的田園”系列之一 2004-08-01 10:39 PM JACKY2
好喜歡這種文章阿!
一個好的程序員不會說這種文章不好吧,就算自己懂了,也可以惠於後來人吧!
超喜歡!!

# 回覆:2004年7月《程序員》試讀文章“程序世界的田園”系列之一 2004-08-04 12:40 PM 於淵

首先謝謝大家對這篇文章的關注,也感謝《程序員》和CSDN提供了這樣一個機會讓大家可以一起討論。

在七月號的雜誌中這篇文章的下面可以看到一篇《“程序世界的田園”系列文章序》,裏面表達了一些我對操作系統的看法,同時也告訴大家,其實這篇文章僅僅是一個系列的第一篇,它以簡單的內容和輕鬆的口吻開始,目的是引起大家對操作系統技術的一點興趣和關注,在今後的幾篇文章中,我會涉及一些稍稍深入點的內容,當然,讀者中肯定有非常多的人對這些問題的研究要深入和廣泛的多,也請大家能不吝賜教,多提意見和建議。

八月號的雜誌已經可以買到了吧,在這一期中刊登了系列文章的第二篇,內容是關於存儲管理的,請大家在閱讀文章之後能繼續給予一些指點。我的EMail是:[email protected]。對於你的來信我會非常感謝。


# 回覆:2004年7月《程序員》試讀文章“程序世界的田園”系列之一 2004-08-04 12:52 PM webspider
絕知此事要躬行!
文章雖然簡單,但還沒有碰到有人用如此歡快節奏的小品文方式把它寫出來。程序世界當中本來就沒什麼難題,只要大家一點一點的去做,注重積累。國內,只是有太多的人眼睛總是盯最流行的東西,從VC到Java,再到後來的.net,什麼東西都淺嘗輒止,其不知在流沙上面是建不了高樓的。這也是國外那些最牛的人都是彙編年代出來的人,對於他們來說細節上沒有難度(對很多玩時髦的人來說,細節是地獄),只要他們有想法,他們就能實現。
在炎熱的、浮躁的夏季,我喜歡這種清涼的短文,也需它對我當前的Java項目沒有很直接的幫助,但它該表了我的一些思想,影響是長遠的。
在此感謝作者!

# 回覆:2004年7月《程序員》試讀文章“程序世界的田園”系列之一 2004-08-04 1:06 PM webspider
有些人埋怨簡單!
是的,現在有現成的Linux內核代碼,
有幾個人不被那如山的代碼嚇倒?在面對如此多的代碼,除了感嘆作者的牛之外,留給我們的更多的是挫折感,還留下了什麼?莫非還有些感嘆吧。這就是當時我的感受。
作者可謂用心良苦!
用這種簡單的方式從浩如煙海的操作系統中精選出這些簡單的東西,讓我感受操作系統的美妙,而又不被嚇爬在地上。

# 回覆:2004年7月《程序員》試讀文章“程序世界的田園”系列之一 2004-08-04 3:03 PM nkscorpion
我近期正對計算機的“啓動->OS”好奇,這篇文章給了一個很好的指導。在此,感謝作者爲我們奉獻了該文;也感謝CSDN給我一個看到該文的機會!繼續關注...

# 回覆:2004年7月《程序員》試讀文章“程序世界的田園”系列之一 2004-08-05 9:03 AM eming
謝謝作者,俺長見識了!

# 回覆:《程序員》04年第7期試讀文章“程序世界的田園”系列之一 2004-08-08 12:50 AM flair
寫軟盤
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
int main()
{
char boot_buf[512];
int floppyd, fd;
fd = open("./bootfile", O_RDONLY);
read(fd, boot_buf, 510);
close(fd);
boot_buf[510] = 0x55;
boot_buf[511] = 0xaa;
floppyd = open("/dev/fd0", O_RDWR);
lseek(floppyd, 0, SEEK_CUR);
write(floppyd, boot_buf, 512);
close(floppyd);
}


# 回覆:《程序員》04年第7期試讀文章“程序世界的田園”系列之一 2004-08-08 3:34 PM 於淵
我寫軟盤用的程序已經放在這個頁面上:http://forrestyu.vicp.net/Download.htm,感興趣的可以下載。
這個主頁並不是24小時有效的,中午12點到凌晨0點可訪問的概率最大。

# 回覆:《程序員》04年第7期試讀文章“程序世界的田園”系列之一 2004-08-16 9:30 PM apemancsdn
關於寫磁盤的絕對扇區的方法, 請大家參看我的blog:
http://blog.csdn.net/apemancsdn
這篇文章上的代碼我全部實現了, 如果需要代碼的朋友可以給我發mail: [email protected]

# 回覆:《程序員》04年第7期試讀文章“程序世界的田園”系列之一 2004-08-18 11:52 AM ycl
學習 ing

# 回覆:《程序員》04年第7期試讀文章“程序世界的田園”系列之一 2004-08-23 4:31 PM guest
大凡能讓大多數人增長見識的
就是好文章!

# 回覆:《程序員》04年第7期試讀文章“程序世界的田園”系列之一 2004-11-04 12:12 AM yanqlv
我試過了,這麼着就可以把那個512字節文件寫到軟盤引導區上:
d:/>debug boot.bin
-w 100 0 0 1
-q



發表評論

標題:
大名:
網址:
評論 
   
發佈了50 篇原創文章 · 獲贊 2 · 訪問量 14萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章