7

以下のような関数があるとします。

# cat 003.c

int foo(int a, int b)
{
    return a+b;
}

そして、次のようにコンパイルします。

gcc -S 003.c

は、次のアセンブリ結果を取得します。

     .file   "003.c"
     .text
 .globl foo
     .type   foo, @function
 foo:
 .LFB2:
     pushq   %rbp
 .LCFI0:
     movq    %rsp, %rbp
 .LCFI1:
     movl    %edi, -4(%rbp)
     movl    %esi, -8(%rbp)
     movl    -8(%rbp), %edx
     movl    -4(%rbp), %eax
     addl    %edx, %eax
     leave
     ret
 .LFE2:
     .size   foo, .-foo /* size of the function foo, how to get it?*/

上記の最後の行は、関数のサイズを取得します。コンパイラはサイズをどこに保存しますか? C または inline asmを使用して、元の C プログラムで何らかの方法で関数のサイズを取得できますか?

4

2 に答える 2

13

関数サイズに関する情報は、対応するシンボル(名前)のELF属性に格納されます。これをプログラムで解析する方法のCサンプルコードは、Solarisのマンページの下部にあります(libelfはLinux、* BSD、MacOSにも存在します。構造体のフィールドgelf_getsym(3ELF)を探す必要があります)が、objdump/を使用することもできます。タスクのelfdump(Solaris)/ readelf(Linux):st_sizeGElf_Sym

$ objdump -h -d --section = .text foo3.o

foo3.o:ファイル形式elf64-x86-64

セクション:
Idx名サイズVMALMAファイルオフAlgn
  0 .text 00000012 0000000000000000 0000000000000000 00000040 2 ** 2
                  コンテンツ、ALLOC、ロード、読み取り専用、コード
[...]
セクション.textの逆アセンブル:

0000000000000000 <foo>:
   0:55プッシュ%rbp
   1:48 89 e5 mov%rsp、%rbp
   4:89 7d fc mov%edi、0xfffffffffffffffc(%rbp)
   7:89 75 f8 mov%esi、0xfffffffffffffff8(%rbp)
   a:8b 45 f8 mov 0xfffffffffffffff8(%rbp)、%eax
   d:03 45 fc add 0xfffffffffffffffc(%rbp)、%eax
  10:c9 Leaveq
  11:c3 retq

これは、コードの最適化されていないコンパイル用ですが、最適化されたバージョンは次のとおりです。

$ objdump -h -d --section = .text foo3.o

foo3.o:ファイル形式elf64-x86-64

セクション:
Idx名サイズVMALMAファイルオフAlgn
  0 .text 00000004 0000000000000000 0000000000000000 00000040 2 ** 4
                  コンテンツ、ALLOC、ロード、読み取り専用、コード
[...]
セクション.textの逆アセンブル:

0000000000000000 <foo>:
   0:8d 04 37 lea(%rdi、%rsi、1)、%eax
   3:c3 retq

「サイズ」がから?に変更されていることに注意して0x12ください4。これが、.sizeアセンブラディレクティブから得られるものです。

インラインアセンブリを使用して関数のサイズ/コードの場所を提供しようとする「トリック」は、コンパイラによって生成されたグルーコード(関数のエントリプロローグ/終了エピローグ、インラインコードの生成など)や、コンパイラの再生成を考慮していません。 -インラインアセンブリを注文する(gccはそうすることで悪名高い)ので、これを信頼することは一般的に良い考えではありません。結局、それはあなたが何をしようとしているのかによって異なります...

編集:スタックオーバーフローだけでなく外部のいくつかの参照:

  1. gccメーリングリストから、スレッドをオンにしますsizeof(function)
  2. sizeof(関数名)は何を返しますか?
  3. Cで関数のサイズを見つける
  4. sourceforgeプロジェクトの例によるLibELF(これはドキュメント/チュートリアルです)
于 2012-07-10T09:57:08.850 に答える
1

関数のポインタと関数の最後にある現在のアドレスの差を取らないのはなぜですか? 現在の IP アドレスを回復するには、この質問をご覧ください: Get address of current instruction for x86 、返信の 1 つから盗まれたこのコードである可能性があります。

unsigned long get_PC()
{
    unsigned long current_instruction;

    __asm__ __volatile__
    (
        "movq 8(%rbp), %rax\n\t"
        : "=a" (current_instruction)
    );

    return current_instruction;
}

トリックを行うだろう、

于 2012-07-10T09:19:59.613 に答える