1.32位環境簡介
在Dos下編匯編程序,我們可以管理系統的所有資源,我們可以改動系統中所有的內存,如自己改動內存控制塊來分配內存,自己修改中斷向量表來截獲中斷等,對其他操作也是如此,如我們對鍵盤端口直接操作就可以把鍵盤屏蔽掉,可以這樣來描述Dos系統:系統只有一個特權級別,在編程上講,任何程序和操作系統都是同級的,所以在Dos下,一個編得不好的程序會影響其他所有的程序,如一個程序把鍵盤口中斷關掉了,所有程序就都不能從鍵盤獲得鍵入的數據,直到任何一個程序重新打開鍵盤為止,一個程序陷入死循環,也沒有其他程序可以把它終止掉。Dos下的編程思路是“單任務”的,你只要認為你的程序會按照你的流程一步步的執行下去,不必考慮先後問題(當然程序可能會被中斷打斷,但你可以認為它們會把環境恢復,如果中斷程序沒有把環境恢復,那是他們的錯)。
在內存管理方式上,Dos匯編和Win32匯編也有很多的不同:Dos工作在實模式下,我們可以尋址1M的內存,尋址時通過段寄存器來制定段的初始地址,每個段的大小為64K,超過1M的部分,就只能把他作為XMS使用,也就是說,只能用作數據存放使用而無法在其中執行程序。
而Windows在保護模式下執行,這裡所有的資源對應用程序來說都是被“保護”的:程序在執行中有級別之分,只有操作系統工作在最高級--0級中,所有應用程序都工作在3級中(Ring3),
在Ring3中,你無法直接訪問IO端口,無法訪問其他程序運行的內存,連向程序自己的代碼段寫入數據都是非法的,會在Windows的屏幕上冒出一個熟悉的藍屏幕來。只有對Ring0的程序來說,系統才是全開放的。
在內存方面,Windows使用了處理器的分頁機制,使得對應用程序來說,所有的內存都是“平坦”的,你不必用一個段寄存器去指定段的地址,因為在保護模式下,段寄存器的含義是不同的(可以參見80386手冊方面的書籍),你可以直接指定一個32位的地址來尋址4GB的內存。
在程序結構方面,Windows程序也有很大的不同,它是“基於消息”的,你可以想象這樣一個常見的Windows窗口,上面有幾個按鈕,如果你用Dos編程的思路去考慮,你會發現實現它很困難:鼠標移動到窗口邊緣時拖動會改變窗口大小,鼠標點擊按鈕時再做要做的事,你會發現,你的程序自開始執行後就在等待,你不知道鼠標先會點什麼地方,實際上你是在等待所有可能的事情的發生。而在Dos下,你可以只顧自己先執行,需要用戶輸入時,再停下來,你不輸入我就不再執行,而且,我讓你輸入數據A你就不能輸入數據B。
好了,言歸正傳,因為以上是Win32編程的基礎,無論對Win32匯編還是VC++,它們都是一樣的,下面我們來看看有關Win32匯編的內容。
2.Win32ASM編譯器
Win32ASM的編譯器最常用的有兩種:Borland公司的Tasm5.0和Microsoft的Masm6.11以上版本,兩種編譯器各有自己的優缺點,Tasm帶了一個不大不小的Import庫,而Masm沒有帶,但Masm在代碼的優化上面好象比Tasm做得好,但它卻不帶Import庫。看來使用哪一種編譯器還是比較難選擇的,但Steve
Hutchesson給了我們一個答案,他為Masm建立了一個很全的Import庫,基本上包括了Windows絕大部分的Api函數,這些庫、include文件和其他工具還有Masm6.14版本一起做成了一個 Masm32編譯器 -- Masm32V5。這樣一來,我們用匯編編程就象用C一樣方便。
因為有了Masm32V5,所以就我個人而言,我推薦使用Masm作為Win32ASM的編譯工具,但Masm和Tasm的宏語法有很多的不同,我的這個教程是以Masm格式寫的。
3.Masm32的環境設置
在Win32編程中,由於Windows有很多的數據結構和定義,這些都放在include文件中,還有連接時要用到Import庫(通俗的講就是Windows提供的DLL文件中的函數列表,也就是告訴程序到哪裡去調用API函數),這些都放在include
和lib目錄中。我們在編譯時要指定以下的系統環境:
set include=\Masm32v5\Include
set lib=\Masmv5\lib
set path=\Masmv5\Bin
這樣編譯器就會到正確的路徑中去找 include 文件和 lib 文件。你可以自己在 autoexec.bat
文件中加上以上語句,為了產生Windows的PE格式的執行文件,在編譯和連接中要指定相應的參數:
編譯: Ml /c /coff 文件名.asm
連接: Link /SUBSYSTEM:WINDOWS OBJ文件名.obj 資源文件名.res
為了不在每次編譯時都要打這麼多的參數,我們可以用 nmake 文件來代為執行,nmake 是代碼維護程序,他會檢查 .asm .obj .exe .res
等文件的時間,如果你更新了源程序,他會自動執行編譯程序或連接程序產生相應的文件。你可以在文件名為 makefile
的文件中指定使用的編譯器和連接程序以及相應的參數,下面是一個 makefile 文件的例子:
NAME = Clock
OBJS = $(NAME).obj
RES = $(NAME).res
$(NAME).exe: $(OBJS) $(RES)
Link /DEBUG /SUBSYSTEM:WINDOWS $(OBJS) $(RES)
$(RES): $(NAME).rc
Rc $(NAME).rc
.asm.obj:
Ml /c /coff $(NAME).asm
文件告訴 nmake程序,程序名為 clock,產生 clock.exe 文件需要 clock.obj和 clock.res 文件,而產生 clock.res
文件需要 clock.rc 文件,產生 clock.obj 文件要用到 clock.asm 文件,至於是否需要執行 ml, link 和
rc,程序會根據文件的時間自動判斷。