2015-09-25 84 views
0

測試是在32-bit x86。我編譯了代碼gcc 4.2,優化級別o2。我將C代碼編譯爲二進制文件,然後使用objdump對其進行反彙編。這兩個函數序言指令序列有什麼區別?

下面是用於函數序言說明兩個序列:

0804a6f0 <quotearg_n>: 
804a6f0:  8b 44 24 04    mov 0x4(%esp),%eax 
804a6f4:  b9 ff ff ff ff   mov $0xffffffff,%ecx 
804a6f9:  8b 54 24 08    mov 0x8(%esp),%edx 
804a6fd:  c7 44 24 04 40 e1 04 movl $0x804e140,0x4(%esp) 
804a704:  08 
804a705:  e9 c6 fa ff ff   jmp 804a1d0 <quotearg_n_options> 
804a70a:  8d b6 00 00 00 00  lea 0x0(%esi),%esi 


0804a730 <quotearg>: 
804a730:  83 ec 1c    sub $0x1c,%esp 
804a733:  8b 44 24 20    mov 0x20(%esp),%eax 
804a737:  c7 04 24 00 00 00 00 movl $0x0,(%esp) 
804a73e:  89 44 24 04    mov %eax,0x4(%esp) 
804a742:  e8 a9 ff ff ff   call 804a6f0 <quotearg_n> 
804a747:  83 c4 1c    add $0x1c,%esp 
804a74a:  c3      ret 
804a74b:  90      nop 
804a74c:  8d 74 26 00    lea 0x0(%esi,%eiz,1),%esi 

注意,在功能quotearg,註冊esp0x1c減少它被用來訪問堆棧,並得到一些參數之前。據我的經驗,我認爲sub然後access模式是相當普遍的O2編譯指令。

但是請注意,在函數quotearg_n中,寄存器esp直接與0x4相加以訪問堆棧。 (我認爲地址爲0x804a6f0的指令的含義是將呼叫站點的返回地址註冊爲eax,我是對的嗎?)根據我的觀察,第一個函數使用的模式很少見,約爲5%的gccO2編譯中等大小的C程序。

因此,這裏是我的問題:

爲什麼編譯器生成類似quoterag_n方式函數序言說明?前三條指令的確切含義是從地址0x804a6f0開始的?

爲什麼編譯器總是在sub然後access模式之後生成函數序言指令? (如quoterag

我清楚嗎?非常感謝

+0

顯示生成此代碼或引用「quotearg_n_options」代碼可能很有用(可能是GNUlib可移植性庫或許多等價的函數)知道這些函數是如何定義的,可以讓我們準確地知道它在做什麼 –

回答

1

sub %esp是一個典型的make-some-room-on-the-stack,然後把args放在那裏,然後調用一個函數。您也可以這樣做來預留空間以將寄存器中的本地變量溢出到內存中。

第一個是tail-call優化,在將一些值加載到寄存器後跳到quotearg_n_options。最後調用的參數與我們輸入quotearg_n時堆棧中的參數相同。

它可以擺脫這一點,因爲它不需要任何本地變量的堆棧空間。

我不確定它到底在做什麼4(%esp)。我認爲這就是其中一個參數存在的地方,因爲它將其設置爲一個常數。 IIRC,(%esp)是返回地址,4(%esp)是第一個arg。它將第一個參數設置爲常量,可能是緩衝區的地址。我不清楚爲什麼它可能會做其他一些事情,除非它跳到quotearg_n_options的中間,其中%edx的值可能很重要。 (並且可以解釋爲什麼它將堆棧中的其他參數加載到被調用者可以破壞的寄存器中

+0

這可能是gcc針對win32'__vectorcall'的ABI,前兩個參數在'ecx'和' edx'。 –