2012-04-22 205 views
26

鑑於這一段代碼:基指針和堆棧指針

 swap: 

      push ebp ; back up the base pointer, 
      mov ebp, esp 
      ; push the context of the registers on the stack 

      push eax 
      push ebx 
      push ecx 
      push edx 

      mov eax, [ebp+8] ; address of the first parameter 
      mov ebx, [ebp+12] ; address of the second parameter 
      mov dl, [eax] 
      mov cl, [ebx] 

      mov [eax], cl 

      mov [ebx], dl 

      ; restore the context of the registers from the stack 

      pop edx 
      pop ecx 
      pop ebx 
      pop eax 
      ; restore the ebp 
      pop ebp 
      ret 

(這僅僅是該方法之前,我們推第一和堆棧上的第二參數。)

我的問題是:爲什麼我們將8添加到基址指針中以獲得第一個參數的地址,然後是12?

我得到的事實是,他們是dword,因此他們每個人都是4字節..所以從ebp + 8到ebp + 12它使得敏感。但爲什麼第一個是ebp + 8?因爲如果ESP指向堆棧的頂部,則mov ebp,esp表示EBP指向堆棧的頂部。然後我們在棧上推入4個值:eax,ebx,ecx和edx。爲什麼EBP + 8指向第一個參數?

回答

39

當函數被調用時,堆棧的樣子:

+-------------+ 
| Parameter 2 | 
+-------------+ 
| Parameter 1 | 
+-------------+ 
| Return Addr | <-- esp 
+-------------+  

然後經過 「堆棧幀」 設置:

+-------------+ 
| Parameter 2 | <-- [ebp + 12] 
+-------------+ 
| Parameter 1 | <-- [ebp + 8] 
+-------------+ 
| Return Addr | 
+-------------+  
| saved ebp | <-- ebp 
+-------------+ <-- esp 

現在上下文被保存:

+-------------+ 
| Parameter 2 | <-- [ebp + 12] 
+-------------+ 
| Parameter 1 | <-- [ebp + 8] 
+-------------+ 
| Return Addr | 
+-------------+  
| saved ebp | <-- ebp 
+-------------+ 
| saved eax | 
+-------------+  
| saved ebx | 
+-------------+  
| saved ecx | 
+-------------+  
| saved edx | <-- esp 
+-------------+  

不要忘記,在許多系統上堆棧向下增長(這對於x86系列來說肯定是這樣),所以堆棧頂部將具有最低的內存地址。

+0

+1 - 簡單,乾淨,信息豐富。 – Cyclonecode 2012-04-22 01:43:39

+0

哇很乾淨!感謝這非常有幫助!我想關鍵是堆棧向下增長!很高興知道 !你讓我今天一整天都感覺很好。 – yhcowboy 2012-04-22 02:23:54

5

因爲在堆棧上還有兩個其他項目;前一個ebp,你在這個例程的開始處推送的,以及返回地址,它通過調用例程放在堆棧上。

+0

我從來沒有想過,返回地址被推入堆棧!非常感謝 – yhcowboy 2012-04-22 02:25:05