給出一段簡單的匯編
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;
}