2013-02-27 58 views
3

爲了更好地理解二進制文件,我準備了一個小型的C++示例,並使用gdb進行反彙編並查找機器代碼。通過創建本地變量減少堆棧指針

main()函數調用函數func()

int func(void) 
{ 
    int a; 
    int b; 
    int c; 
    int d; 
    d = 4; 
    c = 3; 
    b = 2; 
    a = 1; 
    return 0; 
} 

編譯該項目使用g ++保持的調試信息。接下來的gdb用於反彙編源代碼。我得到了func()樣子:

0x00000000004004cc <+0>: push %rbp 
0x00000000004004cd <+1>: mov %rsp,%rbp 
0x00000000004004d0 <+4>: movl $0x4,-0x10(%rbp) 
0x00000000004004d7 <+11>: movl $0x3,-0xc(%rbp) 
0x00000000004004de <+18>: movl $0x2,-0x8(%rbp) 
0x00000000004004e5 <+25>: movl $0x1,-0x4(%rbp) 
0x00000000004004ec <+32>: mov $0x0,%eax 
0x00000000004004f1 <+37>: pop %rbp 
0x00000000004004f2 <+38>: retq 

現在我的問題是,我想到的是,堆棧指針應爲16個字節移動到降低相對於基指針的地址,因爲每個整數需要4個字節。但它看起來像是將值放在堆棧上而不移動堆棧指針。

我有什麼不明白的地方?這是編譯器的問題還是彙編器忽略了一些行?

最好的問候,
前功盡棄

+0

一些編譯器不會做任何事情,但返回0. – QuentinUK 2013-02-27 12:54:42

+0

你嘗試用'-O3'編譯嗎? – Walter 2013-02-27 13:00:50

+0

我總覺得你對「指令指針」的理解與我的不符。 – PlasmaHH 2013-02-27 13:03:47

回答

4

絕對沒有你的編譯器的問題。編譯器可以自由選擇如何編譯你的代碼,並選擇不修改堆棧指針。沒有必要這樣做,因爲你的函數沒有調用任何其他函數。如果它確實調用了另一個函數,那麼它將需要創建另一個堆棧幀,以便被調用者不會跺腳調用者的堆棧幀。

作爲一般規則,您應該避免試圖對編譯器如何編譯代碼做任何假設。例如,你的編譯器完全可以自由地消除你的函數體。

+0

謝謝,正是這一點。在調用一個額外的功能後,一切看起來都如預期的那樣 – NouGHt 2013-02-27 13:00:17

+2

@Nought:一切都如預期。基本指針('%rbp')被存儲在堆棧頂部以供稍後恢復。 '%rbp'然後將堆棧的舊頂部加載到它。然後使用相對於'%rbp'的地址訪問堆棧,並設置所有本地變量。最後,基指針返回到它的原始值,'0'在'%eax'中返回。堆棧指針沒有改變,因爲代碼中沒有任何可能會破壞局部變量的東西,所以不需要通過將堆棧指針設置爲某個值來將它們的位置傳遞給其他代碼。 – Mankarse 2013-02-27 13:34:45