我對組裝非常陌生,所以請多多包涵。
我有這段代碼通過參考一個函式來傳遞一個值以修改它:
[MethodImpl(MethodImplOptions.NoOptimization | MethodImplOptions.NoInlining)]
static void Main()
{
int a = 5 ;
Modify(ref a);
Console.WriteLine(a);
}
[MethodImpl(MethodImplOptions.NoOptimization | MethodImplOptions.NoInlining)]
static void Modify (ref int a )
{
a = 77 ;
}
該代碼是生成的程式集
Program.Main()
L0000: push ebp
L0001: mov ebp, esp
L0003: push eax
L0004: xor eax, eax
L0006: mov [ebp-4], eax ******* (the confusing part 1 )
L0009: mov dword ptr [ebp-4], 5
L0010: lea ecx, [ebp-4]
L0013: call dword ptr [0xa9dc6ac]
L0019: mov ecx, [ebp-4]
L001c: call System.Console.WriteLine(Int32)
L0021: mov esp, ebp
L0023: pop ebp
L0024: ret
我的問題是:在指令 L0006 : mov [ebp-4], eax 這會將暫存器 eax 的值復制到 Ebp-4 指向的記憶體位置,但 Ebp-4 不指向任何東西?我錯過了什么?
uj5u.com熱心網友回復:
發布未優化的程式集會使事情變得更加混亂,但基本上,這些行,
push ebp
mov ebp, esp
ebp指向此函式堆疊框架的頂部附近。(即將EBP設定為幀指標)。
在函式入口處[esp]有回傳地址。Anypush將首先遞減esp4(假設是 32 位環境)并將值存盤在新的[esp]. 用push ebp, (減 4) 存盤,[esp]的舊值ebp并生成.mov ebp, espebp = esp
push eax
該指令只是為一個 dword ( ) 大小的區域變數sub esp, 4保留堆疊空間的一種緊湊方法。int在此之前,ESP = EBP,因此新空間位于 address ebp-4,無論運行時發生什么。
xor eax, eax ; eax = 0
mov [ebp-4], eax ; store EAX, possibly to zero-init int a ?
mov dword ptr [ebp-4], 5
您可以忽略前兩行。它在那里是因為您決定關閉優化,這通常會使事情變得更加混亂。最后一行mov dword ptr [ebp-4], 5覆寫由 寫入的值mov [ebp-4], eax。
你不能寫mov dword ptr [ebp], 5,因為它存盤了我前面提到[ebp]的舊值。ebp
根據 fastcall 呼叫約定,函式呼叫在 ECX 中獲取其引數。該暫存器加載了指向使用[ebp-4]LEA 指令的指標:
lea ecx, [ebp-4] ; ECX = ebp-4. (Not [ebp-4], it's not a load)
在 C 語言中,它&a與 區域變數的地址完全一樣。LEA 計算地址,然后將其放入目標暫存器中,而不是使用它從記憶體中加載。
請注意,在第一個函式呼叫回傳后,該記憶體被重新加載:
mov ecx, [ebp-4] ; load a as the arg for the next function call
call System.Console.WriteLine(Int32)
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/437348.html
