出力フォーマット

出力ファイルのフォーマット
アセンブラの解説をする前に、まずは、実行ファイル/オブジェクトファイルのフォーマットについて説明します。

実行ファイル/オブジェクトファイルのファイル形式は、OS によって異なります。

Unix などELF (Executable and Linkable Format)
WindowsPE (Portable Executable) [拡張 COFF 形式]
MacOSMach-O
ELF フォーマット
Linux などで使われる ELF ファイルの構造は、以下のようになっています。

[ELF ヘッダ]
[プログラムヘッダ]
[セクション or セグメント]
...
[セクションヘッダ]

プログラムヘッダは、オブジェクトファイルには存在しない場合があります。

データの種類ごとに、セクションやセグメントが複数個存在し、それぞれに名前を付けることができます。

セグメントは、実際に実行された時にロードされる一つの単位で、セクションは、フォーマット上の一つの単位です。

x64 の 64bit モードの場合、セグメントは一つとして扱われるので、すべてのセクションは、実行時に一つに結合されます。
16/32bit のモードの場合、一つのプログラムは複数のセグメントで構成されます。
セクション名
以下は、基本的なセクションです。
※実際に使用されるセクション名は、出力フォーマットごとに異なります。

ELFPEMach-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 ディレクティブを使うことで、以降に出力されるバイナリを配置するセクション (またはセグメント) を切り替えることができます。

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 用のオブジェクトを出力してみましょう。

# 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 ファイルを逆アセンブルしてみてください。

$ 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 コマンドで、バイナリ中の表示可能な文字列を表示してみてください。

$ strings mac.o

__text
__TEXT
testfunc

「__TEXT」「__text」という文字があります。これがセグメント名とセクション名です。
.text セクションが、Mach-O に対応するセグメント名とセクション名に変換されていることがわかります。

また、バイナリエディタで開いてみると、終端近くに「b8 7b 00 00 00 c3」のバイナリコードが見つかります。
実行ファイルのセクション情報
ELF と PE で、実行ファイルに含まれるセクションがどのように違うか、確認してみます。

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 用の実行ファイルをコンパイルしてみます。

$ 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 に含まれているセクションとは異なっているのがわかります。