从DWARF信息中获取调用约定

8

我正在尝试从DWARF信息中获取有关调用约定的信息。更具体地说,我想知道用于将参数传递给函数的寄存器/堆栈位置是哪些。我的问题是,在某些情况下,我从DWARF转储中获得了错误的信息。我使用的示例是以下"C代码":

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

我使用以下命令编译这个示例:

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

现在,当我使用以下命令获取dwarf转储时:
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" 强制将它们传递到寄存器中。通过查看生成的目标文件的反汇编代码,我可以看到它们从寄存器复制到函数入口处的堆栈位置。有没有办法从dwarf dump --或使用任何其他方法-- 知道参数最初在调用时传递到哪里?

谢谢。

1个回答

9
因为您正在使用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会告诉您这些参数正在被优化掉。
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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接