给出一段简单的汇编
no_params_function:0000000000000000: 40 57 push rdi0000000000000002: 8B 05 00 00 00 00 mov eax,dword ptr [global_counter]0000000000000008: FF C0 inc eax000000000000000A: 89 05 00 00 00 00 mov dword ptr [global_counter],eax0000000000000010: 8B 05 00 00 00 00 mov eax,dword ptr [global_counter]0000000000000016: D1 E0 shl eax,10000000000000018: 5F pop rdi0000000000000019: C3 ret000000000000001A: CC int 3000000000000001B: CC int 3000000000000001C: CC int 3000000000000001D: CC int 3000000000000001E: CC int 3000000000000001F: CC int 3
汇编分析
1. 寄存器保存与恢复
可以看到有一个对应操作push rdi和pop rdi, 该操作是debug编译特有的操作,release编译则会优化掉。它的作用的保存rdi寄存器的值到该函数的栈顶,让这个函数内部可以随意使用rdi寄存器,而不会损坏函数外部的数据.
执行前: RSP = 0x7FFF0000
执行后: RSP = 0x7FFEFFF8
[0x7FFEFFF8] = RDI原始值
这里出现了RSP寄存器
2. RSP寄存器
在Windows操作系统的x86-64架构中,RSP寄存器(Register Stack Pointer) 是核心的栈指针寄存器,用于管理程序运行时的栈内存操作。RSP始终指向当前栈帧的顶部地址(即最新入栈数据的地址)。栈是一种“后进先出”(LIFO)的内存结构,用于存储函数调用时的临时数据(如局部变量、函数参数、返回地址等)。当数据压栈(push
)时,RSP值减小;数据出栈(pop
)时,RSP值增大,确保栈空间的动态分配与释放
3. 全局变量
0000000000000002: 8B 05 00 00 00 00 mov eax,dword ptr [global_counter]
汇编语句中用[]表示一个全局变量名,在链接阶段会转化成全局变量的地址
4. EAX寄存器
EAX(Extended Accumulator Register,扩展累加器寄存器)是x86/x86-64架构中的核心通用寄存器之一,主要用于算术运算、函数返回值存储及系统调用交互。其核心特性与功能如下:
1. 算术运算的缺省寄存器
累加器角色:加法(ADD
)、乘法(MUL
/IMUL
)等指令默认使用EAX存储操作数或结果
乘除法协作:
- 32位乘法时,结果的高32位存于EDX,低32位存于EAX;
- 除法中,EAX存放被除数,结果商存于EAX,余数存于EDX
2. 函数返回值与系统调用
在Windows/Linux系统调用及函数调用中,EAX通常存储返回值(如API函数执行结果)
3. I/O操作端口寻址
与DX寄存器配合,用于指定输入/输出设备的端口地址
这里使用到的是第二种用于存储函数的返回值
5. INT整型变量
-
dword ptr
:指定 32 位操作(int 类型) -
00 00 00 00
:地址占位符(链接时填充实际地址)
DWORD PTR 指定了32位操作,即一个整型
6. MOV语句
mov语句mov eax,dword ptr [global_counter]
即将[global_counter]地址内的取出一个32位值,存放进eax寄存器
7. INC和SHL语句
inc为加1指令,shl为左移指令相当于乘法
8. 二次加载
000000000000000A: 89 05 00 00 00 00 mov dword ptr [global_counter],eax
0000000000000010: 8B 05 00 00 00 00 mov eax,dword ptr [global_counter]
在汇编中INC和SHL计算中,有一个二次加载的动作,将eax和[global_counter]进行了交换。主要原因是debug模式下的特性,在release当中会被优化掉
- 确保内存可见性(多线程场景)
- 避免寄存器优化(方便调试)
- 内存访问断点支持
9. RET语句
跳出函数
10. 调试特征
- 末尾的
int 3
(CC
)指令是调试断点,用于填充函数对齐(Debug 模式常见) - Release 模式会优化掉冗余的寄存器保存和二次内存访问。
等价转化
通过如上分析将汇编主要做的操作注释如下
no_params_function:0000000000000000: 40 57 push rdi ; 保存 RDI 寄存器0000000000000002: 8B 05 00 00 00 00 mov eax, dword ptr [global_counter] ; 加载全局变量0000000000000008: FF C0 inc eax ; eax 值加 1000000000000000A: 89 05 00 00 00 00 mov dword ptr [global_counter], eax ; 存回全局变量0000000000000010: 8B 05 00 00 00 00 mov eax, dword ptr [global_counter] ; 重新加载全局变量0000000000000016: D1 E0 shl eax, 1 ; eax 左移 1 位(相当于乘 2)0000000000000018: 5F pop rdi ; 恢复 RDI 寄存器0000000000000019: C3 ret ; 返回(返回值在 eax 中)
转化成C语言:
int no_params_function(void){global_counter = global_counter + 1;return global_counter * 2;
}