引用:https://linuxjm.osdn.jp/html/LDP_man-pages/man5/elf.5.html

概要

ヘッダーファイル <elf.h> は ELF 実行可能バイナリファイルのフォーマットを定義する。 これらのファイルとしては、通常の実行可能ファイル・ 再配置可能オブジェクトファイル・コアファイル・共有ライブラリがある。

ELF ファイルフォーマットを使う実行可能ファイルは、 ELF ヘッダーの後にプログラムヘッダーテーブルまたは セクションヘッダーテーブル (またはその両方) が続く構成である。 ELF ヘッダーは常にファイルのオフセット 0 にある。 プログラムヘッダーテーブルとセクションヘッダーテーブルの ファイル内でのオフセットは、ELF ヘッダーに定義されている。 この 2 つのテーブルはファイルの残りの部分の詳細を記述する。

このヘッダーファイルは上記のヘッダーを C 言語の構造体で記述し、 また動的セクション・再配置可能セクション・シンボルテーブルの構造体も 含んでいる。

以下の型は N ビットアーキテクチャーで使われる (N=32,64 であり ElfN は Elf32 または Elf64 を表し、 uintN_t は uint32_t または uint64_t を表す):

型名対応説明
ElfN_AddruintN_t符号なしのプログラムアドレス
ElfN_OffuintN_t符号なしのファイルオフセット
ElfN_Sectionuint16_t符号なしのセクションインデックス
ElfN_Versymuint16_t符号なしのバージョンシンボル情報
Elf_Byteunsigned char
ElfN_Halfuint16_t
ElfN_Swordint32_t
ElfN_Worduint32_t
ElfN_Sxwordint64_t
ElfN_Xworduint64_t

(注意: *BSD での用語は少し異なる。 Elf64_Half は Elf32_Half の 2 倍であり、Elf64Quarter が uint16_t に用いられる。 混乱を避けるため、以下では、これらの型はサイズが自明な型に置き換えてある。)

このファイルフォーマットが定義する全てのデータ構造体は、 関連するクラスの “自然な” サイズと配置の指針に従う。 必要な場合、データ構造体では明示的なパディング (padding, 詰め込み) が行なわれる。これは 4 バイトオブジェクトに対する 4 バイト配置を保証するためや、 構造体のサイズを 4 の倍数にするためなどである。

ELF ヘッダー

ELF ヘッダーは型 Elf32_Ehdr または Elf64_Ehdr で記述される:

#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
    • このバイト配列は、プロセッサやファイルの他の部分には依存せずに、 ファイルを解釈 (interpret) するために指定される。 この配列内のすべてのものは、接頭辞 EI_ で始まるマクロの名前が付き、接頭辞 ELF で始まる値を持つ。 以下のマクロが定義されている:
    • EI_MAG0:マジックナンバーの第 1 バイト。 ELFMAG0 で埋めなければならない。 (0: 0x7f)
    • EI_MAG1:マジックナンバーの第 2 バイト。 ELFMAG1 で埋めなければならない。 (1: ‘E’)
    • EI_MAG2:マジックナンバーの第 3 バイト。 ELFMAG2 で埋めなければならない。 (2: ‘L’)
    • EI_MAG3:マジックナンバーの第 4 バイト。 ELFMAG3 で埋めなければならない。 (3: ‘F’)
    • EI_CLASS
      • 第 5 バイトは、このバイナリのアーキテクチャーを示す:
        • ELFCLASSNONE:このクラスは不正である。
        • ELFCLASS32:32 ビットアーキテクチャーを定義する。 ファイルと仮想アドレス空間が 4 ギガバイトまでのマシンをサポートする。
        • ELFCLASS64:64 ビットアーキテクチャーを定義する。
        • EI_DATA:第 6 バイトはファイル内のプロセッサ固有データの データエンコーディングを指定する。 現在のところ以下のエンコーディングがサポートされている:
        • ELFDATANONE:不明なデータフォーマット。
        • ELFDATA2LSB:2 の補数、リトルエンディアン。
        • ELFDATA2MSB:2 の補数、ビッグエンディアン。
    • EI_VERSION
      • 第 7 バイトは ELF 仕様のバージョン番号である:
        • EV_NONE:不正なバージョン。
        • EV_CURRENT:現在のバージョン。
    • EI_OSABI
      • 第 8 バイトはオブジェクトのターゲットとなるオペレーティングシステムと ABI を示す。他の ELF 構造体のフィールドには、プラットフォーム固有の意味を持つフラグや値を持つものもある。これらのフィールドの解釈は、このバイトの値によって決定される。以下に例を挙げる。
      • ELFOSABI_NONE:ELFOSABI_SYSV と同じ。
      • ELFOSABI_SYSV:UNIX System V ABI.
      • ELFOSABI_HPUX:HP-UX ABI.
      • ELFOSABI_NETBSD:NetBSD ABI.
      • ELFOSABI_LINUX:Linux ABI.
      • ELFOSABI_SOLARIS:Solaris ABI.
      • ELFOSABI_IRIX:IRIX ABI.
      • ELFOSABI_FREEBSD:FreeBSD ABI.
      • ELFOSABI_TRU64:TRU64 UNIX ABI.
      • ELFOSABI_ARM:ARM アーキテクチャー ABI.
      • ELFOSABI_STANDALONE:スタンドアロン (組み込み) ABI.
    • EI_ABIVERSION
      • 第 9 バイトはオブジェクトがターゲットとしている ABI のバージョンを示す。 このフィールドは互換性のない ABI のバージョンを区別するために使われる。 このバージョン番号の解釈は、 EI_OSABI フィールドで識別される ABI に依存する。 この仕様に準拠するアプリケーションでは、値 0 を使う。
    • EI_PAD
      • パディングの開始。 これらのバイトは予約されており、0 に設定されている。 これらを読み込むプログラムは、これらのバイトを無視すべきである。 現在使われていないバイトに意味が与えられる場合、 EI_PAD の値は将来変更されるかもしれない。
    • EI_NIDENT
      • e_ident 配列のサイズ。
  • e_type
    • この構造体のメンバはオブジェクトファイルタイプを示す:
      • ET_NONE:不明なタイプ。
      • ET_REL:再配置可能ファイル。
      • ET_EXEC:実行可能ファイル。
      • ET_DYN:共有オブジェクト。
      • ET_CORE:コアファイル。
  • e_machine
    • このメンバは個々のファイルに必要とされるアーキテクチャーを指定する。 例:
      • EM_NONE:不明なマシン。
      • EM_M32:AT&T WE 32100.
      • EM_SPARC:Sun Microsystems SPARC.
      • EM_386:Intel 80386.
      • EM_68K:Motorola 68000.
      • EM_88K:Motorola 88000.
      • EM_860:Intel 80860.
      • EM_MIPS:MIPS RS3000 (ビッグエンディアンのみ)。
      • EM_PARISC:HP/PA.
      • EM_SPARC32PLUS:拡張命令セット付き SPARC。
      • EM_PPC:PowerPC.
      • EM_PPC64:PowerPC 64-bit.
      • EM_S390:IBM S/390
      • EM_ARM:Advanced RISC Machines
      • EM_SH:Renesas SuperH
      • EM_SPARCV9:SPARC v9 64-bit.
      • EM_IA_64:Intel Itanium
      • EM_X86_64:AMD x86-64
      • EM_VAX:DEC Vax.
  • e_version
    • このメンバはファイルバージョンを示す:
    • EV_NONE
      • 不正なバージョン。
    • EV_CURRENT
      • 現在のバージョン。
  • e_entry
    • このメンバは、システムが最初に制御を渡す、 つまりプロセスを開始する仮想アドレスを指定する。 ファイルにエントリーポイントが関連付けられていない場合、 このメンバには 0 が入る。
  • e_phoff
    • このメンバはプログラムヘッダーテーブルの ファイルオフセット (バイト単位) を保持する。 ファイルにプログラムヘッダーテーブルがない場合、 このメンバには 0 が入る。
  • e_shoff
    • このメンバはセクションヘッダーテーブルの ファイルオフセット (バイト単位) を保持する。 ファイルにセクションヘッダーテーブルがない場合、 このメンバには 0 が入る。
  • e_flags
    • このメンバはファイルに関連付けられたプロセッサ固有のフラグを保持する。 フラグの名前は EF_machine_flag という形式である。 現在のところフラグは定義されていない。
  • e_ehsize
    • このメンバは ELF ヘッダーサイズ (バイト単位) を保持する。
  • e_phentsize
    • このメンバはこのファイルのプログラムヘッダーテーブルの 1 エントリーあたりのサイズ (バイト単位) を保持する; 全てのエントリーは同じサイズである。
  • e_phnum
    • このメンバはプログラムヘッダーテーブルにあるエントリーの数を保持する。 よって e_phentsize と e_phnum の積がテーブルサイズ (バイト単位) になる。 ファイルにプログラムヘッダーがない場合、 e_phnum は値 0 を保持する。
    • プログラムヘッダーテーブルのエントリー数が PN_XNUM (0xffff) 以上の場合、 このメンバは PN_XNUM (0xffff) になり、プログラムヘッダーテーブルの エントリーの実際の数は、セクションヘッダーテーブルの最初のエントリーの sh_info メンバに格納される。それ以外の場合、セクションヘッダーテーブルの 最初のエントリーの sh_info メンバには値 0 が格納される。
      • PN_XNUMe_phnum が保持できる最大値を表し、 0xffff に定義されている。 e_phnum はプログラムヘッダーの実際の数がどこに割り当てられているかを示す。
  • e_shentsize
    • このメンバはセクションヘッダーのサイズ (バイト単位) を保持する。 セクションヘッダーはセクションヘッダーテーブルの 1 つのエントリーである; 全てのエントリーは同じサイズである。
  • e_shnum
    • このメンバはセクションヘッダーテーブルにあるエントリーの数を保持する。 よって e_shentsize と e_shnum の積はセクションヘッダーテーブルのサイズ (バイト単位) になる。 ファイルにセクションヘッダーテーブルがない場合、 e_shnum は値 0 を保持する。
    • セクションヘッダーテーブルのエントリー数が SHN_LORESERVE (0xff00) 以上の場合、 e_shnum には値 0 が入り、セクションヘッダーテーブルのエントリーの実際の数は セクションヘッダーテーブルの最初のエントリーの sh_size メンバに格納される。 それ以外の場合、セクションヘッダーテーブルの最初のエントリーの sh_info メンバ には値 0 が格納される。
  • e_shstrndx
    • このメンバはセクション名文字列テーブルに関連付けられたエントリーの セクションヘッダーテーブルインデックスを保持する。 ファイルにセクション名文字列テーブルがない場合、 このメンバは値 SHN_UNDEF を保持する。 SHN_UNDEF.
    • セクション名前文字列テーブルのインデックスが SHN_LORESERVE (0xff00) 以上の 場合、このメンバには SHN_XINDEX (0xffff) が入り、セクション名前文字列 テーブルの実際のインデックスはセクションヘッダーテーブルの最初のエントリーの sh_link メンバに格納される。それ以外の場合、セクションヘッダーテーブルの 最初のエントリーの sh_link メンバには値 0 が格納される。
      • SHN_UNDEF
        • この値は未定義・存在しない・無関係その他、 意味のないセクションの参照であることを表す。 例えば、セクション番号 SHN_UNDEF に関連づけて「定義」されたシンボルは、「未定義」なシンボルである。
      • SHN_LORESERVE
        • この値は予約済みのインデックス領域の下限を指定する。
      • SHN_LOPROC
        • この値以上で SHN_HIPROC 以下の値はプロセッサ固有の意味に予約されている。
      • SHN_HIPROC
        • この値以下で SHN_HIPROC 以上の値はプロセッサ固有の意味に予約されている。
      • SHN_ABS
        • この値は対応する参照の絶対値を指定する。 例えば、セクション番号 SHN_ABS に関連づけられたシンボルは絶対値を保持し、再配置に影響されない。
      • SHN_COMMON
        • このセクションに関連して定義されたシンボルは、 Fortran の COMMON や C の未割り当て external 変数のような、 共通シンボルである。
      • SHN_HIRESERVE
        • この値は予約されたインデックスの範囲の上限を指定する。 SHN_LORESERVE と SHN_HIRESERVE は含まれる。 この値はセクションヘッダーテーブルを参照しない。 つまり、セクションヘッダーテーブルは 予約されたインデックスのエントリーを 含まない 。

プログラムヘッダー

実行可能ファイルまたは共有オブジェクトファイルのプログラムヘッダーテーブルは、 システムによるプログラム実行準備に必要な、 セグメント等の情報を記述する構造体の配列である。 オブジェクトファイルの セグメント には 1 つ以上の セクション が含まれる。 プログラムヘッダーは実行可能ファイルと共有オブジェクトファイルでのみ意味を持つ。 ファイルは自身のプログラムヘッダーサイズを ELF ヘッダーの e_phentsize メンバと e_phnum メンバで指定する。 ELF プログラムヘッダーは Elf32_Phdr 型または Elf64_Phdr 型で記述される (どちらになるかはアーキテクチャー依存):

typedef struct {
    uint32_t   p_type;
    Elf32_Off  p_offset;
    Elf32_Addr p_vaddr;
    Elf32_Addr p_paddr;
    uint32_t   p_filesz;
    uint32_t   p_memsz;
    uint32_t   p_flags;
    uint32_t   p_align;
} Elf32_Phdr;
 
typedef struct {
    uint32_t   p_type;
    uint32_t   p_flags;
    Elf64_Off  p_offset;
    Elf64_Addr p_vaddr;
    Elf64_Addr p_paddr;
    uint64_t   p_filesz;
    uint64_t   p_memsz;
    uint64_t   p_align;
} Elf64_Phdr;

32 ビットと 64 ビットのプログラムヘッダーの主な違いは、構造体における p_flags メンバの位置にある。

  • p_type
    • Phdr 構造体のこのメンバは、 この配列要素がどのような種類のセグメントを記述しているか、 またはこの配列要素の情報をどのように解釈するか、を表す。
    • PT_NULL
      • この配列要素は使用されておらず、その他のメンバの値は未定義である。 これにより、このプログラムヘッダーのエントリーは無視される。
    • PT_LOAD
      • この配列要素は p_filesz と p_memsz で記述されるロード可能セグメントを指定する。 このファイルからのバイトデータが、このメモリーセグメントの先頭からマップされる。 セグメントのメモリーサイズ _Sy_p_memsz がファイルサイズ _Sy_p_filesz より大きい場合、 「余った」バイトは値 0 となり、 そのセグメント初期化データの後ろに置かれると定められている。 ファイルサイズはメモリーサイズより大きくてはいけない。 プログラムヘッダーテーブルのロード可能セグメントエントリーは、 p_vaddr メンバの昇順にソートされて出現する。
    • PT_DYNAMIC
      • この配列要素は動的リンク情報を指定する。
    • PT_INTERP
      • この配列要素は、インタープリターとして起動されるパス名 (ヌル文字終端) の位置とサイズを指定する。 このセグメント型は (共有オブジェクトにもあるかも知れないが) 実行可能ファイルでのみ意味を持つ。 ただし、このセグメント型は 1 つのファイルに 2 回以上出現してはならない。 もし存在する場合、このセグメント型は 全てのロード可能セグメントエントリーより前になければならない。
    • PT_NOTE
      • この配列要素は補足情報 (auxiliary information) の位置とサイズを指定する。
    • PT_SHLIB
      • このセグメント型は予約されているが、意味は指定されていない。 この型の配列要素を保持するプログラムは ABI に準拠しない。
    • PT_PHDR
      • この配列要素は、もし存在しているならば、 ファイルおよびプログラムのメモリーイメージ双方における プログラムヘッダーテーブル自身の位置とサイズを指定する。 このセグメント型は 1 つのファイルに 2 回以上出現してはならない。 さらに、このセグメント型が存在してもよいのは、プログラムヘッダーテーブルが プログラムのメモリーイメージの一部である場合のみである。 もし存在する場合、これは全てのロード可能セグメントエントリーより 前になければならない。
    • PT_LOPROC
      • この値以上で PT_HIPROC 以下の値はプロセッサ固有の意味に予約されている。
    • PT_HIPROC
      • この値以下で PT_LOPROC 以上の値はプロセッサ固有の意味に予約されている。
    • PT_GNU_STACK
      • GNU 拡張であり、Linux カーネルが p_flags のメンバーにセットされたフラグ経由でスタックの状態を制御するために使用する。
  • p_offset
    • このメンバは、セグメントの先頭バイトがある (ファイル先頭からの) オフセットを保持する。
  • p_vaddr
    • このメンバは、セグメントの先頭バイトがある メモリーの仮想アドレスを保持する。
  • p_paddr
    • 物理アドレスが意味をもつシステムでは、 このメンバはセグメントの物理アドレスとして予約されている。 BSD ではこのメンバは使用されない。0 でなければならない。
  • p_filesz
    • このメンバはセグメントのファイルイメージのバイト数を保持する。 これは 0 でもよい。
  • p_memsz
    • このメンバはセグメントのメモリーイメージのバイト数を保持する。 これは 0 でもよい。
  • p_flags
    • このメンバはセグメントに関連するフラグのビットマスクを保持する:
      • PF_X:実行可能セグメント。
      • PF_W:書き込み可能セグメント.
      • PF_R:読み込み可能セグメント。
    • テキストセグメントは一般にフラグ PF_X と PF_R を持つ。 データセグメントは一般に PF_XPF_WPF_R を持つ。
  • p_align
    • このメンバは、セグメントがメモリーおよびファイルにおいて配置 (align) される値を保持する。 ロード可能プロセスセグメントは、ページサイズを法として p_vaddr と p_offset と合同でなければならない (訳注:「p_vaddr mod ページサイズ = p_offset mod ページサイズ」 でなければならない)。。 0 と 1 という値は配置が必要ないことを意味する。 それ以外の場合、 p_align は正で 2 の整数乗でなければならず、 p_vaddr は p_align を法として p_offset と合同でなければならない (訳注:「p_vaddr mod p_align = p_offset mod p_align」でなければならない)。

ファイルのセクションヘッダーテーブルには、 全てのファイルセクションの場所が記述されている。 セクションヘッダーテーブルは Elf32_Shdr 構造体または Elf64_Shdr 構造体の配列である。 ELF ヘッダーの e_shoff メンバはファイルの先頭から セクションヘッダーテーブルへのバイトオフセットである。 e_shnum はセクションヘッダーテーブルに含まれるエントリーの数を保持する。 e_shentsize は各エントリーのサイズ (バイト単位) を保持する。

セクションヘッダーテーブルインデックス

セクションヘッダーテーブルインデックスは、この配列の添字である。 いくつかのセクションヘッダーテーブルインデックスは予約されている。予約されて いるのは、最初のエントリーと、SHN_LORESERVE と SHN_HIRESERVE の間の インデックスである。 最初のエントリーは、ELF 拡張で e_phnume_shnume_strndx に使用 される。それ以外の場合、最初のエントリーの各フィールドには 0 が設定される。 オブジェクトファイルにはこれらの特別なインデックスに対応するセクションはない。

  • SHN_UNDEF
    • この値は、未定義 (undefined)、不足 (missing)、無関係 (irrelevant)、その他無意味なセクション参照を示す。
  • SHN_LORESERVE
    • この値は予約済みのインデックス領域の下限を指定する。
  • SHN_LOPROC
    • この値以上で SHN_HIPROC 以下の値はプロセッサ固有の意味に予約されている。
  • SHN_HIPROC
    • この値以下で SHN_HIPROC 以上の値はプロセッサ固有の意味に予約されている。
  • SHN_ABS
    • この値は対応する参照の絶対値を指定する。 例えば、セクション番号 SHN_ABS に関連して定義されているシンボルは、 絶対値を保持しているので、再配置に影響されない。
  • SHN_COMMON
    • このセクションに関連して定義されているシンボルは、 FORTRAN の COMMON や C の未割り当て外部変数のような共通シンボルである。
  • SHN_HIRESERVE
    • この値は予約済みのインデックス領域の上限を指定する。 システムは SHN_LORESERVE と SHN_HIRESERVE を含む範囲を予約する。 セクションヘッダーテーブルは予約されたインデックスに対応するエントリーを持たない。

セクションヘッダー

セクションヘッダーは以下の構造体を持つ:

typedef struct {
    uint32_t   sh_name;
    uint32_t   sh_type;
    uint32_t   sh_flags;
    Elf32_Addr sh_addr;
    Elf32_Off  sh_offset;
    uint32_t   sh_size;
    uint32_t   sh_link;
    uint32_t   sh_info;
    uint32_t   sh_addralign;
    uint32_t   sh_entsize;
} Elf32_Shdr;
 
typedef struct {
    uint32_t   sh_name;
    uint32_t   sh_type;
    uint64_t   sh_flags;
    Elf64_Addr sh_addr;
    Elf64_Off  sh_offset;
    uint64_t   sh_size;
    uint32_t   sh_link;
    uint32_t   sh_info;
    uint64_t   sh_addralign;
    uint64_t   sh_entsize;
} Elf64_Shdr;

32 ビットと 64 ビットのセクションヘッダーには実際の違いはない。

  • sh_name
    • このメンバはセクション名を定める。 この値はセクションヘッダー文字列テーブルセクションのインデックスであり、 ヌル文字で終端された文字列の場所を示す。
  • sh_type
    • このメンバはセクションの内容と意味が含まれるカテゴリーを示す。
    • SHT_NULL
      • この値はセクションヘッダーが不活性であることを示す。 これは関連するセクションを持たない。 このセクションヘッダーの他のメンバは、未定義の値を持つ。
    • SHT_PROGBITS
      • このセクションはプログラムにより定義される情報を保持する。 この情報の形式と意味は、ひとえにプログラムによって決定される。
    • SHT_SYMTAB
      • このセクションはシンボルテーブルを保持する。 一般には SHT_SYMTAB はリンク編集のためのシンボルを提供するが、 動的リンクにも使われる。 完全なシンボルテーブルとして、動的リンクには不要な 多くのシンボルを保持できる。 オブジェクトファイルも SHT_DYNSYM セクションを持つことができる。
    • SHT_STRTAB
      • このセクションは文字列テーブルを保持する。 オブジェクトファイルは複数の文字列テーブルセクションを持つことができる。
    • SHT_RELA
      • このセクションは明示的な加数 (addend) を持つ再配置エントリーを保持する。 再配置エントリーの型は、オブジェクトファイルの 32 ビットクラスでは Elf32_Rela である。 オブジェクトファイルは複数の再配置セクションを持つことができる。
    • SHT_HASH
      • このセクションはシンボルハッシュテーブルを保持する。 動的リンクされるオブジェクトは、 シンボルハッシュテーブルを含んでいなければならない。 オブジェクトファイルは 1 つのハッシュテーブルのみを持つことができる。
    • SHT_DYNAMIC
      • このセクションは動的リンクの情報を保持する。 オブジェクトファイルは 1 つの動的セクションのみを持つことができる。
    • SHT_NOTE
      • このセクションはファイルに何らかの印を付ける情報を保持する。
    • SHT_NOBITS
      • このタイプのセクションはファイルの領域を使わないという以外は、 SHT_PROGBITS と似ている。 このセクションは 1 バイトも含まないが、 sh_offset メンバは概念的なファイルオフセットを持つ。
    • SHT_REL
      • このセクションは明示的な加数を持たない再配置オフセットを保持する。 再配置オフセットの型は、オブジェクトファイルの 32 ビットクラスでは Elf32_Rel である。 オブジェクトファイルは複数の再配置セクションを持つことができる。
    • SHT_SHLIB
      • このセクションは予約されているが、意味は指定されていない。
    • SHT_DYNSYM
      • このセクションは動的リンクシンボルの最小セットを保持する。 オブジェクトファイルは SHT_SYMTAB セクションも含むことができる。
    • SHT_LOPROC
      • この値以上で SHT_HIPROC 以下の範囲はプロセッサ固有の意味に予約されている。
    • SHT_HIPROC
      • この値以下で SHT_LOPROC 以上の範囲はプロセッサ固有の意味に予約されている。
    • SHT_LOUSER
      • この値はアプリケーションプログラムのために予約される インデックス範囲の下限を指定する。
    • SHT_HIUSER
      • この値はアプリケーションプログラムのために予約される インデックス範囲の上限を指定する。 SHT_LOUSER から SHT_HIUSER の間のセクションタイプは、 現在または将来のシステム定義セクションタイプと衝突することなく、 アプリケーションで使用することができる。
  • sh_flags
    • 様々な属性を記述するための 1 ビットのフラグをサポートするセクション。 フラグビットが sh_flags に設定された場合、そのセクションについての属性は “オン” になる。 それ以外の場合、属性が “オフ” であるか属性が適用されない。 未定義の属性は 0 に設定される。
    • SHF_WRITE
      • このセクションはプロセス実行中に書き込み可能なデータを含む。
    • SHF_ALLOC
      • このセクションはプロセス実行中にメモリーを使用する。 制御セクションの中には、オブジェクトファイルのメモリーイメージには 存在しないものもある。 そうしたセクションの場合、この属性はオフである。
    • SHF_EXECINSTR
      • このセクションは実行可能なマシン命令を含む。
    • SHF_MASKPROC
      • このマスクに含まれる全てのビットはプロセッサ固有の意味に予約されている。
  • sh_addr
    • このセクションがプロセスのメモリーイメージにある場合、 このメンバはセクションの最初のバイトが存在するアドレスを保持する。 それ以外の場合、このメンバは 0 である。
  • sh_offset
    • このメンバの値は、ファイルの先頭からセクションの最初のバイトへの バイトオフセットを保持する。 セクションタイプ SHT_NOBITS はファイルの領域を全く使用せず、このタイプの sh_offset メンバはファイルの概念的な位置を示す。
  • sh_size
    • このメンバはセクションのサイズ (バイト単位) を保持する。 セクションタイプが SHT_NOBITS でない限り、そのセクションはファイル中の sh_size バイトを使用する。 タイプが SHT_NOBITS のセクションはサイズが 0 でないが、ファイルの領域を使用しない。
  • sh_link
    • このメンバは、セクションヘッダーテーブルインデックスリンクを保持する。 この解釈はセクションタイプに依存する。
  • sh_info
    • このメンバは追加情報を保持する。 この解釈はセクションタイプに依存する。
  • sh_addralign
    • アドレス配置に制約があるセクションもある。 セクションが倍長語 (doubleword) を保持する場合、 システムは全てのセクションについて倍長語の配置を保証しなければならない。 つまり、 sh_addr の値は sh_addralign の値を法として 0 と合同でなければならない (訳注:「sh_addr mod sh_addralign = 0 でなければならない)。 2 の 0 乗と正の整数乗のみが許可される。 0 または 1 はセクションの配置に制約がないことを意味する。
  • sh_entsize
    • シンボルテーブルのような固定サイズエントリーのテーブルを保持する セクションもある。 このようなセクションでは、 このメンバは各エントリーのサイズ (バイト単位) を表す。 このメンバが 0 の場合、 そのセクションは固定サイズエントリーのテーブルを保持しない。

セクションの種類

さまざまなセクションにプログラム情報・制御情報が保持される:

  • .bss
    • このセクションはプログラムのメモリーイメージに配置される 非初期化データを保持する。 定義上、システムはプログラムの実行開始時に、データを 0 で初期化する。 このセクションのタイプは SHT_NOBITS である。 属性タイプは SHF_ALLOC と SHF_WRITE である。
  • .comment
    • このセクションはバージョン制御情報を保持する。 このセクションのタイプは SHT_PROGBITS である。 属性タイプは使用されない。
  • .ctors
    • このセクションは C++ コンストラクター関数への初期化されたポインターを保持する。 このセクションのタイプは SHT_PROGBITS である。 属性タイプは SHF_ALLOC と SHF_WRITE である。
  • .data
    • このセクションはプログラムのメモリーイメージに配置される 初期化済みデータを保持する。 このセクションのタイプは SHT_PROGBITS である。 属性タイプは SHF_ALLOC と SHF_WRITE である。
  • .data1
    • このセクションはプログラムのメモリーイメージに配置される 初期化済みデータを保持する。 このセクションのタイプは SHT_PROGBITS である。 属性タイプは SHF_ALLOC と SHF_WRITE である。
  • .debug
    • このセクションはシンボリックデバッグ用の情報を保持する。 その内容は指定されていない。 このセクションのタイプは SHT_PROGBITS である。 属性タイプは使用されない。
  • .dtors
    • このセクションは C++ デストラクタ関数への初期化されたポインターを保持する。 このセクションのタイプは SHT_PROGBITS である。 属性タイプは SHF_ALLOC と SHF_WRITE である。
  • .dynamic
    • このセクションは動的リンク情報を保持する。 このセクションの属性は SHF_ALLOC ビットを含む。 SHF_WRITE ビットが設定されるか否かはプロセッサによる。 このセクションのタイプは SHT_DYNAMIC である。 上記の属性を参照すること。
  • .dynstr
    • このセクションは動的リンクに必要な文字列を保持する。 最も一般的には、この文字列はシンボルテーブルエントリーと 関連づけられた名前を表す。 このセクションのタイプは SHT_STRTAB である。 使用される属性タイプは SHF_ALLOC である。
  • .dynsym
    • このセクションは動的リンクシンボルテーブルを保持する。 このセクションのタイプは SHT_DYNSYM である。 使用される属性タイプは SHF_ALLOC である。
  • .fini
    • このセクションはプロセス終了コードに置かれる実行可能命令を保持する。 プロセスが正常に終了した場合、システムはこのセクションにある コードを配置して実行する。 このセクションのタイプは SHT_PROGBITS である。 使用される属性タイプは SHF_ALLOC と SHF_EXECINSTR である。
  • .gnu.version
    • このセクションはバージョンシンボルテーブルを保持する。 その内容は ElfN_Half 要素の配列である。 このセクションのタイプは SHT_GNU_versym である。 使用される属性タイプは SHF_ALLOC である。
  • .gnu.version_d
    • このセクションはバージョンシンボルの定義を保持する。 その内容は ElfN_Verdef 構造体のテーブルである。 このセクションのタイプは SHT_GNU_verdef である。 使用される属性タイプは SHF_ALLOC である。
  • .gnu.version_r
    • このセクションはバージョンシンボルが必要とする要素を保持する。 その内容は ElfN_Verneed 構造体のテーブルである。 このセクションのタイプは SHT_GNU_versym である。 使用される属性タイプは shf_alloc である。
  • .got
    • このセクションはグローバルオフセットテーブルを保持する。 このセクションのタイプは SHT_PROGBITS である。 属性はプロセッサ毎に異なる。
  • .hash
    • このセクションはシンボルハッシュテーブルを保持する。 セクションのタイプは SHT_HASH である。 使用される属性は SHF_ALLOC である。
  • .init
    • このセクションはプロセス初期化コードに配置される実行可能命令を保持する。 プログラムが実行を開始すると、 システムはメインプログラムエントリーポイントを呼び出す前に、 このセクションにあるコードを配置して実行する。 このセクションはのタイプは SHT_PROGBITS である。 使用される属性は SHF_ALLOC と SHF_EXECINSTR である。
  • .interp
    • このセクションはプログラムインタープリターのパス名を保持する。 ファイルにこのセクションを含むロード可能セグメントがある場合、 そのセクションの属性には SHF_ALLOC ビットが含まれる。 それ以外の場合このビットはオフになる。 このセクションのタイプは SHT_PROGBITS である。
  • .line
    • このセクションはシンボリックデバッグのための行番号情報を保持する。 ここにはプログラムソースコードとマシンコードの対応関係が記述される。 内容は指定されていない。 このセクションのタイプは SHT_PROGBITS である。 属性タイプは使用されない。
  • .note
    • このセクションは “Note Section” 形式で情報を保持する。このセクションのタイプ は SHT_NOTE である。属性タイプは使用されない。通常 OpenBSD ネイティブ実行 可能ファイルは自身を識別するために .note.openbsd.ident セクションを持つ。 これによりカーネルは、ファイルをロードする際に 互換 ELF バイナリエミュレーショ ンテストを回避できる。
  • .note.GNU-stack
    • このセクションは Linux のオブジェクトファイルで スタック属性を宣言するのに使用される。 セクションのタイプは SHT_PROGBITS である。使用される属性は SHF_EXECINSTR だけである。この属性は GNU リンカーに対して オブジェクトファイルが実行可能なスタック (executable stack) を必要とする 示すものである。
  • .plt
    • このセクションは手続き (procedure) リンクテーブルを保持する。 このセクションのタイプは SHT_PROGBITS である。 属性はプロセッサ毎に異なる。
  • .relNAME
    • このセクションは以下に記述される再配置情報を保持する。 ファイルが再配置を含むロード可能セグメントを持っている場合、 このセクションの属性は SHF_ALLOC ビットを含む。 それ以外の場合、そのビットはオフである。 慣例として、 “NAME” は再配置が適用されるセクションが指定される。 よって .text についての再配置セクションは、通常は .rel.text という名前を持つ。 このセクションのタイプは SHT_REL である。
  • .relaNAME
    • このセクションは以下に記述される再配置情報を保持する。 ファイルが再配置を含むロード可能セグメントを持っている場合、 このセクションの属性は SHF_ALLOC ビットを含む。 それ以外の場合、そのビットはオフである。 慣例として、 “NAME” は再配置が適用されるセクションが指定される。 よって .text についての再配置セクションは、通常は .rela.text という名前を持つ。 このセクションのタイプは SHT_RELA である。
  • .rodata
    • このセクションはリードオンリーのデータを保持する。 このデータはプロセスイメージにおける書き込み不可能なセグメントに置かれる。 このセクションのタイプは SHT_PROGBITS である。 使用される属性は SHF_ALLOC である。
  • .rodata1
    • このセクションはリードオンリーのデータを保持する。 このデータはプロセスイメージにおける書き込み不可能なセグメントに置かれる。 このセクションのタイプは SHT_PROGBITS である。 使用される属性は SHF_ALLOC である。
  • .shstrtab
    • このセクションはセクション名を保持する。 このセクションのタイプは SHT_STRTAB である。 属性タイプは使用されない。
  • .strtab
    • このセクションは文字列を保持する。 最も一般的なのは、シンボルテーブルエントリーに関連づけられた 名前を表す文字列である。 ファイルがシンボル文字列テーブルを含むロード可能セグメントを持つ場合、 セクションの属性は SHF_ALLOC ビットを含む。 それ以外の場合、そのビットはオフである。 このセクションのタイプは SHT_STRTAB である。
  • .symtab
    • このセクションはシンボルテーブルを保持する。 ファイルがシンボルテーブルを含むロード可能セグメントを持つ場合、 セクションの属性は SHF_ALLOC ビットを含む。 それ以外の場合、ビットはオフである。 このセクションのタイプは SHT_SYMTAB である。
  • .text
    • このセクションはプログラムの “テキスト” または実行可能命令を保持する。 セクションのタイプは SHT_PROGBITS である。 使用される属性は SHF_ALLOC と SHF_EXECINSTR である。

文字列テーブルセクション

文字列テーブルセクションはヌル文字で終端されたキャラクター配列 (通常文字列と呼ばれるもの) を保持する。 オブジェクトファイルはこれらの文字列を シンボル名とセクション名を表すために使う。 文字列は、文字列テーブルセクションへのインデックスとして参照される。 インデックス 0 の最初のバイトは、ヌルバイト (‘\0’) を 保持すると定義されている。 同様に文字列テーブルの最後のバイトもヌル文字を保持すると定義されている。 これは全ての文字列がヌルバイトで終端されていることを保証するためである。

シンボルテーブル

オブジェクトファイルのシンボルテーブルは、 プログラムのシンボル定義と参照を配置または再配置するのに 必要な情報を保持する。

typedef struct {
    uint32_t      st_name;
    Elf32_Addr    st_value;
    uint32_t      st_size;
    unsigned char st_info;
    unsigned char st_other;
    uint16_t      st_shndx;
} Elf32_Sym;
 
typedef struct {
    uint32_t      st_name;
    unsigned char st_info;
    unsigned char st_other;
    uint16_t      st_shndx;
    Elf64_Addr    st_value;
    uint64_t      st_size;
} Elf64_Sym;

32 ビット版と 64 ビット版は同じメンバを持ち、単に順番が異なるだけである。

  • st_name
    • このメンバはオブジェクトファイルのシンボル文字列テーブルの インデックスを保持する。 シンボル文字列テーブルはシンボル名の文字表現を保持する。 この値が 0 でない場合、シンボル名を得るための文字テーブルインデックスを表す。 それ以外の場合、シンボルテーブルは名前を持たない。
  • st_value
    • このメンバは関連づけられたシンボルの値を表す。
  • st_size
    • 多くのシンボルにはそれに関連づけられたサイズがある。 シンボルがサイズを持たない場合、またはサイズが不明な場合、 このメンバは 0 である。
  • st_info
    • このメンバはシンボルのタイプとバインディング (binding) 属性を指定する:
    • STT_NOTYPE
      • シンボルのタイプが定義されていない。
    • STT_OBJECT
      • シンボルはデータオブジェクトに関連づけられている。
    • STT_FUNC
      • シンボルは関数またはその他の実行コードに関連づけられている。
    • STT_SECTION
      • シンボルはセクションに関連づけられている。 このタイプのシンボルテーブルエントリーは、 主として再配置のために存在し、通常は STB_LOCAL バインディングを持つ。
    • STT_FILE
      • 慣例として、シンボルの名前は オブジェクトファイルに関連づけられたソースファイルの名前を指定する。 ファイルシンボルは STB_LOCAL バインディングを持ち、そのセクションインデックスは SHN_ABS である。 ファイルシンボルは、ファイルに他の STB_LOCAL シンボルがある場合は、それよりも先に来る。
    • STT_LOPROC
      • この値以上で STT_HIPROC 以下の範囲はプロセッサ固有の意味に予約されている。
    • STT_HIPROC
      • この値以下で STT_LOPROC 以上の範囲はプロセッサ固有の意味に予約されている。
    • STB_LOCAL
      • 局所的シンボルはその定義を含むオブジェクトファイルの外からは見えない。 同じ名前の局所的シンボルは、お互いに影響を受けることなく、 複数のファイルに存在できる。
    • STB_GLOBAL
      • 大域的シンボルは結びつけられている全てのオブジェクトファイルから見える。 1 つのファイルで大域的シンボルが定義されていたら、 他のファイルでは同じシンボルへの参照は未定義でなければならない。
    • STB_WEAK
      • 弱シンボルは大域的シンボルに似ているが、その定義は優先度が低い。
    • STB_LOPROC
      • この値以上で STB_HIPROC 以下の範囲はプロセッサ固有の意味に予約されている。
    • STB_HIPROC
      • この値以下で STB_LOPROC 以上の範囲はプロセッサ固有の意味に予約されている。
      • バインディングとタイプフィールドを パックしたりアンパックしたりするマクロがある:
        • ELF32_ST_BIND(info) または ELF64_ST_BIND(info) 
          • st_info の値からバインディングを取り出す。
        • ELF32_ST_TYPE(info) または ELF64_ST_TYPE(info)
          • st_info の値からタイプを取り出す。
        • ELF32_ST_INFO(bind, type) または ELF64_ST_INFO(bind, type)
          • バインディングとタイプを st_info の値に変換する。
  • st_other
    • このメンバはシンボルの visibility (見える範囲) を規定する。
      • STV_DEFAULT
        • デフォルトのシンボル visibility ルール。
      • STV_INTERNAL
        • プロセッサ固有の隠しクラス。
      • STV_HIDDEN
        • シンボルは他のモジュールからは利用できない。
      • STV_PROTECTED
        • 横取りできず (not preemptible)、公開されない。
    • visibility 種別を抽出するためのマクロがある。
      • ELF32_ST_VISIBILITY(other) または ELF64_ST_VISIBILITY(other)
  • st_shndx
    • 各シンボルテーブルエントリーは、いくつかのセクションに関連して “定義されている”。 このメンバは関連するセクションヘッダーテーブルインデックスを保持する。

リロケーション

再配置はシンボル参照とシンボル定義を結合するプロセスである。 再配置可能ファイルはセクションの内容をどのように修正するかに関する 情報を持たなければならない。 これにより、実行可能ファイルと共有オブジェクトファイルはプロセスのプログラムイメージについての正しい情報を持つことができる。 再配置エントリーは以下のようなデータである。

加数を必要としない再配置構造体。

typedef struct {
    Elf32_Addr r_offset;
    uint32_t   r_info;
} Elf32_Rel;
 
typedef struct {
    Elf64_Addr r_offset;
    uint64_t   r_info;
} Elf64_Rel;

加数を必要とする再配置構造体。

typedef struct {
    Elf32_Addr r_offset;
    uint32_t   r_info;
    int32_t    r_addend;
} Elf32_Rela;
 
typedef struct {
    Elf64_Addr r_offset;
    uint64_t   r_info;
    int64_t    r_addend;
} Elf64_Rela;
  • r_offset
    • このメンバは再配置動作が適用される位置を与える。 再配置可能ファイルの場合、この値はセクションの先頭から 再配置で影響を受ける格納単位 (storage unit) までのバイトオフセットである。 実行可能ファイルまたは共有オブジェクトの場合、 この値は再配置で影響を受ける格納単位の仮想アドレスである。
  • r_info
    • このメンバは、再配置が行われなければならないシンボルテーブルインデックスと、 適用される再配置のタイプの両方を与える。 再配置タイプはプロセッサ毎に異なる。 テキストが再配置エントリーの再配置タイプ またはシンボルテーブルインデックスを参照している場合、 それぞれエントリーの r_info メンバに対して、それぞれ ELF[32|64]_R_TYPE と ELF[32|64]_R_SYM を適用した結果を意味する。
  • r_addend
    • このメンバは定数の加数を指定する。 この加数は再配置可能フィールドに格納される値を計算するために使われる。

.dynamic セクション

.dynamic セクションは、関連する動的リンク情報を保持している 一連の構造体を保持する。 d_tag メンバは d_un の解釈を制御する。

typedef struct {
    Elf32_Sword    d_tag;
    union {
        Elf32_Word d_val;
        Elf32_Addr d_ptr;
    } d_un;
} Elf32_Dyn;
extern Elf32_Dyn _DYNAMIC[];
 
typedef struct {
    Elf64_Sxword    d_tag;
    union {
        Elf64_Xword d_val;
        Elf64_Addr  d_ptr;
    } d_un;
} Elf64_Dyn;
extern Elf64_Dyn _DYNAMIC[];
  • d_tag
    • このメンバは以下の値を持つことができる:
    • DT_NULL
      • 動的セクションの終りのマーク
    • DT_NEEDED
      • 必要なライブラリの名前への文字列テーブルオフセット
    • DT_PLTRELSZ
      • PLT 再配置 (reloc) テーブルのサイズ (バイト単位)
    • DT_PLTGOT
      • PLT と GOT (または何れか一方) のアドレス
    • DT_HASH
      • シンボルハッシュテーブルのアドレス
    • DT_STRTAB
      • 文字列テーブルのアドレス
    • DT_SYMTAB
      • シンボルテーブルのアドレス
    • DT_RELA
      • Rela 再配置テーブルのアドレス
    • DT_RELASZ
      • Rela テーブルのサイズ (バイト単位)
    • DT_RELAENT
      • Rela テーブルエントリーのサイズ (バイト単位)
    • DT_STRSZ
      • 文字列テーブルのサイズ (バイト単位)
    • DT_SYMENT
      • シンボルテーブルエントリーのサイズ (バイト単位)
    • DT_INIT
      • 初期化関数のアドレス
    • DT_FINI
      • 終了関数のアドレス
    • DT_SONAME
      • 共有オブジェクトの名前への文字列テーブルオフセット
    • DT_RPATH
      • ライブラリ検索パスへの文字列テーブルオフセット (推奨されない)
    • DT_SYMBOLIC
      • リンカーがシンボルの実行可能ファイルより前に この共有オブジェクトを検索した場合は、警告を出す。
    • DT_REL
      • Rel 再配置テーブルのアドレス
    • DT_RELSZ
      • Rel テーブルのサイズ (バイト単位)
    • DT_RELENT
      • Rel テーブルエントリーのサイズ (バイト単位)
    • DT_PLTREL
      • PLT が参照する再配置テーブルのタイプ (Rela または Rel)
    • DT_DEBUG
      • デバッグのために使用されている。内容は定義されていない。
    • DT_TEXTREL
      • これが指定されていない場合、 書き込み不可のセグメントには再配置は適用されない。
    • DT_JMPREL
      • PLT 専用の再配置エントリーのアドレス
    • DT_BIND_NOW
      • 実行可能ファイルに制御を譲る前に、 全ての再配置を処理するように動的リンカーに指示する。
    • DT_RUNPATH
      • ライブラリ検索パスへの文字列テーブルオフセット
    • DT_LOPROC
      • プロセッサ固有の意味の開始
    • DT_HIPROC
      • プロセッサ固有の意味の終了
  • d_val
    • このメンバは様々な意味に解釈される整数値である。
  • d_ptr
    • このメンバはプログラムの仮想アドレスを表す。 これらのアドレスを解釈する際に、 実際のアドレスは元々のファイルの値と メモリーの基底アドレスから計算される。 ファイルにはこれらのアドレスを修正するための 再配置エントリーを含めてはならない。
  • _DYNAMIC
    • .dynamic セクションにある全ての動的構造体を含む配列。 これは自動的にリンカーに渡される。