1. ホーム
  2. c

[解決済み】GCCを使用して読みやすいアセンブリを作成しますか?

2022-03-31 20:41:25

質問

をどう使うか悩んでいました。 GCC C言語のソースファイルに機械語のニモニックバージョンをダンプして、自分のコードが何にコンパイルされたかを確認できるようにしました。Javaでこれを行うことができますが、GCCでの方法を見つけることができません。

C言語のメソッドをアセンブリで書き直そうとしているのですが、GCCがそれをどのように行うかを見ることは大きな助けになるでしょう。

どのように解決するのですか?

デバッグシンボル付きでコンパイルした場合( -g を使っている場合でも、GCCのコマンドラインに -O3 1 ), を使用することができます。 objdump -S を使えば、C言語のソースとインターリーブされた、より読みやすいディスアセンブルを作成することができます。

>objdump --help
[...]
-S, --source             Intermix source code with disassembly
-l, --line-numbers       Include line numbers and filenames in output

objdump -drwC -Mintel がいいですね。

  • -r はリロケーション時のシンボル名を表示します。 puts の中に call という命令があります。)
  • -R ダイナミックリンクのリロケーションとシンボル名を表示します。
  • -C C++のシンボル名を目立たなくする
  • -w は "wide"モード:マシンコードバイトを改行しない
  • -Mintel GAS/binutils MASM ライクなものを使用します。 .intel_syntax noprefix の代わりに AT&T の構文を使用します。
  • -S : ソース行を逆アセンブルでインターリーブします。

のようなものを置くことができます。 alias disas="objdump -drwCS -Mintel" の中に ~/.bashrc . x86 でない場合、または AT&T 構文が好きな場合は、以下のように省略します。 -Mintel .


> gcc -g -c test.c
> objdump -d -M intel -S test.o

test.o:     file format elf32-i386


Disassembly of section .text:

00000000 <main>:
#include <stdio.h>

int main(void)
{
   0:   55                      push   ebp
   1:   89 e5                   mov    ebp,esp
   3:   83 e4 f0                and    esp,0xfffffff0
   6:   83 ec 10                sub    esp,0x10
    puts("test");
   9:   c7 04 24 00 00 00 00    mov    DWORD PTR [esp],0x0
  10:   e8 fc ff ff ff          call   11 <main+0x11>

    return 0;
  15:   b8 00 00 00 00          mov    eax,0x0
}
  1a:   c9                      leave  
  1b:   c3                      ret

なお、この ではありません。 を使って -r ということで call rel32=-4 はアノテーションされません。 puts のシンボル名です。 そして見た目は壊れた call のように、mainのcall命令の途中に飛び込んでくるものです。 この rel32 呼び出しエンコーディングの変位は、リンカが実際のオフセット(この場合、libcを静的にリンクしない限りPLTスタブへのオフセット)を埋めるまでの単なるプレースホルダに過ぎません。


脚注1 : ソースのインターリーブは厄介で、最適化されたビルドではあまり役に立ちません。 https://godbolt.org/ などで、どの命令がどのソース行に対応しているかを視覚化することができます。 最適化されたコードでは ある命令に対応するソース行が常に1つとは限らない が、デバッグ情報では、asm命令ごとに1つのソース行が選ばれます。