読者です 読者をやめる 読者になる 読者になる

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

などをどうぞ。