2

x86バイナリインタープリターを書いています。

現在、実行可能ファイルと共有オブジェクトのロードを扱っています。しかし、私はいくつかの疑問に悩まされています:

1)ダイナミックリンカー/ローダーは、メインの実行可能ファイルと共有ライブラリの.iniセクションを連結して、プロセスイメージ用の.iniセクションを1つだけ生成しますか?そして、.finiセクションについては?

2)多くのシンボルと文字列テーブルを連結しますか?

3)転居に迷いました。それらは、バイナリがロードされた瞬間に行われるべきですか、それともプロシージャが呼び出されたときに行われるべきですか?ダイナミックリンカー/ローダーがどのように再配置を管理するのか理解できなかったと思います。

4).hashセクションと.gnu.hashセクションが存在するのはなぜですか?なぜ「ハッシュ」記号が必要なのですか?

リンク、コメント、そして明らかに答えは大歓迎です。

4

1 に答える 1

5

ローダーに関する限り、セクションは重要ではありません。セクションは無視されます。ローダーはセグメントのみを調べ、実行可能ファイルのロード可能な各セグメントは指定されたアドレスにロードされます。次に、ローダーは動的リンカー(実行可能ファイルで必要な場合)をトリガーして、共有オブジェクトを処理します。通常、シンボルテーブルと文字列テーブルはロード可能なセグメントにないため、ローダーはそれらを無視します。

だから順番にあなたの質問に答えます:

1)ローダーは.initセクションと.finiセクションを無視します。これらは通常、ロード可能なセグメントの一部であり、実行可能ファイルの初期コードは.initセクションのコードを実行します。ダイナミックリンカは共有オブジェクトのセグメントをロードし、各エントリポイントを呼び出します。各エントリポイントは、ロードされたセグメントにある.initコードを同様に呼び出します。

2)文字列/シンボルテーブルは、ロードではなく、リンクにのみ意味があります。したがって、ダイナミックリンカはそれらを調べて再配置を解決し、ジャンプテーブルを作成します

3)再配置は​​主に(静的)リンクに使用されます。実行可能ファイルには再配置が含まれていてはならず、共有オブジェクトではまれである必要があります(通常、位置に依存しないように構築されているため、再配置は必要ありません)。一部のダイナミックリンカは再配置をまったく処理できないため(通常のLinuxダイナミックリンカについてはよくわかりません)、再配置されたままの共有オブジェクトをロードできません。

4).hashセクションは、シンボルのルックアップを高速化するための単なる最適化です。特定のシンボルのシンボルテーブルを線形検索するのではなく、.hashセクションから直接そのシンボルに移動します。必要に応じて、それらを無視してシンボルルックアップをゆっくり行うことができます。

編集

ELFローダーの機能についての短いやや漠然とした説明:

  1. ELFファイルのプログラムヘッダーを読み取ります

  2. ファイルのすべてのLOADセグメントをメモリにロードします。

  3. プログラムヘッダーにINTERPエントリがある場合は、そのバイナリを再帰的にロードします

  4. プログラムのエントリポイントを呼び出します。

それはほとんどそれです(スタックの設定については余分な問題がありますが、ローダーが実行される前のプロセス設定の一部ではなく、明らかにローダーの一部ではありません)。

静的にリンクされた実行可能ファイルの場合、INTERPエントリがないので、ほとんどそれです。動的にリンクされた実行可能ファイルの場合、INTERPセクションは「/lib/ld-linux.so.2」(文字列)のようなものになるため、ローダーへの再帰呼び出しはそのバイナリファイルを読み取り、すべてのLOADセクションをロードします。 INTERPセクションがないため(したがって、それ以上の再帰呼び出しはありません)、エントリポイントを呼び出してから、戻ります(この時点で、ベース実行可能ファイルのローダーはベース実行可能ファイルのエントリポイントを呼び出します)。

これで、ダイナミックリンカーはロードされた2番目の実行可能ファイル(/lib/ld-linux.so.2)になります。元のバイナリの.dynamicセクションに移動して読み取ります。これにより、ロードする共有オブジェクトのリストと、それらの共有オブジェクト内の特定のシンボルのアドレスを入力するテーブル(.pltセクション-プログラムロードテーブル)が通知されます。したがって、それらの共有オブジェクトをロードし、それらのシンボルを検索して、それらのアドレスをそのテーブルに貼り付けます。各共有オブジェクトには、動的リンカーによって再帰的に処理される独自の.dynamicセクションがあります。シンボルルックアップは、これまでにロードされたすべてのオブジェクトのすべてのシンボルを調べるため、メインプログラムのシンボルは、他の共有オブジェクトのシンボルを「オーバーライド」し、共有オブジェクトの.pltにアドレスを固定する場合があります。各共有オブジェクトとそのすべての依存関係がロードされた後、共有オブジェクトのエントリポイントが呼び出されます。2つの共有オブジェクトが相互に依存している場合(これは合法です)、両方がロードされ、.pltsが解決されてから、両方のエントリポイントが呼び出されますが、特に定義された順序ではありません。

上記のすべてにおいて、再配置は決してそれには入らないことに注意してください。再配置が発生する可能性があるのは、共有オブジェクトで指定された(仮想)アドレスに共有オブジェクトをロードできない場合です(他の何かがそのアドレスにすでにロードされているため)。その場合、共有オブジェクトを再配置して別のアドレスにロードする必要があります。これには、再配置されたアドレスを処理するためにパッチを適用する必要があるものについて、オブジェクト内のすべての再配置エントリを調べることが含まれます。

最後に、シンボル参照には、参照を含むオブジェクトのシンボルテーブルにオフセットがあるだけです。リンカは、ロードされた他のすべてのオブジェクトのシンボルテーブルでシンボル名(文字列)を検索して、何を把握する必要があります。を指します。すべてのオブジェクトには独自のシンボルテーブルがあり、それらのテーブルは論理的に結合される以外は結合されません。シンボルルックアップは、これまでにロードされたすべてのオブジェクトを調べ、各シンボルテーブルでそのシンボルを順番にルックアップし、シンボルを定義するエントリを探します。

于 2012-08-27T02:29:11.617 に答える