今天要回頭看第一篇的 Hello World 程式,經過這麼多篇不知道大家有沒有覺得 Hello World 親切許多,回去看 Hello World 絕對不是我沒東西寫了。
Hello World 程式:
; 定義數據段,存放數據
data segment
; db 是定義接下來的數據為單字節的意思,
; '$'是字串的結尾,類似 C 的 '\0'
string db 13,10,'Hello World!',13,10,'$'
data ends
; 定義代碼段,執行的程式碼
code segment
; 偽指令,告訴組譯器代碼段的對應
assume cs:code, ds:data
start:
mov ax, data ; 將 data 的地址放到 ax 暫存器
mov ds, ax ; 將 ax 的值放到 ds 暫存器
lea dx, string ; 將 string 變數的地址放進 dx 暫存器
mov ah, 09h ; 09h 對應的是將字串輸出到螢幕上
int 21h ; 調用系統功能,對應的是目前 ah 暫存器中的值
mov ax, 4c00h ; 退出程式
int 21h ; 調用系統功能
code ends
end start ; 讓組譯器知道程式的進入點
組合語言的指令分為一般指令和偽指令,一般指令是指可以直接被對應成機器碼的指令,例如 mov、add,而偽指令是給編譯器看的,實際上並不會被編譯為機器碼。
segment 和 ends 用來定義一個段,一個程式最少需要代碼段才能正常執行,段的名稱是可以自訂的,並不一定要用 data 或 code。
assume 用於告訴編譯器段暫存器和段的對應關係,例如 ds:data 就代表 data 是數據段,比較難理解的是 assume 並不會改變段暫存器內容,程式中還是需要用 mov 指令將 data 的地址指定給 ds 暫存器,Google 後找到的內容是寫 assume 會影響編譯後執行檔開頭的描述訊息,但並不是很理解,有經驗的大大可以幫我補充一下。
end 代表程式的結尾,而 end 後面接著的標號就是程式的入口點,cs 和 ip 不像 ds 需要在程式內指定,作業系統將 CPU 控制權交給程式時,會自動把 CS 和 IP 設在程式的入口點上,入口標號同樣也可以自訂名稱,不一定要用 start。
標號代表一個記憶體地址,可以搭配其他指令使用,例如 end、jmp,等等。
在講 int 21h 之前要先知道程式是如何執行的,電腦開機後首先執行 BIOS 程式,接著才會載入作業系統,之後 CPU 的控制權就會交給作業統,而要執行我們的程式,需要作業系統再把控制權交給程式,程式結束後返還控制權,因為 DOS 一次只能執行一個程式,所以如果程式結束後沒有正確的返還控制權給作業系統,電腦就會卡住不動了。
程式中的 int 21h 就是用來結束程式並將 CPU 控制權還給作業系統,int 21h 用於調用系統功能,而要調用的功能則看 ah 暫存器中的值,例如 int 21h 的上一段指令 mov ax, 4c00h
,4c 對應的功能就是退出程式,中斷在 DOS 作業系統是非常重要的概念,之後會再詳細介紹。
第一篇介紹過可以使用 masm
和 link
編譯程式,但每次都需要執行兩個步驟實在麻煩,這裡介紹一個更快速的方法。
ml hello.asm
ml 等於 masm + link,一個步驟就完成編譯。
執行檔 .exe 是如何被加載執行的呢?
其中 PSP 是一個 256 字節大小的區域,位於程式之前,主要用於程式和 DOS 作業系統間的資訊交流,程式加載的過程中會將 DS 設在 PSP 的段地址上,所以程式中才需要另外將 DS 指定到我們定義的數據段上,因為 PSP 和程式位於不同的段上。
PSP 示意圖:
不知道大家看懂 Hello World 了嗎?
寫到第九篇才算完整介紹完 Hello World,疑~不對好像還有變數沒講,這真是一條艱難的路阿!!!,哈哈哈。
今天就到這裡摟,感謝大家觀看。