2011-04-20 66 views
3

裝配新手。我有以下功能有人可以解釋彙編代碼嗎?

int foo(char *argv[]) 
{ 
    char buf[256]; 
    bar(argv[1], buf); 
} 

其中在組裝 -

0x08048473 <foo+0>:push %ebp 
0x08048474 <foo+1>:mov %esp,%ebp 
0x08048476 <foo+3>:sub $0x118,%esp 
0x0804847c <foo+9>:mov 0x8(%ebp),%eax 
0x0804847f <foo+12>:add $0x4,%eax 
0x08048482 <foo+15>:mov (%eax),%edx 
0x08048484 <foo+17>:lea -0x100(%ebp),%eax 
0x0804848a <foo+23>:mov %eax,0x4(%esp) 
0x0804848e <foo+27>:mov %edx,(%esp) 
0x08048491 <foo+30>:call 0x8048454 <bar> 
0x08048496 <foo+35>:leave 
0x08048497 <foo+36>:ret  

有人能解釋這個給我好嗎?爲什麼在那裏有一個子280? 256字節確實在堆棧上分配。其餘的我無法解釋。

回答

4

堆棧用於局部變量,但也用於函數所需的中間值。在這裏,你的foo()函數調用bar()給它兩個指針,一個指向字符串(argv[1]),另一個指向buf變量;這些指針值被壓入堆棧,即在mov %eax,0x4(%esp)mov %edx,(%esp)操作碼中。因此,foo()需要多於256個字節的堆棧空間。

在更多的細節:

0x08048473 <foo+0>:push %ebp 
0x08048474 <foo+1>:mov %esp,%ebp 

這是標準函數序言:該函數將使用%ebp來點之前它被稱爲(即其參數)堆棧元素

0x08048476 <foo+3>:sub $0x118,%esp 

在堆棧上預留了一些空間,主要是(但不僅限於)buf[]

0x0804847c <foo+9>:mov 0x8(%ebp),%eax 
0x0804847f <foo+12>:add $0x4,%eax 
0x08048482 <foo+15>:mov (%eax),%edx 

0x8(%ebp)argv函數參數;這些操作碼從argv[1]獲取指針並將結果存儲在%edx中。這將成爲bar()的第一個參數。

0x08048484 <foo+17>:lea -0x100(%ebp),%eax 

這存儲在%eaxbuf[]地址 - 編譯器決定buf[]是設在上部256個字節將其與保留sub堆棧空間。

0x0804848a <foo+23>:mov %eax,0x4(%esp) 
0x0804848e <foo+27>:mov %edx,(%esp) 

bar()兩個參數的數據壓入堆棧(實際上,寫在兩個頂部堆疊位置,%esp已經已經調整)。

0x08048491 <foo+30>:call 0x8048454 <bar> 

bar()被調用。

0x08048496 <foo+35>:leave 
0x08048497 <foo+36>:ret 

leave撤消序言(它相當於mov %ebp, %esp; pop %ebp)。 ret退出該功能。

已知GCC在堆疊上稍微放置一點;在這裏,它可以保留264個字節而不是280個。這似乎是其內部寄存器分配優化器的一個假象(用於存儲中間值的額外堆棧槽,但優化器最終找到了保留相應值的方法只有寄存器)。

+0

謝謝。這很清楚。那麼前兩行是函數返回值的存儲位置呢?不是函數參數之後和被調用函數的局部變量之前存儲的返回值嗎? – user220201 2011-04-20 14:14:52

+0

返回值通常在傳統寄存器中交換(x86處理器上的%eax)。這裏你沒有'return',所以彙編代碼對'%eax'沒有任何作用:調用者會發現'foo()'「返回」'%eax'包含的值。 – 2011-04-20 14:23:25

+0

抱歉意味着詢問bar()返回的點 - bar返回時foo()繼續執行的點。存儲在哪裏? – user220201 2011-04-20 14:25:35