2013-04-30 6 views
6

私はどのようにCファイルがマシンコードにコンパイルされているかを学習しています。私はgccから-Sフラグを使ってアセンブリを生成できることを知っていますが、現時点では興味のないmain()printf()と多くのコードが生成されています。単一の関数のアセンブリを単独で出力する方法はありますか?

gccまたはclangを「コンパイル」にする方法はありますか?

e.e.e.隔離して、次のCのためのアセンブリを取得:

int add(int a, int b) { 
    return a + b; 
} 
+0

一部のIDEでは、ブレークポイントを設定し、その関数によって生成されたアセンブリコードを表示できます。これは*逆アセンブリウィンドウと呼ばれています。それはあなたが探しているものを行うはずです - あなたはIDEを使用していますか? – Aaron

+0

私は(最適化を使って)コンパイルしてから逆アセンブルすることを好みますが、コンパイラが外部アドレスなどのために不完全な命令をいくつか残していることを理解する必要がありますが、-Sを使用するよりもIMOを読む方が簡単です。 gcc -O2 -c hello.c -o hello.o、objdump -D hello.o –

+3

ここに行きます:http://gcc.godbolt.org/機能を貼り付け、コンパイラを選択すると非常に便利です。 – harold

答えて

7

特定のオブジェクト・ファイルのためにこれを行うには2つの方法があります。

  1. gccから-ffunction-sectionsオプションは、コンパイルされたsourcefileの各機能について別々のELFセクションを作成することを指示します。
  2. シンボルテーブルには、セクション名、開始アドレス、および指定された関数のサイズが含まれます。 --start-address/--stop-address引数を使用してobjdumpに入力することができます。

最初の例は:

$ readelf -S t.o | grep ' .text.' 
    [ 1] .text    PROGBITS   0000000000000000 00000040 
    [ 4] .text.foo   PROGBITS   0000000000000000 00000040 
    [ 6] .text.bar   PROGBITS   0000000000000000 00000060 
    [ 9] .text.foo2  PROGBITS   0000000000000000 000000c0 
    [11] .text.munch  PROGBITS   0000000000000000 00000110 
    [14] .text.startup.mai PROGBITS   0000000000000000 00000180

これは-ffunction-sectionsしてコンパイルされていて、4つの機能、foo()、私のオブジェクト・ファイル内のbar()foo2()munch()があります。私はそうのように、それらを別々に分解することができます

$ objdump -w -d --section=.text.foo t.o 

t.o:  file format elf64-x86-64 

Disassembly of section .text.foo: 

0000000000000000 <foo>: 
    0: 48 83 ec 08    sub $0x8,%rsp 
    4: 8b 3d 00 00 00 00  mov 0(%rip),%edi  # a <foo+0xa> 
    a: 31 f6     xor %esi,%esi 
    c: 31 c0     xor %eax,%eax 
    e: e8 00 00 00 00   callq 13 <foo+0x13> 
    13: 85 c0     test %eax,%eax 
    15: 75 01     jne 18 <foo+0x18> 
    17: 90      nop 
    18: 48 83 c4 08    add $0x8,%rsp 
    1c: c3      retq

他のオプションは、(nmは、シンボルテーブルエントリダンプ)このように使用することができます。この場合は

$ nm -f sysv t.o | grep bar 
bar  |0000000000000020| T | FUNC|0000000000000026|  |.text 
$ objdump -w -d --start-address=0x20 --stop-address=0x46 t.o --section=.text 

t.o:  file format elf64-x86-64 

Disassembly of section .text: 

0000000000000020 <bar>: 
    20: 48 83 ec 08    sub $0x8,%rsp 
    24: 8b 3d 00 00 00 00  mov 0(%rip),%edi  # 2a <bar+0xa> 
    2a: 31 f6     xor %esi,%esi 
    2c: 31 c0     xor %eax,%eax 
    2e: e8 00 00 00 00   callq 33 <bar+0x13> 
    33: 85 c0     test %eax,%eax 
    35: 75 01     jne 38 <bar+0x18> 
    37: 90      nop 
    38: bf 3f 00 00 00   mov $0x3f,%edi 
    3d: 48 83 c4 08    add $0x8,%rsp 
    41: e9 00 00 00 00   jmpq 46 <bar+0x26>

を、-ffunction-sectionsオプションを持っていませんしたがって、関数の開始オフセットはゼロではなく、別のセクションにはありません(ただし、.text)。

オブジェクトファイルを逆アセンブルするとき、オブジェクトファイル、callターゲット(だけでなく、グローバル変数のアドレス)で解決されていない、これは、あなたが望む正確何ではありません...しかし

を用心 - ここでは、fooprintfを呼び出すことはできません。これは、バイナリレベルでの解像度がリンク時にのみ発生するためです。アセンブリのソースは、そこにcall printfを持っています。このcallqprintfに実際にあるという情報は、(それがリンカーによって「パッチを適用」されるオブジェクトファイルに場所を示し、いわゆるリロケーションセクションに'S)オブジェクトファイルであるが、コードとは別に。ディスアセンブラはこれを解決できません。

+0

他の人のためのfyiだけで、 "gcc -ffunction-sections -c test.c"を使って、ソースファイルをオブジェクトファイルにコンパイルすることができます。ありがとう〜 – ashleysmithgpu

0

単一temp.c Cファイルにあなたの関数をコピーすることであろうと、このような-cフラグとそれをコンパイルするために行くための最善の方法:gcc -c -S temp.c -o temp.s

ヘッダーとフッターを除いて、他の気を散らすことなくアセンブリコードを強化する必要があります。

関連する問題