出力ファイルのフォーマット
アセンブラの解説をする前に、まずは、実行ファイル/オブジェクトファイルのフォーマットについて説明します。
実行ファイル/オブジェクトファイルのファイル形式は、OS によって異なります。
実行ファイル/オブジェクトファイルのファイル形式は、OS によって異なります。
Unix など | ELF (Executable and Linkable Format) |
---|---|
Windows | PE (Portable Executable) [拡張 COFF 形式] |
MacOS | Mach-O |
ELF フォーマット
Linux などで使われる ELF ファイルの構造は、以下のようになっています。
プログラムヘッダは、オブジェクトファイルには存在しない場合があります。
データの種類ごとに、セクションやセグメントが複数個存在し、それぞれに名前を付けることができます。
セグメントは、実際に実行された時にロードされる一つの単位で、セクションは、フォーマット上の一つの単位です。
x64 の 64bit モードの場合、セグメントは一つとして扱われるので、すべてのセクションは、実行時に一つに結合されます。
16/32bit のモードの場合、一つのプログラムは複数のセグメントで構成されます。
[ELF ヘッダ] [プログラムヘッダ] [セクション or セグメント] ... [セクションヘッダ]
プログラムヘッダは、オブジェクトファイルには存在しない場合があります。
データの種類ごとに、セクションやセグメントが複数個存在し、それぞれに名前を付けることができます。
セグメントは、実際に実行された時にロードされる一つの単位で、セクションは、フォーマット上の一つの単位です。
x64 の 64bit モードの場合、セグメントは一つとして扱われるので、すべてのセクションは、実行時に一つに結合されます。
16/32bit のモードの場合、一つのプログラムは複数のセグメントで構成されます。
セクション名
以下は、基本的なセクションです。
※実際に使用されるセクション名は、出力フォーマットごとに異なります。
※Mach-O の場合、セグメントの中にセクションが含まれている形になるので、「segment,section」として表記しています。
NASM でセクションを指定する場合も、この形式で指定する必要があります (',' の後に空白を開けないこと)。
※実際に使用されるセクション名は、出力フォーマットごとに異なります。
ELF | PE | Mach-O | 内容 |
.text | .text | __TEXT,__text | プログラムコード |
.data | .data | __DATA,__data | 値が初期化されているデータ |
.bss | .bss | __DATA,__bss | 値が初期化されていないデータ。 プログラムが実行を開始した時に、0 で初期化される。 |
.rodata | .rdata | __DATA,__const | 読み込み専用データ |
※Mach-O の場合、セグメントの中にセクションが含まれている形になるので、「segment,section」として表記しています。
NASM でセクションを指定する場合も、この形式で指定する必要があります (',' の後に空白を開けないこと)。
SECTION ディレクティブ
NASM では、SECTION ディレクティブを使うことで、以降に出力されるバイナリを配置するセクション (またはセグメント) を切り替えることができます。
このため、「.text」「.data」「.bss」の3つに関しては、ELF/PE/Mach-O いずれの形式でも、共通のセクション名として使用することができます。
ただし、読み込み専用データに関しては、ELF/Mach-O なら .rodata、PE なら .rdata を使う必要があります。
section .text ; プログラムコードとして出力 section .data ; データとして出力 section __DATA,__data ; Mach-O の初期化されたデータ
互換セクション名
各出力形式ごとに、対応するセクション名を指定する必要がありますが、NASM では、Mach-O と ELF との互換性を確保するため、以下のセクション名にも対応しています。.text = __TEXT,__text .data = __DATA,__data .bss = __DATA,__bss .rodata = __DATA,__const
このため、「.text」「.data」「.bss」の3つに関しては、ELF/PE/Mach-O いずれの形式でも、共通のセクション名として使用することができます。
ただし、読み込み専用データに関しては、ELF/Mach-O なら .rodata、PE なら .rdata を使う必要があります。
各出力形式でアセンブルしてみる
前回試したサンプルプログラムでは、.text セクションしか使用していないので、ELF/PE/Mach-O いずれの出力形式でも、同じコードでそのまま出力できます。
「-f win64」「-f macho64」オプションで、それぞれ、Windows、MacOS X 用のオブジェクトを出力してみましょう。
「-f win64」「-f macho64」オプションで、それぞれ、Windows、MacOS X 用のオブジェクトを出力してみましょう。
# Windows $ nasm -f win64 02_test.asm -o win.obj # MacOS X $ nasm -f macho64 02_test.asm -o mac.o
win.obj の逆アセンブル
objdump は、PE フォーマットにも対応しています。
前回と同じように、win.obj ファイルを逆アセンブルしてみてください。
ファイル形式は「pe-x86-64」 (ELF の場合は elf64-x86-64)、セクション名は「.text」になっています。
前回と同じように、win.obj ファイルを逆アセンブルしてみてください。
$ objdump -d -M intel win.obj win.obj: ファイル形式 pe-x86-64 セクション .text の逆アセンブル: 0000000000000000 <testfunc>: 0: b8 7b 00 00 00 mov eax,0x7b 5: c3 ret
ファイル形式は「pe-x86-64」 (ELF の場合は elf64-x86-64)、セクション名は「.text」になっています。
mac.o
objdump は、Mach-O フォーマットには対応していないので、表示できません。
代わりに、strings コマンドで、バイナリ中の表示可能な文字列を表示してみてください。
「__TEXT」「__text」という文字があります。これがセグメント名とセクション名です。
.text セクションが、Mach-O に対応するセグメント名とセクション名に変換されていることがわかります。
また、バイナリエディタで開いてみると、終端近くに「b8 7b 00 00 00 c3」のバイナリコードが見つかります。
代わりに、strings コマンドで、バイナリ中の表示可能な文字列を表示してみてください。
$ strings mac.o __text __TEXT testfunc
「__TEXT」「__text」という文字があります。これがセグメント名とセクション名です。
.text セクションが、Mach-O に対応するセグメント名とセクション名に変換されていることがわかります。
また、バイナリエディタで開いてみると、終端近くに「b8 7b 00 00 00 c3」のバイナリコードが見つかります。
実行ファイルのセクション情報
ELF と PE で、実行ファイルに含まれるセクションがどのように違うか、確認してみます。
objdump で -h, --[section-]headers オプションを指定すると、セクションヘッダの内容を表示できます。
objdump で -h, --[section-]headers オプションを指定すると、セクションヘッダの内容を表示できます。
ELF64
前回作成した test の実行ファイルを使います。
色々なセクション名があります。
$ objdump -h test test: ファイル形式 elf64-x86-64 セクション: Idx Name Size VMA LMA File off Algn 0 .interp 0000001c 0000000000000318 0000000000000318 00000318 2**0 CONTENTS, ALLOC, LOAD, READONLY, DATA 1 .note.gnu.property 00000020 0000000000000338 0000000000000338 00000338 2**3 CONTENTS, ALLOC, LOAD, READONLY, DATA 2 .note.gnu.build-id 00000024 0000000000000358 0000000000000358 00000358 2**2 CONTENTS, ALLOC, LOAD, READONLY, DATA 3 .note.ABI-tag 00000020 000000000000037c 000000000000037c 0000037c 2**2 CONTENTS, ALLOC, LOAD, READONLY, DATA 4 .gnu.hash 0000001c 00000000000003a0 00000000000003a0 000003a0 2**3 CONTENTS, ALLOC, LOAD, READONLY, DATA 5 .dynsym 000000a8 00000000000003c0 00000000000003c0 000003c0 2**3 CONTENTS, ALLOC, LOAD, READONLY, DATA 6 .dynstr 0000008f 0000000000000468 0000000000000468 00000468 2**0 CONTENTS, ALLOC, LOAD, READONLY, DATA 7 .gnu.version 0000000e 00000000000004f8 00000000000004f8 000004f8 2**1 CONTENTS, ALLOC, LOAD, READONLY, DATA 8 .gnu.version_r 00000030 0000000000000508 0000000000000508 00000508 2**3 CONTENTS, ALLOC, LOAD, READONLY, DATA 9 .rela.dyn 000000c0 0000000000000538 0000000000000538 00000538 2**3 CONTENTS, ALLOC, LOAD, READONLY, DATA 10 .rela.plt 00000018 00000000000005f8 00000000000005f8 000005f8 2**3 CONTENTS, ALLOC, LOAD, READONLY, DATA 11 .init 0000001b 0000000000001000 0000000000001000 00001000 2**2 CONTENTS, ALLOC, LOAD, READONLY, CODE 12 .plt 00000020 0000000000001020 0000000000001020 00001020 2**4 CONTENTS, ALLOC, LOAD, READONLY, CODE 13 .text 00000136 0000000000001040 0000000000001040 00001040 2**4 CONTENTS, ALLOC, LOAD, READONLY, CODE 14 .fini 0000000d 0000000000001178 0000000000001178 00001178 2**2 CONTENTS, ALLOC, LOAD, READONLY, CODE 15 .rodata 00000008 0000000000002000 0000000000002000 00002000 2**2 CONTENTS, ALLOC, LOAD, READONLY, DATA 16 .eh_frame_hdr 00000024 0000000000002008 0000000000002008 00002008 2**2 CONTENTS, ALLOC, LOAD, READONLY, DATA 17 .eh_frame 0000007c 0000000000002030 0000000000002030 00002030 2**3 CONTENTS, ALLOC, LOAD, READONLY, DATA 18 .init_array 00000008 0000000000003dd0 0000000000003dd0 00002dd0 2**3 CONTENTS, ALLOC, LOAD, DATA 19 .fini_array 00000008 0000000000003dd8 0000000000003dd8 00002dd8 2**3 CONTENTS, ALLOC, LOAD, DATA 20 .dynamic 000001e0 0000000000003de0 0000000000003de0 00002de0 2**3 CONTENTS, ALLOC, LOAD, DATA 21 .got 00000028 0000000000003fc0 0000000000003fc0 00002fc0 2**3 CONTENTS, ALLOC, LOAD, DATA 22 .got.plt 00000020 0000000000003fe8 0000000000003fe8 00002fe8 2**3 CONTENTS, ALLOC, LOAD, DATA 23 .data 00000010 0000000000004008 0000000000004008 00003008 2**3 CONTENTS, ALLOC, LOAD, DATA 24 .bss 00000008 0000000000004018 0000000000004018 00003018 2**0 ALLOC 25 .comment 0000001b 0000000000000000 0000000000000000 00003018 2**0 CONTENTS, READONLY
色々なセクション名があります。
.rodata | 読み込み専用データ |
---|---|
.init | プロセス初期化時に使用される実行コード |
.fini | プロセス終了時に使用される実行コード |
.dynamic | 動的リンク情報 |
PE
MinGW を使って、Windows 用の実行ファイルをコンパイルしてみます。
ELF に含まれているセクションとは異なっているのがわかります。
$ nasm -f win64 02_test.asm -o win.obj $ x86_64-w64-mingw32-cc -o test.exe test1.c win.obj $ objdump -h test.exe test.exe: ファイル形式 pei-x86-64 セクション: Idx Name Size VMA LMA File off Algn 0 .text 00006d08 0000000140001000 0000000140001000 00000600 2**4 CONTENTS, ALLOC, LOAD, READONLY, CODE, DATA 1 .data 000000e0 0000000140008000 0000000140008000 00007400 2**4 CONTENTS, ALLOC, LOAD, DATA 2 .rdata 00000de0 0000000140009000 0000000140009000 00007600 2**4 CONTENTS, ALLOC, LOAD, READONLY, DATA 3 .eh_frame 00000004 000000014000a000 000000014000a000 00008400 2**2 CONTENTS, ALLOC, LOAD, DATA 4 .pdata 00000480 000000014000b000 000000014000b000 00008600 2**2 CONTENTS, ALLOC, LOAD, READONLY, DATA 5 .xdata 00000444 000000014000c000 000000014000c000 00008c00 2**2 CONTENTS, ALLOC, LOAD, READONLY, DATA 6 .bss 00000be0 000000014000d000 000000014000d000 00000000 2**4 ALLOC 7 .idata 00000760 000000014000e000 000000014000e000 00009200 2**2 CONTENTS, ALLOC, LOAD, DATA 8 .CRT 00000060 000000014000f000 000000014000f000 00009a00 2**2 CONTENTS, ALLOC, LOAD, DATA 9 .tls 00000010 0000000140010000 0000000140010000 00009c00 2**2 CONTENTS, ALLOC, LOAD, DATA 10 .reloc 00000084 0000000140011000 0000000140011000 00009e00 2**2 CONTENTS, ALLOC, LOAD, READONLY, DATA 11 .debug_aranges 00000670 0000000140012000 0000000140012000 0000a000 2**0 CONTENTS, READONLY, DEBUGGING 12 .debug_info 00013018 0000000140013000 0000000140013000 0000a800 2**0 CONTENTS, READONLY, DEBUGGING 13 .debug_abbrev 000032c0 0000000140027000 0000000140027000 0001da00 2**0 CONTENTS, READONLY, DEBUGGING 14 .debug_line 000069b3 000000014002b000 000000014002b000 00020e00 2**0 CONTENTS, READONLY, DEBUGGING 15 .debug_frame 00002168 0000000140032000 0000000140032000 00027800 2**0 CONTENTS, READONLY, DEBUGGING 16 .debug_str 0000042e 0000000140035000 0000000140035000 00029a00 2**0 CONTENTS, READONLY, DEBUGGING 17 .debug_line_str 00002f8d 0000000140036000 0000000140036000 0002a000 2**0 CONTENTS, READONLY, DEBUGGING 18 .debug_loclists 0000787d 0000000140039000 0000000140039000 0002d000 2**0 CONTENTS, READONLY, DEBUGGING 19 .debug_rnglists 00000526 0000000140041000 0000000140041000 00034a00 2**0 CONTENTS, READONLY, DEBUGGING
ELF に含まれているセクションとは異なっているのがわかります。