Jack's第一個Win32彙編程式HelloWorld
本文已被更新,請看新版文章
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
Hello.asm檔案的內容如下:
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 第一部分:模式和源程式格式的定義語句
.386 ; 指令集
.model flat,stdcall ; 工作模式
option casemap:none ; 格式
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; Include 檔案定義
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
include windows.inc
include user32.inc
includelib user32.lib
include kernel32.inc
includelib kernel32.lib
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 資料段
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
.data
szCaption db 'A MessageBox !',0
szText db 'Hello, World !',0
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 程式碼段
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
.code
start:
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,stdcall
option 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 NULL
push offset szText
push offset szCaption
push MB_OK
call 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:dword
b) 處理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位組合語言程式設計》(第二版)第三章
相關文章
- Jack架設WIN32彙編程式的開發環境Win32開發環境
- Jack整理的Win32彙編基礎知識Win32
- 彙編程式碼Helloworld
- 13_Linux第一個程式HelloWorldLinux
- win32下彙編程式碼結構學習Win32
- 用eclipes寫第一個HelloWorld
- go語言入門教程分享:第一個程式:HelloWorldGo
- JAVA開發環境搭建及變數配置(利用eclipse編寫第一個Java程式HelloWorld)Java開發環境變數Eclipse
- 編寫第一個Qt程式QT
- Jack's側方移位全攻略
- Jack對分支迴圈語句偽指令反彙編前後的比較
- 【擁抱元宇宙】建立你的第一個Unity程式HelloWorld,併發布元宇宙Unity
- kubernetes學習第一篇-k8s安裝以及HelloWorldK8S
- 初識彙編-第一篇
- WIN32 手動編譯Win32編譯
- windows搭建彙編程式IDEWindowsIDE
- STM彙編程式設計程式設計
- 機器語言編寫helloworld
- win32下vs2013彙編傳參和區域性變數棧的分配Win32變數
- CatFly【彙編程式碼還原】
- iOS彙編入門教程(二)在Xcode工程中嵌入彙編程式碼iOSXCode
- Linux C++ 開發2 - 編寫、編譯、執行第一個程式LinuxC++編譯
- 在VS2019使用MASM編寫彙編程式ASM
- 彙編程式開發環境搭配開發環境
- STM32彙編程式設計程式設計
- 幾個彙編入門小例子
- 基礎入門: 編寫第一個 Go 語言程式Go
- 彙編
- 位元組碼程式設計 Byte-buddy 篇 一 基於Byte Buddy語法建立的第一個 HelloWorld程式設計
- # 編寫第一個Chrome ExtensionChrome
- IOS 初級開發入門教程(二)第一個HelloWorld工程及StoryBoard使用iOS
- S5PV210 | 裸機彙編LED流水燈實驗
- 彙編入門第一篇,小白也能看懂
- nasm彙編ASM
- 彙編命令A
- 讓我們寫一個 Win32 文字編輯器吧 - 1. 簡介Win32
- 編寫第一個 .NET 微服務微服務
- MyBatis第一個程式MyBatis