2012-09-03 57 views
6

我想從DWARF信息獲取有關調用約定的信息。更具體地說,我想要得到哪些寄存器/堆棧位置被用來傳遞參數給函數。我的問題是,我在某些情況下從DWARF轉儲獲取某種錯誤的信息。我使用的例子是下面的「C代碼」:從DWARF信息獲取調用約定

gcc -c -g -m32 test.c -o test.o 

現在,當我用下面的命令來獲得侏儒轉儲:

int __attribute__ ((fastcall)) __attribute__ ((noinline)) mult (int x, int y) { 
return x*y; 
} 

我使用下面的命令編譯這個例子

dwarfdump test.o 

我得到這個功能的以下信息:

< 2><0x00000042>  DW_TAG_formal_parameter 
         DW_AT_name     "x" 
         DW_AT_decl_file    0x00000001 /home/khaled/Repo_current/trunk/test.c 
         DW_AT_decl_line    0x00000001 
         DW_AT_type     <0x0000005b> 
         DW_AT_location    DW_OP_fbreg -12 
< 2><0x0000004e>  DW_TAG_formal_parameter 
         DW_AT_name     "y" 
         DW_AT_decl_file    0x00000001 /home/khaled/Repo_current/trunk/test.c 
         DW_AT_decl_line    0x00000001 
         DW_AT_type     <0x0000005b> 
         DW_AT_location    DW_OP_fbreg -16 

查看DW_AT_location條目,它與幀基有一些偏移。這意味着它們是內存參數,但實際調用約定「fastcall」強制將它們傳遞到寄存器。通過查看生成的目標文件的反彙編,我可以看到它們從寄存器複製到函數入口點的堆棧位置。有沒有一種方法可以從矮人轉儲中知道 - 或者以任何其他方式 - 最初在調用中傳遞參數的地方?

感謝,

回答

6

由於您使用gcc -c -g -m32 test.c -o test.o。儘管它是一個fastcall函數,但GCC仍然需要生成代碼以在函數的開頭將值從寄存器保存到堆棧幀。沒有這些,任何調試器或gdb都不能調試程序,或者他們會說這個參數正在被優化並且沒有顯示出來。它使調試不可能。

在x86_64中,編譯器也默認使用一些寄存器傳遞一些參數,即使沒有爲函數指定屬性fastcall也是如此。你也可以發現那些寄存器也被複制到堆棧中。

// x86_64 assembly code 
_mult: 
Leh_func_begin1: 
     pushq %rbp 
Ltmp0: 
     movq %rsp, %rbp 
Ltmp1: 
     movl %edi, -4(%rbp) 
     movl %esi, -8(%rbp) 
     movl -4(%rbp), %eax 
     movl -8(%rbp), %ecx 
     imull %ecx, %eax 

如果您打開優化標誌-O-O2-O3(不管-g與否),你可以拆開,發現沒有什麼被複制到堆棧幀。當你gdb優化的可執行文件,並停止在函數的開頭顯示局部變量,gdb會告訴你這些參數正在優化。

的32位程序的dwarfdump例子看起來像

0x00000083:  TAG_formal_parameter [4] 
       AT_name("x") 
       AT_decl_file("test.c") 
       AT_decl_line(1) 
       AT_type({0x0000005f} (int)) 
       AT_location(0x00000000 
        0x00000000 - 0x00000003: ecx 
        0x00000003 - 0x00000018: ecx) 

0x00000090:  TAG_formal_parameter [4] 
       AT_name("y") 
       AT_decl_file("test.c") 
       AT_decl_line(1) 
       AT_type({0x0000005f} (int)) 
       AT_location(0x0000001e 
        0x00000000 - 0x00000003: edx 
        0x00000003 - 0x00000018: edx) 

,你可以找到生成的彙編代碼是非常簡單和乾淨。

_mult: 
     pushl %ebp 
     movl %esp, %ebp 
     movl %ecx, %eax 
     imull %edx, %eax 
     popl %ebp 
     ret  $12