2012-04-03 18 views
0

友達、私はa.cとb.cの2つのファイルを持っています。 b.cから呼び出されているa.cに関数fooを定義しました。私が理解からリンク時または実行時に参照を解決するには?

、コンパイラがBCをコンパイルしようとすると、それはOSがリンクで解決すべきシンボルテーブル内のfooのエントリを追加しますので、それは、fooの実装はBではないことがわかります時間。私はこの概念を正しく理解していました。

今、私はglibcに実装されているb.cのprintfとは別の関数printfを持っています。私が理解するところでは、printfはロード時または実行時にリンクすることができます。実行時にprintfがリンクされる場合は、システムコールを使用して実行時に解決されるprintfへの呼び出しごとにスタブが必要です。

私の質問は「コンパイラが関数fooがリンカによって解決され、実行時ではないと判断する方法は?」

私はいくつかの同様の質問に気付きましたが、ここでその重要性を理解できませんでしたか?

答えて

3

私はあなたの質問が少し難しいので、私はあなたがそれを理解する方法についてはあまりよく分かりませんので、どのように動作するか説明します。

  1. シンボルが同じファイル(b.c)にある場合、コンパイラはそれを直接参照します。リンカーは何も解決するために使用されません。シンボルが同じファイルではなく、-fPICが指定ないであれば、コンパイラは単に未定義シンボルへの呼び出しを発する

  2. 。この場合、リンカは他の.oファイルまたはライブラリのシンボルを検索し、基本的に空白に貼り付けることによってリンク時に直接参照を挿入します。

    これは、通常、(ライブラリではなく)プログラムを作成する方法です。プログラムがダイナミックライブラリを使用する場合、リンク時に修正できないシンボルが存在する可能性があります。その場合、リンカーはライブラリにそれらがあることをチェックし、実行時にジョブを終了するために動的リンカーに残されます。

    唯一の動的リンカが常に実行時にプログラムにアドレスを貼り付けて、また共有ライブラリに正確にこれを行うことが可能であろうが、それはライブラリを共有することを意味するだろう行うには、共有することができませんでした:各プログラムは独自の修正を加えた独自のコピーを持たなければなりません。これが起こらない理由です。

  3. シンボルが同じファイル内になく、-fPICの場合、コンパイラはシンボル名を直接使用しません。代わりに、PLT(Procedure Linkage Table)を介して関数を呼び出し、GOT(グローバルオフセットテーブル)を介して他のシンボルのアドレスを取得します。

    GOTはリンカによって作成された特別なテーブルであり、通常はPIC以外の通常のプログラムで見つかるものに似た未定義のシンボル参照のリストです(通常はGOTの​​基盤)動的リンカーは、実行時に空白を埋め込みます。コンパイラは、常に特定のCPUレジスタにGOTのアドレスを配置して、テーブルを常に見つけることができます。

    PLTは、リンカーによって作成されたトランポリンのセットです。コンパイラはPLTにジャンプを作成し、ダイナミックリンカはPLTをセットアップして関数の実際の場所にバウンスさせます。実際には、多くの場合、PLTはライブラリがロードされるときにダイナミックリンカによって埋められません.PLTはGOT(自己修正コード)を使用して初めて呼び出されます。

    これは、ダイナミックライブラリが通常-fPICで構築されている理由です。ライブラリのテキストを変更せずに共有できるようにしながら、GOTおよびPLTをプログラムごとに変更することができます。

だから、あなたの質問に今答え:

私はあなたの話「スタブ」はPLTかもしれないと思いますか?関数が解決されるとき

コンパイラないは知っているん。それはそれがそれ自体を解決できないことを知っているだけです。実際、ダイナミックライブラリを使用すると、リンカはシンボルを完全に解決しようとしません(ただし、ライブラリ内で定義されているかどうかチェックしていると思います)。つまり、同じ名前の別の関数を提供することで、ライブラリ内の特定の関数をオーバーライドすることができます。 tsocksのようなツールは、LD_PRELOADでこれを使用してライブラリ呼び出しをインターセプトします。

関連する問題