GCC(binutils)のツールの紹介: objdump
GCCには様々なツールが付属しています。実際にはGCCではなく、一緒にコンパイルされるBinutilsに付属しているものですが。
Binutilsを使うことでプログラムに関する様々な情報を容易に取得できたり、アセンブラレベルでのデバッグや最適化にも有効です。
組み込み用途には必須のツールと言えます。
今回紹介するのはobjdumpだけですが、今後残りも紹介していきます。
サンプルに使うソースコード
内容は何でも良いのですが、ファイルシステムのソースから一部を抜粋してきました。
#include <stdio.h> #include <stdlib.h> #include <string.h> #define SECTOR_SIZE 512 // Read a sector from filesystem. void readsector(char *mmc, char *dest, int sec) { if (!dest) return; memcpy(dest, &mmc[sec * SECTOR_SIZE], SECTOR_SIZE); } // Write a sector to filesystem. void writesector(char *mmc, char *src, int sec) { int i; char nullchar = '\0'; if (src) { memcpy(&mmc[sec * SECTOR_SIZE], src, SECTOR_SIZE); } else { for (i = 0; i < SECTOR_SIZE; i++) { memcpy(&mmc[sec * SECTOR_SIZE + i], &nullchar, sizeof(char)); } } }
これをコンパイルして.oを作っておきます。また、debugオプションを付けてコンパイルしたファイルも生成しておきます。
$ gcc -c test.c $ gcc -g -c test.c -o test-debug.o $ ls test-debug.o test.c test.o
objdump
objdumpはbinutilsの中でも(asとldを除いて)最も使う頻度の高いツールです。
いわゆるディスアセンブラのようなもので、機械語となったプログラムをアセンブリ言語に戻してくれます。
また、それ以外にもプログラムの情報を表示する機能もあります。
まずは、一番基本の-dオプション(disassemble)を実行してみます。
$ objdump -d test.o test.o: file format elf32-i386 Disassembly of section .text: 00000000: 0: 55 push %ebp 1: 89 e5 mov %esp,%ebp 3: 83 ec 18 sub $0x18,%esp 6: 83 7d 0c 00 cmpl $0x0,0xc(%ebp) a: 74 22 je 2e c: 8b 45 10 mov 0x10(%ebp),%eax f: c1 e0 09 shl $0x9,%eax 12: 03 45 08 add 0x8(%ebp),%eax 15: c7 44 24 08 00 02 00 movl $0x200,0x8(%esp) 1c: 00 1d: 89 44 24 04 mov %eax,0x4(%esp) 21: 8b 45 0c mov 0xc(%ebp),%eax 24: 89 04 24 mov %eax,(%esp) 27: e8 fc ff ff ff call 28 2c: eb 01 jmp 2f 2e: 90 nop 2f: c9 leave 30: c3 ret 00000031 : ...
以上ののように関数毎に、
が表示されることがわかります。
また、2段目にsectionが.textと表示されていますが、これはこれらの関数が.textセクションにあるということを意味しています。
セクションには様々なものがあり、自分で任意のセクションを作ることができますが、通常は.textセクションにプログラムがあります。
-Sオプションを指定すると-dオプションと同様にディスアセンブリするだけでなく、対応するソースコードも表示してくれます。
ただし、ソースコードが表示されるのはdebugオプションを付けてコンパイルした場合のみとなります。
$ objdump -S test-debug.o
-xオプションでヘッダ情報を全て表示することもできます。
$ objdump -x test.o test.o: file format elf32-i386 test.o architecture: i386, flags 0x00000011: HAS_RELOC, HAS_SYMS start address 0x00000000 Sections: Idx Name Size VMA LMA File off Algn 0 .text 0000009e 00000000 00000000 00000034 2**2 CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE 1 .data 00000000 00000000 00000000 000000d4 2**2 CONTENTS, ALLOC, LOAD, DATA 2 .bss 00000000 00000000 00000000 000000d4 2**2 ALLOC 3 .comment 0000001d 00000000 00000000 000000d4 2**0 CONTENTS, READONLY 4 .note.GNU-stack 00000000 00000000 00000000 000000f1 2**0 CONTENTS, READONLY SYMBOL TABLE: 00000000 l df *ABS* 00000000 test.c 00000000 l d .text 00000000 .text 00000000 l d .data 00000000 .data 00000000 l d .bss 00000000 .bss 00000000 l d .note.GNU-stack 00000000 .note.GNU-stack 00000000 l d .comment 00000000 .comment 00000000 g F .text 00000031 readsector 00000000 *UND* 00000000 memcpy 00000031 g F .text 0000006d writesector RELOCATION RECORDS FOR [.text]: OFFSET TYPE VALUE 00000028 R_386_PC32 memcpy 0000005d R_386_PC32 memcpy 0000008b R_386_PC32 memcpy
先ほど出てきた.textセクション以外にいくつかのセクションが存在していることがわかります。
簡単に説明すると、.dataはstaticなデータが置いてある場所で、.bssはstaticなデータだけど値が0のものがおいてあります。残り2つについてはよく知りません。
.commentに関してはファイル内に何かデータがある(sizeが1d)ようなので、バイナリエディタで.commentセクションの中身を見てみましょう。
ヘッダの情報によるとファイル先頭から0xd4バイト目から0x1dバイト分とのことです。
$ bvi -b 0xd4 -e $[0xd4+0x1d] test.o 000000D4 00 47 ..... 00 00 .GCC: (Debian 4.4.5-8) 4.4.5..
このように、GCCのバージョン情報が埋め込まれているということがわかりります。
同様にして.textをみると-dオプションでみた機械語が並んでいることもわかります。
今回はobjdumpのみの紹介でしたが、objdumpによってわかる情報はまだまだたくさんあります。
更に詳しい情報は
$ man objdump $ man elf
などをどうぞ。