13

Cファイルをマシンコードにコンパイルする方法を学んでいます。gccフラグを使用してアセンブリを生成できることはわかっていますが、関連-Sする多くのコードも生成され、現時点では興味がありませんmain()printf()

関数を分離して取得gccまたはclangコンパイル」し、アセンブリを出力する方法はありますか?

つまり、次の c のアセンブリを分離して取得します。

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

2 に答える 2

15

特定のオブジェクト ファイルに対してこれを行うには、次の 2 つの方法があります。

  1. コンパイルされるソースファイル内の関数ごとに個別の ELF セクションを作成するように指示する-ffunction-sectionsオプション。gcc
  2. シンボル テーブルには、特定の関数のセクション名、開始アドレス、およびサイズが含まれます。/引数をobjdump介して入力できます。--start-address--stop-address

最初の例:

$ readelf -S へ | 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

これは でコンパイルされており、オブジェクト ファイルには、 、 の4-ffunction-sectionsつの関数があります。次のように個別に分解できます。foo()bar()foo2()munch()

$ objdump -w -d --section=.text.foo へ

変換先: ファイル形式 elf64-x86-64

セクション .text.foo の分解:

0000000000000000 <foo>:
   0: 48 83 ec 08 サブ $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 テスト %eax,%eax
  15: 75 01 jne 18 <foo+0x18>
  17:90 ノップ
  18: 48 83 c4 08 追加 $0x8、%rsp
  1c: c3 retq

もう 1 つのオプションは、次のように使用できます (nmシンボル テーブル エントリをダンプします)。

$ nm -f sysv へ | grep バー
バー |0000000000000020| T | T | FUNC|0000000000000026| |.text
$ objdump -w -d --start-address=0x20 --stop-address=0x46 ~ --section=.text

変換先: ファイル形式 elf64-x86-64

セクション .text の分解:

0000000000000020 <バー>:
  20: 48 83 ec 08 サブ $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 テスト %eax,%eax
  35: 75 01 38 <bar+0x18>
  37:90ノップ
  38: bf 3f 00 00 00 mov $0x3f,%edi
  3d: 48 83 c4 08 追加 $0x8、%rsp
  41: e9 00 00 00 00 jmpq 46 <bar+0x26>

この場合、-ffunction-sectionsオプションは使用されていないため、関数の開始オフセットはゼロではなく、別のセクションにはありません (しかし にはあり.textます)。

オブジェクトファイルを逆アセンブルするときは注意してください...

オブジェクト ファイルの場合、ターゲット (およびグローバル変数のアドレス) が解決されないため、これはまさにあなたが望むものではありません。リンク時。ただし、アセンブリ ソースには があります。これが実際に行われる情報はオブジェクト ファイルにありますが、コードとは別です (これは、リンカーによって「パッチが適用される」オブジェクト ファイル内の場所をリストする、いわゆる再配置セクションにあります)。逆アセンブラはこれを解決できません。callfooprintfcall printfcallqprintf

于 2013-04-30T17:39:01.940 に答える
1

最善の方法は、関数を単一の C ファイルにコピーし、次のようにフラグtemp.cを付けてコンパイルすることです。-cgcc -c -S temp.c -o temp.s

(ヘッダーとフッターを除いて) 他に気を散らすものがない、よりタイトなアセンブリ コードを生成する必要があります。

于 2013-04-30T15:02:28.290 に答える