プログラムの実行時には、実行形式ファイルのイメージをメモリ上に展開する必要があります。

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

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

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

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

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





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

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


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

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

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

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

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

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

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

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

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

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



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

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

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

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