Cファイルをマシンコードにコンパイルする方法を学んでいます。gcc
フラグを使用してアセンブリを生成できることはわかっていますが、関連-S
する多くのコードも生成され、現時点では興味がありませんmain()
。printf()
関数を分離して取得gcc
またはclang
「コンパイル」し、アセンブリを出力する方法はありますか?
つまり、次の c のアセンブリを分離して取得します。
int add( int a, int b ) {
return a + b;
}
Cファイルをマシンコードにコンパイルする方法を学んでいます。gcc
フラグを使用してアセンブリを生成できることはわかっていますが、関連-S
する多くのコードも生成され、現時点では興味がありませんmain()
。printf()
関数を分離して取得gcc
またはclang
「コンパイル」し、アセンブリを出力する方法はありますか?
つまり、次の c のアセンブリを分離して取得します。
int add( int a, int b ) {
return a + b;
}
特定のオブジェクト ファイルに対してこれを行うには、次の 2 つの方法があります。
-ffunction-sections
オプション。gcc
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
ます)。
オブジェクトファイルを逆アセンブルするときは注意してください...
オブジェクト ファイルの場合、ターゲット (およびグローバル変数のアドレス) が解決されないため、これはまさにあなたが望むものではありません。リンク時。ただし、アセンブリ ソースには があります。これが実際に行われる情報はオブジェクト ファイルにありますが、コードとは別です (これは、リンカーによって「パッチが適用される」オブジェクト ファイル内の場所をリストする、いわゆる再配置セクションにあります)。逆アセンブラはこれを解決できません。call
foo
printf
call printf
callq
printf
最善の方法は、関数を単一の C ファイルにコピーし、次のようにフラグtemp.c
を付けてコンパイルすることです。-c
gcc -c -S temp.c -o temp.s
(ヘッダーとフッターを除いて) 他に気を散らすものがない、よりタイトなアセンブリ コードを生成する必要があります。