本文已被更新,請看新版文章
Jack整理的Win32彙編基礎知識
http://blog.csdn.net/magus_yang/archive/2007/04/05/1552930.aspx
標 題: Jack's第一個Win32組譯工具HelloWorld
作 者: Jack Yang時 間: 2007-02-26 1:02鏈 接: http://blog.csdn.net/magus_yang/archive/2007/02/26/1514439.aspxHello.asm檔案的內容如下:;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; 第一部分:模式和來源程式格式的定義語句 .386 ; 指令集 .model flat,stdcall ; 工作模式 option casemap:none ; 格式;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; Include 檔案定義;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>include windows.incinclude user32.incincludelib user32.libinclude kernel32.incincludelib kernel32.lib;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; 資料區段;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> .dataszCaption db 'A MessageBox !',0szText db 'Hello, World !',0;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>; 程式碼片段;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> .codestart: invoke MessageBox,NULL,offset szText,offset szCaption,MB_OK invoke ExitProcess,NULL;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> end start ; 指定程式的入口
1.
第一部分
模式和來源程式格式的定義語句第一行 指定使用的指令集(編譯器使用)Win32環境工作在80386及以上的處理器中,所以必須定義.386。如果程式(VxD等驅動程式)中要用到特權指令,那麼必須定義.386p。第二行 定義程式工作的模式(包括記憶體模式、語言模式、其它模式)對Win32程式來說,只有一種記憶體模式,即flat(平坦)模式。Win32 API調用使用的是stdcall格式,所以Win32彙編中必須在.model中加上stdcall參數。第三行 option語句 由於Win32 API中的API名稱區分大小寫,所以必須定義option casemap:none,來表明程式中的變數和子程式名對大小寫敏感。
2.
包含全部段的來源程式結構:.386.model flat,stdcalloption casemap:none<一些include語句>.stack [堆棧段的大小].data<一些初始化過的變數定義>.data?<一些沒有初始化過的變數定義>.const<一些常量定義>.code<代碼><開始標記><其他語句>end 開始標記
3.
段的定義資料區段 .data 已初始化資料區段,可讀可寫的已定義變數;當程式裝入完成時,這些值就已經在記憶體中; 資料定義在.data段中會增加可執行檔的大小; .data段一般存放在可執行檔的_DATA節區(Section)內; .data? 未初始化資料區段,可讀可寫的未定義變數,在可執行檔中不佔空間; 這些變數一般作為緩衝區或者在程式執行後才開始使用。 資料定義在.data?資料區段中不會增加可執行檔的大小; .data?段一般存放在可執行檔的_BSS節區內; .const 常量,可讀不可寫的變數; 程式碼片段 .code 所有的指令都必須寫在程式碼片段中; Win32中,資料區段是不可執行檔,只有程式碼片段有可執行檔屬性; 對於運行在特權級3的應用程式,.code段不可寫。除非把可執行檔PE頭部中的屬性位改成可寫; 對於運行在特權級0的程式,所有的段都有讀寫權限,包括程式碼片段; .code程式碼片段一般存放在可執行檔的_TEXT節區內; 堆棧段 .stack 與DOS彙編不同,Win32彙編不必考慮堆棧。系統會自動分配堆棧空間; 堆棧段的記憶體屬性是可讀寫並且可執行; 靠動態修改代碼的反跟蹤模組可以拷貝到堆棧中去邊修改邊執行; 緩衝區溢位技術也會用到這個特性;
4.
叫用作業系統功能的方法:DOS下作業系統的功能通過各種非強制中斷來實現。 應用程式叫用作業系統功能將經曆如下三個過程: 把相應的參數放在各個寄存器中再調用相應的中斷; 程式控制權轉到中斷中去執行; 完成以後通過iret中斷返回指令回到應用程式中; DOS下調用系統功能方法的缺點: 所有的功能號定義是難以記憶的數字; 80x86系列處理器能處理的中斷最多隻能有256個; 通過寄存器來傳遞參數,對於參數較多的函數很不方便;Win32下 系統功能模組放在Windows的動態連結程式庫(DLL)中 作為Win32 API核心的3個DLL: KERNEL32.DLL 系統服務功能。 GDI32.DLL 圖形裝置介面。 USER32.DLL 使用者介面服務。 常用API的參數和函式宣告,查看文檔《Microsoft Win32 Programmer's Reference》
5.
Win32 API
的函數原型聲明函數原型聲明的彙編格式如下:函數名 proto [距離] [語言] [參數1]:資料類型, [參數2]:資料類型,......proto是函式宣告的偽指令距離可以設定為NEAR、FAR、NEAR16、NEAR32、FAR16或FAR32,由於Win32中只有一個平坦的段,無所謂距離,所以在定義時可以忽略距離。語言類型可是使用.model所定義的預設值。 以訊息對話方塊函數MessageBox為例C格式如下:int MessageBox( HWND hWnd, // Handle to owner window LPCTSTR lpText, // text in message box LPCTSTR lpCaption, // message box title UINT uType // message box style ); 彙編格式如下:MessageBox Proto hWnd:dword,lpText:dword,lpCaption:dword,uType:dword或者寫為MessageBox Proto :dword,:dword,:dword,:dword編譯器只對參數的數量和類型感興趣,參數的名稱只是增加可讀性,所以可以省略。對於組合語言來說,Win32環境中的參數實際上只有一種類型,就是一個32位的整數(dword,double word),雙字,四位元組。
6.
調用Win32 API調用API有如下兩種方法:1) invoke MASM提供的偽指令; invoke偽指令的好處就是能夠提高代碼的可讀性,減少錯誤; invoke做了下面三件事: 在編譯的時候,由編譯器把invoke偽指令展開成相應的push指令和call指令; 進行參數數量的檢查工作; 如果帶的參數數量和聲明時的數量不符,編譯器會報錯;2) push和call的組合80386處理器的指令 invoke MessageBox,NULL,offset szText,offset szCaption,MB_OK也可寫為push NULLpush offset szTextpush offset szCaptionpush MB_OKcall MessageBox
7.
Win32 API
函數傳回值的處理方法對於組合語言來說,Win32 API函數傳回值的類型只有dword一種類型,它永遠放在eax中。如果要返回的內容在一個eax中放不下,Win32 API採用如下方法來解決:a) 一般是eax中返回一個指向返回資料的指標;b) 在調用參數中提供一個緩衝區地址,資料直接返回到這個緩衝區中去。類似變參的概念;
8.
與字串相關Win32 API
的分類在Win32環境中,根據兩個不同的字元集(ANSI字元集和Unicode字元集),可以把和字串相關的API分成兩類:a) 處理ANSI字元集的Win32 API函數函數名稱的尾部帶一個“A”字元;ANSI字串是以NULL結尾的一串字元數組,每一個ANSI字元佔一個位元組的寬度;MessageBoxA Proto hWnd:dword,lpText:dword,lpCaption:dword,uType:dwordb) 處理Unicode字元集的Win32 API函數函數名稱的尾部帶一個“W”字元; 每一個Unicode字元佔兩個位元組的寬度,所以可以同時定義65536個不同的字元; MessageBoxW Proto hWnd:dword,lpText:dword,lpCaption:dword,uType:dword Windows 9x系列不支援Unicode版本的API,絕大多數的API只有ANSI版本。只有Windows NT系列才完全支援Unicode版本的API。為了編寫在幾個平台中都能通用的程式,一般應用程式都使用ANSI版本的API函數集。 提高程式可移植性的一個方法:一般在來源程式中不直接指明使用Unicode還是ANSI版本,而是使用宏彙編中的條件彙編功能來統一替換。比如,在標頭檔中做如下定義:if UNICODE MessageBox equ <MessageBoxW>else MessageBox equ <MessageBoxA>endif然後在來源程式的頭部指定UNICODE=1或UNICODE=0,重新編譯後就能產生不同的版本。 未完,待續。。。 參考資料:羅雲彬的《Windows環境下32位組合語言程式設計》(第二版)第三章