2013-12-16 49 views
1

我寫了一個簡單的代碼來理解彙編代碼。它是以下內容:方法調用後使用EBP指針

int sum(int a, int b){ 
     int res = a+b; 
    } 

而在主函數我調用sum函數。 所以,我也得到了assemblercode(我只需要在這裏和功能的一部分)4

push ebp, 
    mov ebp, esp 
    sub esp, 16 
    mov eax, DWORD PTR[ebp + 12] 
    mov edx, DWORD PTR[ebp + 8] 
    add eax, edx 
    mov DWORD PTR [ebp-4], eax 
    mov eax, DWORD PTR [ebp-4] 
    leave 

,現在我的問題。我有兩個問題: 首先,在ebp + 12和ebp + 8中記錄sum參數的值(例如sum(5,4))和ebp-4的結果是否有原因?爲什麼我們這樣做?它總是一樣的還是隨機選擇的?

第二,我們有一部分:

mov DWORD PTR [ebp-4], eax 
    mov eax, DWORD PTR [ebp-4] 

爲什麼我們首先在EBP-4,然後執行結果EAX前再次我們離開的功能? 還有一個原因嗎?

+0

爲了能夠給你一個明確的答覆,並有一個,我想問問你,告訴你正在使用的編譯器。 – Rastikan

+0

哪個操作系統和哪個編譯器? – nrz

+0

您將函數聲明爲「int」,但沒有返回任何內容 –

回答

2

這通常是如何在x86系統中創建堆棧框架的。

調用者將它轉換爲...

push b 
push a 
call sum 

由於每個項目都壓入堆棧,堆棧向下增長。也就是說,堆棧指針寄存器會減少四(4)個字節(在32位模式下),並且該項目被複制到堆棧指針寄存器所指向的存儲器位置。

此時,「調用」指令已經發出,我們現在處於被調用例程的開始處。如果我們想進入我們的參數,我們可以像

[esp + 4] - parameter 'a' 
[esp + 8] - parameter 'b' 

訪問它們。然而,我們開拓出局部變量和東西的空間在此之後可以得到笨拙。因此,除了堆棧指針寄存器之外,我們還使用了堆棧庫指針寄存器。但是,我們希望將堆棧庫指針寄存器設置爲當前幀,而不是之前的函數。因此,我們將舊版本保存在堆棧上(它修改了堆棧上參數的偏移量),然後將當前的堆棧指針寄存器複製到堆棧指針寄存器。

push ebp  ; save previous stackbase-pointer register 
mov ebp, esp ; ebp = esp 

把它放在一起。參數是使用stackbase指針registe訪問

[ebp + 12] - parameter 'b' 
[ebp + 8] - parameter 'a' 
[ebp + 4] - return address 
[ebp + 0] - saved stackbase-pointer register 

來源: What is stack frame in assembly?

0

您可以通過尋找如關鍵字查找此信息:

  • 調用約定
  • FASTCALL
  • stdcall

那時候,一個16位的字參數會在EAX中傳給AX(和32位一個)。回報將是AX/EAX。一個64位參數(或2個參數將在EDX:EAX中)並返回。這是一個典型的FASTCALL調用約定(我相信老帕斯卡使用的)

現在對於C/C++ fastcall通常不會使用(也許是因爲它不像便攜式那樣)。絕大多數情況下都使用堆棧,這就是EBP發揮作用的地方。 EBP是您的基本堆棧指針-4,-8,-12只是您的本地堆棧中存儲和返回參數的偏移指針。

這裏有幾個環節: http://en.wikibooks.org/wiki/X86_Disassembly/Calling_Convention_Examples http://en.wikipedia.org/wiki/X86_calling_conventions