1、8086匯編源程序從編寫到執行的過程
前面介紹過通過debug模式來進行匯編程序的編寫和調試。但是隨着深入學習,所編寫的匯編程序會越來越復雜,而通過debug的A命令去逐條編寫匯編指令是非常低效的。
因此,這里將要介紹8086匯編源程序這一概念,使得我們可以通過文本的方式編寫匯編程序,並通過一系列的措施將其轉化為最終的二進制可執行程序。
一個匯編源程序從編寫到執行大概可以分為幾個階段:
1. 開發者編寫文本形式的匯編源程序
2. 對匯編源程序進行編譯並生成目標文件、對目標文件進行鏈接並生成可執行文件
3. 運行可執行文件
下面通過一個簡單例子來詳細說明(以windows操作系統下的masm5環境舉例):
1. 編寫匯編源程序
通過系統自帶的記事本或者更高級的文本編輯器編寫文本形式的匯編源程序,將其命名為demo.asm,程序內容如下:
assume cs:codesg codesg segment mov ax,0123H mov bx,0456H add ax,bx add ax,ax mov ax,4c00H int 21H ;中斷退出程序 codesg ends end
2. 對匯編源程序進行編譯、鏈接
編譯:
通過命令行運行masm.exe,先讓用戶輸入需要編譯的匯編源文件的本地文件地址(Source filename :)。如果文件在當前工作路徑下可以僅輸入文件名(例如 demo.asm),否則就需要輸入絕對地址路徑(例如 c:\MASM\ASM\demo.asm)。另外,如果源程序文件的默認后綴拓展名為[.ASM],如果是.txt之類的文件,則需要輸入全名(例如 c:\MASM\ASM\demo.txt)。
接着會讓用戶輸入所生成的.obj目標文件的存放路徑以及名稱(Object filename :),例如 c:\MASM\ASM\demo.obj。后面的Source listing和Cross-reference能夠讓masm編譯器生成編譯過程中的中間結果文件,這里可以直接回車跳過,不去讓編譯器生成。
如果沒有出現錯誤日志(0 Errors),此時可以在Object filename指定的路徑下找到所生成的目標文件。

鏈接:
通過命令行執行link.exe,先讓用戶輸入需要進行鏈接的目標文件(Object Modules:) 例如 c:\MASM\ASM\demo.obj。絕對路徑/相對路徑以及文件全名的使用和masm.exe進行編譯時規則保持一致。
接着需要用戶輸入所生成的.exe可執行文件的存放路徑以及名稱(Run File :),例如 c:\MASM\ASM\demo.exe。后面的List File以及Libraries用於指定和obj文件進行鏈接的子程序以及庫程序,由於這里程序很簡單,並不需要用到,選擇回車直接跳過。
如無意外,將會在指定位置出現demo.exe可執行文件。(no stack segment警告(而不是錯誤)程序中沒有棧段,這是個不好的習慣,但這里先暫時忽略掉)
3. 運行可執行文件
通過命令行窗口運行demo.exe,會發現沒有什么效果。這是因為我們的程序中只有對CPU寄存器的簡單操作,在執行完之后程序便立即結束了,並沒有常駐。
對於這種執行完成會立即退出的匯編程序,可以通過debug.exe對其進行調試,以了解中間的執行過程。
使用debug命令將可執行文件路徑作為參數執行,可以對該可執行文件進行調試(例如:debug c:\masm\asm\demo.exe)。從截圖中可以看到,通過U指令反編譯,文本中的源程序被准確的轉換為了二進制可執行程序。

2、8086匯編源程序語法介紹
匯編源程序的內容大致可以分為兩種,一種是與機器指令對應的可執行指令(例如:mov ax,0123H add ax,bx等),另一種是偽指令(例如: codesg segment)。
偽指令和可執行指令的區別在於,可執行指令是和CPU的硬件掛鈎的,會被匯編器轉換為對應的機器指令;而偽指令的作用是為了控制編譯過程而存在的,其僅由匯編器處理,沒有對應的機器指令,不會被CPU執行。
assume cs:codesg codesg segment mov ax,0123H mov bx,0456H add ax,bx add ax,ax mov ax,4c00H int 21H ;中斷退出程序
codesg ends
end
以前面的源程序舉例分析:一個好的源程序需要具備基礎的層次結構,而匯編源程序通過源程序層面上的段來進行層次划分的。可以在一個段中存放代碼,數據或者將某一個段當作棧來使用,這也和前面介紹的CPU的幾種類型的段寄存器對應。
因為程序是結構化的,所以要理解上面這段程序不能完全從上到下的進行理解,而是要進行有機的拆解:
首先,我們定義了一個段,名為codesg,段的程序界限由segment和ends這對關鍵字控制,也就是 codesg segment 。。。 codesg ends,在這兩行語句中間的所有內容都屬於這個段。codesg段是作為代碼段來使用的,所以內容都是程序指令。
接着明確的告訴匯編器,將codesg作為程序段(cs)來使用,也就是第一行assume cs:codesg的意義,關鍵字為assume cs:。
最后指明程序的結束,也就是最后一行end關鍵字的作用。
這里segment 、ends、end等關鍵字構成的指令都是偽指令。
其它需要注意的點:
1. 8086匯編的注釋是通過分號;來識別的,匯編器會將每一行分號后面的內容當作注釋,自動忽略后面一整行的內容。
2. 在codesg的段內容中出現了一個前面沒有出現過的指令int。int指令代表着中斷(interrupt),由於當前程序是由DOS調用執行的,而mov ax,4c00H int 21H這兩句指令就是通過中斷結束當前程序並返回到DOS中。關於中斷的內容會在后續的博客里做詳細介紹。
3. 和高級語言一樣,匯編語言中的錯誤也分為語法錯誤和邏輯錯誤兩種,語法錯誤包括未識別的符號、變量等;而邏輯錯誤包括棧越界溢出、錯誤的跳轉等。一般來說,能被編譯器在編譯時直接發現的錯誤都是語法錯誤,而更深層次的邏輯錯誤就只能靠開發人員自己想辦法避免了。
