ASM32 3 宏汇编
宏汇编
宏——具有宏名的一段汇编语句序列——宏定义时书写
宏指令——这段汇编语句序列的缩写——宏调用时书写
宏展开——宏指令处用这段宏代替的过程——宏汇编时实现
宏的功能强大,颇具特色
宏定义
1 | 宏名 macro [形参表] |
1 | main MACRO ;定义名为main的宏,无参数 |
宏调用
1 | 宏名 [实参表] |
1 | start: main ;宏调用,建立DS内容 |
- 宏调用的实质是在汇编过程中进行宏展开
- 宏展开的具体过程是:当汇编程序扫描源程序遇到已有定义的宏调用时,即用相应的宏定义体取代源程序的指令,同时用位置匹配的实参对形参进行取代
1 | ;宏定义 |

示例代码
hello.asm
1 | include hello.inc |
头文件和库的包含
1 | include hello.inc |
- **
include hello.inc**:包含一个名为hello.inc的头文件,通常包含宏、常量或其他汇编代码片段。 includelib user32.lib和 **includelib kernel32.lib**:包含 Windows API 的库文件,用于链接程序中调用的 Windows API 函数,如ExitProcess。
宏定义
1 | MyAdd2 macro n1,n2,n3 |
- **
MyAdd2 macro n1,n2,n3**:定义一个宏MyAdd2,接受三个参数n1、n2和n3。宏类似于函数,但在预处理阶段展开。 - **
mov eax,n1**:将第一个参数n1的值加载到eax寄存器中。 - **
add eax,n2**:将第二个参数n2的值加到eax寄存器中。 - **
;db "&n3&",0**:这行代码被注释掉了,可能是尝试将参数n3作为字符串插入,但被取消了。
函数定义
1 | .code |
- **
.code**:指示代码段的开始,所有可执行的指令都在这个段中定义。 - **
MyAdd1 proc n1:dword,n2:dword**:定义一个名为MyAdd1的过程(函数),接受两个DWORD类型的参数n1和n2。 - **
mov eax,n1**:将参数n1的值加载到eax寄存器中。 - **
add eax,n2**:将参数n2的值加到eax寄存器中。 - **
ret**:返回调用者,结束函数的执行。
主程序 START 的定义
1 | START proc |
- **
START proc**:定义一个名为START的过程,程序的入口点。 local @pt:Point和 **local @pt2:Point**:定义局部变量@pt和@pt2,它们的类型是Point结构体。- **
local @num:dword**:定义一个局部变量@num,类型为DWORD(32位无符号整数)。 - **
local @num2:byte**:定义一个局部变量@num2,类型为BYTE(8位无符号整数)。 - **
local @ary[10]:dword**:定义一个DWORD类型的数组@ary,包含 10 个元素。
1 | lea ebp,@ary |
- **
lea ebp,@ary**:将局部数组@ary的地址加载到ebp寄存器中。 - **
mov word ptr[@ary+2*2],1**:将数组@ary的第三个元素(@ary[2])设置为 1。2*2是偏移量,表示字节偏移。
1 | lea ebx,@pt |
lea ebx,@pt和 **lea ecx,@pt2**:将局部变量@pt和@pt2的地址分别加载到ebx和ecx寄存器中。ASSUME ebx:ptr Point和 **ASSUME ecx:ptr Point**:告诉汇编器ebx和ecx寄存器指向Point结构体。mov [ebx].x,0和 **mov [ebx].y,0**:将@pt结构体的x和y成员设置为 0。mov [ecx].x,0和 **mov [ecx].y,0**:将@pt2结构体的x和y成员设置为 0。ASSUME ebx:nothing和 **ASSUME ecx:nothing**:取消之前的假设。
1 | mov @num,0 |
- **
mov @num,0**:将局部变量@num设置为 0。 - **
mov @num2,1**:将局部变量@num2设置为 1。 - **
mov ebx,@num**:将@num的值加载到ebx寄存器中。 - **
mov al,@num2**:将@num2的值加载到al寄存器中(al是eax的低8位部分)。
1 | mov ebx,offset g_pt2 |
- **
mov ebx,offset g_pt2**:将全局变量g_pt2的地址加载到ebx寄存器中。 - **
ASSUME ebx:ptr Point**:假设ebx指向Point结构体。 - **
mov eax,[ebx].x**:将g_pt2的x成员值加载到eax寄存器中。 - **
mov eax,[ebx].y**:将g_pt2的y成员值加载到eax寄存器中(覆盖上一步的值)。 - **
ASSUME ebx:nothing**:取消假设。
1 | ASSUME eax:ptr Point3D |
- **
ASSUME eax:ptr Point3D**:假设eax寄存器指向Point3D结构体。 - 注释掉的行代码本来是用来从
ebx偏移量加载Point结构体的x和y成员。
函数调用和程序结束
1 | invoke MyAdd1,1,2 |
- **
invoke MyAdd1,1,2**:调用MyAdd1函数,参数为 1 和 2。该函数会将两个数相加,并返回结果。 - **
invoke ExitProcess,0**:调用 Windows API 函数ExitProcess,终止程序并返回状态码 0。 - **
ret**:返回调用者,结束START过程的执行。 - **
START endp**:标记START过程的结束。 - **
end START**:定义程序的入口点为START。
hello.inc
1 | .386 ;指令集 |
处理器和模式定义
1 | .386 ;指令集 |
- **
.386**:指示汇编器使用 80386 指令集,这意味着可以使用 32 位寄存器和指令。 - **
.model flat,stdcall**:指定使用平坦内存模型(即不分段),调用约定为stdcall。在stdcall调用约定中,函数的参数由调用者传递,函数本身负责清理堆栈。 - **
OPTION CASEMAP:none**:设置汇编器为大小写敏感模式。
宏定义和常量
1 | NULL EQU 0 |
- **
NULL EQU 0**:定义NULL常量,值为0,用于表示空指针或无效地址。 - **
MB_OK EQU 0**:定义MB_OK常量,值为0,用于表示MessageBox函数的OK按钮标志。
1 | MyMsg MACRO p1 |
- **
MyMsg MACRO p1**:定义一个名为MyMsg的宏,接受一个参数p1。宏在编译时展开为具体的代码片段。 - **
mov eax,eax**:这是一条无操作指令(NOP),它不改变任何状态。可用于占位或调试。
函数声明
1 | MessageBoxA proto hWnd:dword,lpText:dword,lpCaption:dword,uType:dword |
- **
MessageBoxA proto hWnd:dword,lpText:dword,lpCaption:dword,uType:dword**:声明MessageBoxA函数的原型,表示它接受四个DWORD类型的参数。MessageBoxA是 Windows API 用于显示一个消息框的函数。 - **
ExitProcess proto uExitCode:dword**:声明ExitProcess函数的原型,表示它接受一个DWORD类型的参数,用于终止当前进程。
常量区
1 | .const |
- **
.const**:开始定义只读常量区。 - **
MY_MSG db "Hello World!",0**:定义一个字符串常量MY_MSG,内容为"Hello World!",以空字符0结尾。 - **
MY_TITLE db "51asm",0**:定义一个字符串常量MY_TITLE,内容为"51asm",以空字符0结尾。这通常用于消息框的标题。
结构体定义
1 | Point struct 4 |
- **
Point struct 4**:定义一个名为Point的结构体,使用 4 字节对齐方式。 - **
test1 dword ?**:定义一个名为test1的成员,类型为DWORD(32 位无符号整数),初始值为不确定(?)。 x dword ?和 **y dword ?**:分别定义x和y成员,类型为DWORD,初始值为不确定。- **
Point ends**:标记Point结构体的结束。
1 | Point3D struct 4 |
- **
Point3D struct 4**:定义一个名为Point3D的结构体,使用 4 字节对齐方式。 - **
pt Point<?>**:定义一个名为pt的成员,类型为Point结构体,初始值为不确定。 - **
z dword ?**:定义z成员,类型为DWORD,初始值为不确定。 - **
Point3D ends**:标记Point3D结构体的结束。
初始化数据区
1 | .data |
- **
.data**:定义数据段,存放全局变量或已初始化的数据。 - **
g_pt1 Point<0,0>**:定义一个全局变量g_pt1,类型为Point结构体,并初始化x和y为0。 - **
g_pt2 Point<1,2>**:定义一个全局变量g_pt2,类型为Point结构体,并初始化x和y为1和2。 - **
g_pt3 Point<?>**:定义一个全局变量g_pt3,类型为Point结构体,但没有初始化。 - **
g_pt4 Point3D<<?,?>>**:定义一个全局变量g_pt4,类型为Point3D结构体,且pt和z都没有初始化。
注释部分
1 | ;g_ptArt Point 10 dup(<4,5>);数组 |
- **
g_ptArt Point 10 dup(<4,5>)**:注释掉的代码,表示定义一个包含 10 个元素的Point结构体数组,每个元素的x和y都初始化为4和5。 - **
g_pt2 Point3D<<?,?>,?>**:注释掉的代码,表示定义一个Point3D结构体,并初始化pt和z为不确定值。 - **
g_pt3 Point3D<<1,2>,3>**:注释掉的代码,表示定义一个Point3D结构体,pt初始化为Point<1,2>,z初始化为3。 - **
g_pt4 Point3D<<?,2>,3>**:注释掉的代码,表示定义一个Point3D结构体,pt.x初始化为不确定,pt.y初始化为2,z初始化为3。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Hexo!