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!