Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .vectors PROGBITS 00000000 000094 000100 00 WA 0 0 4
[ 2] .text PROGBITS 00000100 000194 000658 00 AX 0 0 2
[ 3] .rodata PROGBITS 00000758 0007ec 000098 01 AMS 0 0 1
[ 4] .data PROGBITS 00fffc20 000884 000014 00 WA 0 0 4
[ 5] .bss NOBITS 00fffc34 000898 00001a 00 WA 0 0 4
[ 6] .shstrtab STRTAB 00000000 000898 00003d 00 0 0 1
[ 7] .symtab SYMTAB 00000000 000a40 0006f0 10 8 4d 4
[ 8] .strtab STRTAB 00000000 001130 0002a1 00 0 0 1
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings)
I (info), L (link order), G (group), x (unknown)
O (extra OS processing required) o (OS specific), p (processor specific)

項目内容は以下になります。
|表記|サイズ(byte)|意味|
------------------------------------
|Name|4|セクション名|
|Type|4|セクションの種別|
|Flg |4|各種フラグ|
|Addr|4|セクションのアドレス(VA)|
|Off |4|セクションのファイル中の位置|
|Size|4|セクションのサイズ|
|Lk |4|関連するセクションの番号|
|Inf |4|セクション依存の情報|
|Al |4|セクションのアラインメント|
|ES |4|セクション内のエントリのサイズ|


「2」「4」という数値は複数あるセクションのインデックスになります。
こえをセクション番号と呼ぶことにします。

Nameはセクション名で4byteのサイズの値として情報が格納されているが、可変長の文字列なのでヘッダ上に置くことができないということで、.shstrtabというセクションにセクション名が置かれているということです。

ELFヘッダには「Section header string table index」というパラメータがありますが、これが.shstrtabセクションのセクション番号になります。ちゃんと6が格納されていました。

Addrは、そのセクションが配置されるアドレスになります。つまり関数や変数はこのアドレス体系でリンクされていることになっていて、そのセクションが動作するアドレスのことです。

「セクションの位置」「セクションのサイズ」は、ELFファイル内でどの部分がそのセクションとなるのかを表しています。

「予約領域」は可変なのでありません。
ELF Header:
Magic: 7f 45 4c 46 01 02 01 00 00 00 00 00 00 00 00 00
Class: ELF32
Data: 2's complement, big endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: EXEC (Executable file)
Machine: Hitachi H8/300
Version: 0x1
Entry point address: 0x100
Start of program headers: 52 (bytes into file)
Start of section headers: 2264 (bytes into file)
Flags: 0x810000
Size of this header: 52 (bytes)
Size of program headers: 32 (bytes)
Number of program headers: 3
Size of section headers: 40 (bytes)
Number of section headers: 9
Section header string table index: 6

readelfしたELFヘッダの出力を確認。

①Magic
先頭16バイトの識別情報の内容です。
|bit |表記 |内容
-------------------------------------------------------
|0-3 |- |0x7f 'E' 'L' 'F'(マジック・ナンバ)
|4 |Class |32ビット/64ビットの区別
|5 | Data |エンディアン
|6 |Version |ELF形式のバージョン
|7 |OS/ABI |OSの種別
|8 |ABI Version |OSのバージョン
|9-15 |- |予約(未使用)

文脈から推測するに対応した情報が以下かと思われる。
Magic: 7f 45 4c 46 01 02 01 00 00 00 00 00 00 00 00 00
Class: ELF32
Data: 2's complement, big endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0

ELF形式は汎用性の高いフォーマットになっており、32ビット/64ビットの両方と、さらにリトル・エンディアン/ビッグ・エンディアンの両方に対応している。

9-15はリザーブ領域です。今後情報を追加したい場合にELFヘッダのサイズが変化してしまったりなど、互換性の点で非常に都合の悪いことになるのでそれの対策のために設けてある。

これらの情報を識別した後でないとデータを正しく読みこめないとのこと。
要はそれらの情報が変わるとフォーマットも変わってくるということなのだろう。


|表記 |サイズ(byte) |内容
-------------------------------------------------------
|Type|2|オブジェクトファイル(REL:リロケータブルファイルの意)や実行形式ファイル(EXEC)などの種別
|Machine|2|CPUのアーキテクチャ(H8/i386)
|Version|4|ELF形式のバージョン
|Entry point address|4|実行開始アドレス(エントリ・ポイント)
|Start of program headers|4|プログラム・ヘッダ・テーブルの位置
|Start of section headers|4|セクション・ヘッダ・テーブルの位置
|Flags|4|フラグ(何のだろう?とりあえず置いておく)
|Size of this header|2|ELFヘッダのサイズ(たしかに52byteだ)
|Size of program headers|2|プログラム・ヘッダのサイズ
|Number of program headers|2|プログラム・ヘッダの個数
|Size of section headers|2|セクション・ヘッダのサイズ
|Number of section headers|2|セクション・ヘッダの個数
|Section header string table index|2|セクション名を格納するセクションの番号

文脈から推測するに対応した情報が以下かと思われます。
Type: EXEC (Executable file)
Machine: Hitachi H8/300
Version: 0x1
Entry point address: 0x100
Start of program headers: 52 (bytes into file)
Start of section headers: 2264 (bytes into file)
Flags: 0x810000
Size of this header: 52 (bytes)
Size of program headers: 32 (bytes)
Number of program headers: 3
Size of section headers: 40 (bytes)
Number of section headers: 9
Section header string table index: 6


64ビットのELF形式ではサイズが変化するとのこと。
ここで重要なのは、セクション・ヘッダに関する情報と、プログラム・ヘッダに関する情報です。これらの情報を見ることで、セクション・ヘッダ・テーブルの位置を知ることができ、さらにセクション・ヘッダ・テーブルを見ることで、セクション構成を知ることができるということだ。
プログラムの実行時には、実行形式ファイルのイメージをメモリ上に展開する必要があります。

この展開作業を行うプログラムをローダと呼びます。

ELF形式を解析してロードするプログラムならば「ELFローダ」ということになります。

そしてロードの際のメモリ展開の単位が、セグメントです。

ローダはプログラム実行時には、実行形式ファイルのセグメント情報を見て、そこに書かれているとおりに実行形式ファイル中の領域を実メモリ上にセグメント単位で展開します。

つまりセクションはリンカのためにあり、セグメントはローダにためにあるということになります。





以前にreadelfコマンドでELF形式を確認しましたが、その内部構造を絵で表すと以下のようなイメージになります。

$OS自作してみる。-ELF内部


①ELFヘッダ…たくさんの情報が存在するので後述。とりあえずここではプログラムヘッダテーブルとセクションヘッダテーブルの位置情報があることだけ記憶にとどめておく。
②プログラムヘッダテーブル…セグメントの情報が配列状に連なった構造になっている。
③セクションヘッダテーブル…セクションの各情報が配列状に連なった構造になっている。

セクション・ヘッダが持つ情報でまず重要なものは、セクションの開始位置とサイズです。これらはELFファイルの内部で、どの位置からどの位置までがそのセクションとして扱われるのかを示します。

これらのパラメータはセクションごとに独立しているため、たとえば2つのセクションがまたがっているような領域を作成したり、どのセクションにも含まれないような領域を作成したりすることもできます。

つまりセクションはELF形式内部で連続している必要も無いし、重複されても構わないというころです。

これはプログラム・ヘッダも同様です。

またセクション・ヘッダとプログラム・ヘッダは独立しているため、あるセクションが2つのセグメントにまたがっているのも可能です。

#そうなると、同じ内容がメモリ上に2つ存在するということか?!
#使用ケースはどんなときなんだろう。

また、あるセクションはどのセグメントにも含まれなかったりという構成も可能です。

#メモリ上にロードしない実行形式ファイルの情報っていったい何があるんだ?!

ただ、セグメントの役割はローダに対してメモリ上への展開方法を指示することなので、多くの場合は複数のセクションをまとめた形でひとつのセグメントが構成されるという状態になっています。



セクションはリンカが、セグメントはローダが参照するものです。

このためリンク前のオブジェクト・ファイルは、セクションを持っていますがセグメントは持っていません。つまりプログラム・ヘッダは持っていません。逆に実行形式ファイルからは、セクションを削ってしまっても問題はありません。

プログラム・ヘッダ・テーブルとセクション・ヘッダ・テーブルのファイルの中でテーブルの格納位置が最初と最後にわかれています。

これを解釈するには、ロード時になにを参照するかの順番の要素がポイントになります。