objdumpから16進出力のみを取得する

objdumpから16進出力のみを取得する

たとえば、次のC関数があります。

void f(int *x, int *y)
{
    (*x) = (*x) * (*y);
}

に保存すると、次のf.cコンパイルgcc -c f.c結果が表示されますf.oobjdump -d f.o

f.o:     file format elf64-x86-64


Disassembly of section .text:

0000000000000000 <f>:
   0:   55                      push   %rbp
   1:   48 89 e5                mov    %rsp,%rbp
   4:   48 89 7d f8             mov    %rdi,-0x8(%rbp)
   8:   48 89 75 f0             mov    %rsi,-0x10(%rbp)
   c:   48 8b 45 f8             mov    -0x8(%rbp),%rax
  10:   8b 10                   mov    (%rax),%edx
  12:   48 8b 45 f0             mov    -0x10(%rbp),%rax
  16:   8b 00                   mov    (%rax),%eax
  18:   0f af d0                imul   %eax,%edx
  1b:   48 8b 45 f8             mov    -0x8(%rbp),%rax
  1f:   89 10                   mov    %edx,(%rax)
  21:   5d                      pop    %rbp
  22:   c3                      retq  

私はこれを次のように出力したいと思います。

55 48 89 e5 48 89 7d f8 48 89 75 f0 48 8b 45 f8 8b 10 48 8b 45 f0 8b 00 0f af d0 48 8b 45 f8 89 10 5d c3

つまり、関数の16進値です。objdumpこれを実行できるフラグはありますか?それ以外の場合は、目的の出力を取得するためにどのようなツール(たとえば、awk、sed、cutなど)を使用できますか?

答え1

次のコマンドを使用して、テキストセグメントのバイト値を抽出できます。

$ objcopy -O binary -j .text f.o fo

-Oバイナリオプション:

objcopyは、バイナリ出力ターゲット(-Oバイナリを使用するなど)を使用してネイティブバイナリを生成するために使用できます。 objcopyがネイティブバイナリファイルを生成すると、デフォルトでは入力オブジェクトファイルの内容のメモリダンプが生成されます。すべてのシンボルおよび再配置情報は削除されます。メモリダンプは、出力ファイルの最下部にコピーされたロードアドレスから始まります。

オプション-j .text:

-jsectionpattern
--only-section=sectionpattern
入力ファイルで指定されたセクションのみを出力ファイルにコピーします。このオプションは複数回与えられます。
このオプションを不適切に使用すると、出力ファイルが使用できなくなる可能性があります。セクションパターンにはワイルドカードが許可されています。

最終結果は、foそのセクションのバイナリ値.text、つまりシンボルや再配置情報のない実行コードのみを含むファイル()です。

次に、foファイルの16進値を印刷します。

$ od -An -v -t x1 fo
 55 48 89 e5 48 89 7d f8 48 89 75 f0 48 8b 45 f8
 8b 10 48 8b 45 f0 8b 00 0f af d0 48 8b 45 f8 89
 10 90 5d c3

答え2

どうですか?

awk '/^....:/{a=substr($0,9,20);sub(/ +$/,"",a);b=b" "a}END{print substr(b,2)}'

この場合は返されます。

55 48 89 e5 48 89 7d f8 48 89 75 f0 48 8b 45 f8 8b 10 48 8b 45 f0 8b 00 0f af d0 48 8b 45 f8 89 10 5d c3

答え3

別のオプションは、次のものを使用することですreadelf

$ readelf -x .text f.o

Hex dump of section '.text':
  0x00070c00 f30f1efa 488d15fd 13100048 8d357606 ....H......H.5v.
  0x00070c10 1100488d 3dc33809 00e902f5 fffff30f ..H.=.8.........
  0x00070c20 1efa5548 8d2d9606 1100be22 00000045 ..UH.-....."...E
  ...

一部の特定の.elfファイルでは、未知の理由で(特定のアーキテクチャの非互換性のために)欠落しており、私が見つけることができる唯一の動作ソリューションですobjdumpobjcopyreadelf

答え4

解決策1:

42sh$ objcopy -j .text f.o /proc/self/fd/1 -O verilog | tail -n +2 | tr '\n' ' ' | tr -d '\r'
8B 07 0F AF 06 89 07 C3 42sh$

'\ n'が空白に変換され、最後の改行文字の代わりに末尾の空白が表示されることがわかります。 tailとtrは、必要なものを正確に変換するためにのみ使用されます。

解決策2:

42sh$ objcopy -O binary -j .text f.o /proc/self/fd/1 | xxd -ps -c 36 | sed 's,..,& ,g; s, $,,'
8b 07 0f af 06 89 07 c3
42sh$

ここでは、objcopyに生のバイナリとして印刷するように要求し、許可された答えのようにod(8進ダンプを表す)ではなくxxd(16進ダンプを表す)として16進エンコードします。

-c は文字数です。すべてのシンボルを1行に表示するには、大きな数字を使用できます。 sedは、説明したように2つの代替項目を使用します。https://askubuntu.com/a/661687/7729551つはスペースを広げ、もう1つは最後のスペースを削除することです。 sedが予約されました。\ n

一般的な説明:

objcopyは私たちが望む部分だけを読みます。

どちらのソリューションも、Linuxでは/proc/self/fd/1、darwinでは/dev/fd/1を指す/dev/stdoutパイプに直接作成して一時ファイルを防止します。

2進数出力の場合は、16進数に変換する必要があります。

その後、sed / trを使用して美しくなり、awk / perlを使用できます。

編集1:

@Stéphane Chazelas ありがとうございます。

関連情報