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,程式會根據檔案的時間自動判斷。