ELFの実行可能ヘッダーについて
実行可能ヘッダーを詳しく見ていこうと思います。
実行可能ヘッダーの定義
ターミナルでman elf
を入力することで確認することができます。
#define EI_NIDENT 16 typedef struct { unsigned char e_ident[EI_NIDENT]; uint16_t e_type; uint16_t e_machine; uint32_t e_version; ElfN_Addr e_entry; ElfN_Off e_phoff; ElfN_Off e_shoff; uint32_t e_flags; uint16_t e_ehsize; uint16_t e_phentsize; uint16_t e_phnum; uint16_t e_shentsize; uint16_t e_shnum; uint16_t e_shstrndx; } ElfN_Ehdr;
e_ident配列
e_identは16バイトの配列です。この配列の先頭にはELFファイルであることを示す、0x7f454c46という値が入っています。
続いて、このELFファイルが何ビットのアーキテクチャで構成されているかを表す値が入ります。
- 32ビット => 1
- 64ビット => 2
その後にはバイトオーダーを示すビット列が並びます。
次のバイトには、ELFのバージョンが入ります。現在のバージョンは1しかありません。
最後は、ABI(Application Binary Interface)とOSの情報を示す値が格納されます。ここは難しくてよく分かりませんでしたが、デフォルトの値は0入るそうです。
e_typeフィールド
このフィールドには、バイナリの種類が入ります。
- ET_NONE(ファイルタイプが存在しない) => 0
- ET_REL(再配置可能ファイル) => 1
- ET_EXEC(実行可能ファイル) => 2
- ET_DYN(共有オブジェクトファイル) => 3
- ET_CORE(コアファイル) => 4
e_machineフィールド
このフィールドには、バイナリを実行するアーキテクチャが入ります。下記に有名なものを抜粋しました。
- ARM 32-bit architecture => 40(0x28)
- AMD x86-64 architecture => 62(0x3E)
- ARM 64-bit architecture => 183(0xB7)
e_versionフィールド
ここには、e_ident配列にも記述されていたELFファイルのバージョンが入ります。
現状は1しかありません。
e_entryフィールド
このフィールドには、バイナリのエントリポイントと呼ばれる、実行を開始すべき場所の仮想アドレスが入ります。
環境によって入る値が変わります。
例:0x400100
e_phoffフィールド
これは、プログラムヘッダーテーブルのファイルオフセットを示します。64ビットアーキテクチャの場合、64(0x40)となります。
※ ファイルオフセット‥ヘッダーにたどり着くまでにファイルから読み取らなければならないバイト数のこと
e_shoffフィールド
ここは、セクションヘッダーテーブルのファイルオフセットを示します。環境によって大きく値が違ってきます。
セクションヘッダーテーブルが存在しない場合、0が入ります。
e_flagsフィールド
このフィールドには、プロセッサ固有のフラグが入ります。
x86バイナリの場合は、基本的に0が入るそうです。
e_ehsizeフィールド
実行可能ヘッダーの大きさを表します。
e_phentsizeフィールド
ELFファイルのプログラムヘッダーテーブルのエントリサイズをバイト単位で示します。
例:56バイト(0x38)
e_phnumフィールド
このフィールドは、プログラムヘッダテーブルのエントリ数を表します。
例:9
e_phentsizeフィールドとe_phnumフィールドの値を掛けることによって、プログラムヘッダーテーブル内の合計サイズを求めることができます。
e_shentsizeフィールド
このフィールドには、セクションヘッダーテーブルのエントリサイズをバイト単位で示します。
例:64バイト(0x40)
e_shnumフィールド
ここには、セクションヘッダーテーブルのエントリ数が入ります。
例:31(0x1F)
e_shentsizeフィールドとe_shnumフィールドの値を掛けることによって、セクションヘッダーテーブルの内の合計サイズを求めることができます。
e_shstrndxフィールド
このフィールドには、セクションヘッダー文字列テーブルのインデックスが記述されています。
例:28(0x1C)
まとめ
最初の方はイメージしやすかったのですが、後半のフィールド値の役割や意味をあまり理解できませんでした。 しかし、プログラムヘッダーやセクションヘッダーについて少し触れることができました。
次は、セクションヘッダーについて詳しく勉強していこうと思います。