在解釋的代碼,所述PUSH
操作碼的功能,必須定義:
它遞減堆棧指針,然後存儲在堆棧的頂部的源操作數。
所以,首先,下面兩行創建一個標準的堆棧幀。他們分配給EBP
的堆棧指針(ESP
)當前位置,這是通過引用它們相對於EBP
(所謂基本指針)訪問堆棧上的局部變量非常有用。
push ebp //put in top the stack, right?
mov ebp, esp //mov the value esp to ebp
現在EBP
指向當前堆棧位置。
下面的行推ECX
到堆棧(ESP
) - 降低ESP
由4. EBP
保持不變。
push ecx // ok...
因爲EBP
調用時這個函數減去4(見上文),將下面的行
mov eax, [ebp+8] //What's ebp+8?
移動第一參數EBP+8
到EAX
仍然指向堆棧中的位置。
記住:
- 進入時:ESP = X(=返回地址推入有由
CALL
)PUSH EBP
- 後:ESP = X-4(=返回地址是在ESP + 4)
- 然後
EBP
被設定爲:ESP = X-4(EBP = ESP = X-4(現在指向EBP的舊值))
- 所以返回地址位於和第一參數位於
EBP+8
(32位= 4字節)。
等等這樣的:
add eax, [ebp+0Ch] //What's ebp+0Ch?
[EBP+0Ch]
是第二個參數...
add eax, [ebp+10h] //What's ebp+10h
[EBP+10h]
是第三個參數。
因此,以下行將EAX
複製到堆棧上的32位值。這是ECX
,這是PUSH
'd到上面的堆棧。
mov [ebp-4], eax //What's ebp-4
複製回來以下行ECX
局部變量是很沒用......
mov eax, [ebp-4]
現在堆棧幀通過複製EBP
回ESP
恢復。
mov esp, ebp
pop ebp
下面一行只是做一個32位附近回報給調用者:
retn
我認爲這解釋了這個子程序的功能相當不錯。
棧也是普通的內存。所以要操縱堆棧中的值,你也可以用[esp]來解決它。進入你的程序後,[esp]指向返回地址(堆棧頂部)。 'push ebp'將存儲舊的'ebp'值,[esp]現在指向舊的ebp,[esp + 4]是返回地址(堆棧「向下增長」,'push dword value'做'esp - = 4') 。然後在調用你(第一個參數)之前,'[esp + 8]'是由棧上的調用者推送的dword。當你將'esp'複製到'ebp'時,你現在可以用'[ebp + 8]'來解決它。在調試器中運行它,將存儲器窗口指向esp區域,然後觀察那裏的值。 – Ped7g
什麼使得這段代碼是什麼? –