首先,讓我們看看壹個“復雜的”Win32匯編程序。
該程序用於顯示壹個消息框
-
;文件名:3.asm
.386
。模型平面,標準呼叫
NULL equ 0
MB_OK equ 0
ExitProcess PROTO :Dword
消息框A PROTO :DWORD,:DWORD,:DWORD,:DWORD
includelib kernel32.lib
includelib user32.lib
。數據
szText db“妳好,世界!”,0
szCaption db "Win32Asm ",0
。密碼
開始:
按下MB_OK
lea eax,szCaption
推送eax
李eax,深圳文本
推送eax
推送空值
呼叫messageboxa
異或運算
推送eax
調用exitprocess
結束開始
-
編譯鏈接:
它分以下兩步進行:
ml /c /coff 3.asm
link/subsystem:Windows/libpath:d:\ masm 7 \ lib 3 . obj
第壹步是編譯並生成3.obj文件。
/c表示只編譯,不鏈接。
/COFF表示生成COFF格式的目標文件。
第二步是鏈接生成3.exe文件。
/subsystem:windows表示生成壹個windows文件。
/libpath:d:\masm7\lib表示導入庫的路徑是:d:\masm7\lib。
安裝Masm32後,導入庫位於Masm32\Lib目錄中。
還可以設置環境變量Lib的值:在dos提示符下鍵入Set Lib=d:\masm7\lib,這樣“link”就可以簡單地寫成:
Link /subsystem:Windows 3.obj,試想壹下,在程序調試的過程中,修改源程序是常有的事,每編譯壹個鏈接都要帶上/libpath:...會有多討厭。當然,我們也可以直接給出導入庫在源程序中的位置,這樣便於鏈接,如下:
include lib d:\ masm 7 \ lib \ kernel 32 . lib
包括lib d:\masm7\lib\user32.lib
-
執行:在dos提示符下鍵入3,回車,會出現壹個消息框,哈哈,壹個真正的Win32程序!
-
深度分析:
看源程序,有兩行:調用messageboxa \調用exitprocess。大家都知道,這是壹個子程序調用,但是我們沒有寫這樣的子程序。其實這些都是API函數。作為壹個函數,我們在調用時可能需要傳遞壹些參數給函數。程序如何知道傳遞的是什麽參數,什麽類型?由函數原型定義,如下所示:
ExitProcess PROTO :Dword
消息框A PROTO :DWORD,:DWORD,:DWORD,:DWORD
可以看到,ExitProcess有壹個參數,MessageBoxA有四個參數,都是Dword類型。
在Win32中,參數通過堆棧傳遞。像MessageBoxA這樣的函數有四個參數。是左邊第壹個還是右邊第壹個?。模平,stdcall給出了答案。Stdcall指定參數從右向左推入堆棧,子程序返回時完成堆棧的調整。不需要在源程序中使用“add sp,value”來保持堆棧平衡。對於MessageBox,它在API手冊中的定義如下:
int MessageBox(
HWND hWnd,//所有者窗口的句柄
LPCTSTR lpText,//消息框中文本的地址
LPCTSTR lpCaption,//消息框標題的地址
UINT uType & ampn
妳正在看的匯編語言是:妳好,世界!Win32匯編程序小程序。
bsp//消息框的樣式
)
;所以接下來是我們的節目片段:
按下MB_OK
lea eax,szCaption
推送eax
李eax,深圳文本
推送eax
推送空值
呼叫messageboxa
看上面的程序,不難想到,寫程序時如果少壹個數據壓入堆棧,那將是致命的錯誤。能不能把檢查參數個數和電腦匹配的任務交給妳?這是可能的,INVOKE指令可以幫助我們完成這項工作。如果您的參數數量不正確,連接器將給出壹個錯誤提示。因此,強烈建議您使用invoke而不是call來調用子例程。當然,這不是絕對的。使用上面的指令invoke可以縮寫成下面這樣,看起來簡潔多了,也方便了錯誤檢查!
調用messageboxa,NULL,addr szText,addr szCaption,MB_OK
另外,NULL和MB_OK是常量。這樣的常數很多,結構也很多。如果壹開始就在我們的程序裏寫這麽多東西,可能壹下子就被嚇到了,而且容易出錯,不方便看程序的主要部分。hutch編譯的Windows.inc包含WIN32編程所需的常量和結構的定義。我們可以簡單地用include指令將這些常量和結構定義插入到我們的文件中:
include d:\ masm 32 \ include \ windows . Inc
但是Windows.inc不包含函數原型的語句,需要從其他頭文件中獲取函數原型的語句,比如messageboxa的原型在user32.inc文件中聲明,exitprocess在kernel32.inc文件中聲明。這些頭文件放在\masm32\include文件夾中。
此外,要使用Windows.inc,必須使用選項casemap:none,這意味著告訴MASM區分符號的大小寫,例如,start和START是不同的。否則壹個小程序可能會犯上百個錯誤!
剩下的我就不細說了。此時,上述程序可以修改如下:
-
;最後的結果
.386 ;表示要使用386指令。
。模型平面,stdcall32位程序,用平面!;標準呼叫
選項案例圖:無;區分大小寫
包括Windows.inc包括常數和結構定義。
包括kernel32.inc函數原型聲明
包括user32.inc
include lib kernel 32 . lib;使用的簡介庫
includelib user32.lib
。數據;數據區,定義2個字符串。
szText db“妳好,世界!”,0
szCaption db "Win32Asm ",0
。代碼;代碼開始執行位置
開始:
調用MessageBox,NULL,addr szText,addr szCaption,MB_OK
;調用MessageBoxAPI函數
調用ExitProcess,NULL。程序出口
結束開始;結束
-
編譯鏈接:
ml/c/coff/I d:\ masm 7 \ include 3 . ASM;請註意,開關字符區分大小寫。
link/subsystem:Windows/libpath:d:\ masm 7 \ lib 3 . obj
/I d:\masm7\include指示*的位置。inc文件,或者可以設置環境變量Set include=d:\masm7\include來簡化操作,也可以明確指出*的位置。inc在該計劃中。
以上所有指令都是用來完成編譯環節的,但實際上也可以使用壹條指令,如下:
ml/coff/I d:\ masm 7 \ include 3 . ASM/link/subsystem:Windows/libpath:lib
如果*。inc和導入庫清楚地表明它們在源程序中的位置,這可以簡化為:
ml /coff 3.asm /link /subsystem: