【Rev・バイナリ解析関係】ELFパーサをつくろう:ELFフォーマット2/4
前書き
前回の記事に引き続き、ELFフォーマットについて書いていきます。
今回はセクションヘッダについて書いていきます。
ELFフォーマット
セクションヘッダは以下のようなフォーマットになっています。
セクションヘッダは後に解説するセクションと一対一の関係を持ち、対応するセクションの名前に関する情報や属性に関する情報など、様々な情報を格納しています。
ところで、話は少しそれますが、セクションとは別に、ELFフォーマットには直接出現しませんがセグメントという概念があります。セクションは主にリンク時にリンカが取り扱う最小単位で、セグメントは実行時にローダが取り扱う最小単位です。
話を戻して、以降、セクションヘッダの各フィールドについて確認していきます。今回は主に以下のフィールドについて確認します。
- sh_name
- sh_type
- sh_flags
- sh_addr
- sh_size
- sh_link
sh_name
前回の記事で、ELFヘッダのe_strndxについて確認しました。sh_nameは、紐づけられているセクション名の情報が、.shstrtabのどこに格納されているのかを示します。より具体的には、名前文字列が格納されている.shstrtabのインデックスを格納します。
sh_type
後述するセクションには、.strtabや.shstrtabなど、文字列を格納しているセクションや、.textなどの命令を格納しているセクションもあります。これらセクションの内容に関する情報を格納するのがsh_typeフィールドです。readelfなどで確認すると、.strtabや.shstrtabは値として3(readelfではSTRTAB)がセットされていて、.textには値として1(readelfではPROGBIT)がセットされていることが確認できます。リンカは、ここの情報を確認して再配置を実施します。
sh_flags
(この表現が適切かどうかはさておき、)セクションには実行時に書き込み可能なものもあれば、.textの様に実行可能なものもあります。これらの属性を表すのがsh_flagsです。例として.textを見てみると、値として6がセットされていて、実行が可能で、かつ実行時にメモリを占有することが分かります。
sh_addr
セクションの先頭バイトが位置する仮想メモリアドレスを格納します。objdumpなどで、実際にセクションの開始アドレスを見てみると、sh_addrフィールドと同じ値になっていることが分かります。ところで、sh_addrとsh_offsetを見比べていくと、途中で両フィールドの値に差が生じてくることが観測されます。なんでなんでしょうか?(SHT_NOBITSの関係…?)
sh_size
sh_sizeはセクションのサイズ情報を格納します。上の話で出てきたSHT_NOBITS
ですが、sh_typeにこの値がセットされていると、対応するセクションはsh_sizeに0以外の値が格納されていたとしても、実際にその分の領域をファイル上に持つことはありません。
sh_link
sh_linkは、そのセクションに関連付けられているセクションヘッダのインデックスを格納します。
例えば、.dynamicセクションのセクションヘッダは、sh_linkに.dynstrセクションのセクションヘッダインデックスを格納しています。
ところで、セクションに"関連付けられている"とは、何をもって関連付けられているとなるのでしょうか...?
現在の自分の知識ではこの先の理解が及びません...。
坂井さんのリンカ・ローダテクニックでも読んでみます...
今後
次回はいよいよセクションについて書いていきます。ELFフォーマット近辺の記事を書いていて、まだまだ勉強不足だと実感させられることが多々ありましたが、ちょっとずつ強くなっていこうと思います...。