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

次のコマンドを使用してドワーフダンプを取得すると、次のようになります。

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」は、それらをレジスタに渡すことを強制します。生成されたオブジェクトファイルの逆アセンブリを見ると、それらがレジスタから関数のエントリポイントのスタック位置にコピーされていることがわかります。ドワーフダンプから(または他の方法を使用して)引数が最初に呼び出しで渡される場所を知る方法はありますか?

ありがとう、

4

1 に答える 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し、関数の先頭で停止してローカル変数を表示gdbすると、これらの引数が最適化されていることがわかります。

dwarfdump32ビットプログラムの例は次のようになります。

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
于 2012-11-08T15:03:55.883 に答える