2016-06-13 12 views
6

オブジェクトファイル内のテキストセクションに関するすべてのマシンコードはアドレスを持っていますが、0から数値になります。静的再配置c

リンカがすべてのオブジェクトファイルをリンクすると、命令に関するアドレスが変更されます。

すべての命令アドレスを変更するためにリンカがテキストセクションに関する命令を1つずつ読み込むかどうかはわかりません。リンク

08048074 <_start>: 

    8048074: bf 00 00 00 00   mov $0x0,%edi 
    8048079: 8b 04 bd a0 90 04 08 mov 0x80490a0(,%edi,4),%eax 
    8048080: 89 c3     mov %eax,%ebx 

によって

Disassembly of section .text: 

00000000 <_start>: 

    0: bf 00 00 00 00   mov $0x0,%edi 
    5: 8b 04 bd 00 00 00 00 mov 0x0(,%edi,4),%eax 
    c: 89 c3     mov %eax,%ebx 

ちょうどように0→8048074など。

+0

これはあなたが探しているものかどうかは分かりませんが、 ['man gcc'](http://linux.die.net/man/1/gcc)のfpic関連のセクションを参照してください。 – CristiFati

+8

実際の質問は何ですか? – Art

+0

リンカがそれを作成するまではマシンコードが存在しないので、私はあなたが意味することを理解していません。 "テキストセクションについての説明を1つずつ読む"はどこからですか? – Lundin

答えて

2

大丈夫ですが、これはobjdumpコマンドの出力のように思われるので、あなたはいくつかのUNIXベースのシステムを使用していると思いますが、これはELFファイルとPEファイルの両方に関係しています。

まず、cを使用するときにいくつかのモデルをオブジェクトファイルにコンパイルし、最終的にそれらを一緒にリンクするようにしましょう。例えば:

  • m1.c - >m1.o
  • m2.c - >m2.o
  • main.c + m2.o + m1.o - >main.exe

我々はいくつかの関数を定義しm1.c/m2.cと呼ばれるいくつかのCプログラムを持っています、 main.cによって呼び出され、最終的にはすべてがリンクされてmain.exe wh ichは完全に実行可能です。

ここでは、何が起こったのかを見てみましょう。まず最初に、私たちの例(main.exe)の最後の実行可能ファイルの中で非常に重要な始まりから始めたいと思います。完全に解決された仮想アドレス(これはPIE/PICと呼ばれる概念のためあなたが実行可能ファイル内でfoom1.oの中には、fooが呼び出されたときにmain.exe内で解決されたアドレス(例えば0x400100)があります。 as

これは概念的に起こりますが、実際には何が起こるのかを見てみましょう。 またはcall命令のような命令をフェッチする場合は オペランドとしていくつかのアドレスが与えられ、次にプロセッサの命令レジスタがオペランドとして与えられたアドレスに変更されるので、リンカが指示に従って命令を出し、変更して変更する必要がありますか?まあいいえ、リンカは単にそれをしない、それはそれよりずっと賢いです。

第1に、コンパイル時に、コンパイラは、実行中の命令と比較して内部モジュール(この例ではに既に属しているはずのアドレスへのjmp)へのジャンプと呼び出しを生成します。どういう意味ですか? if文がいくつかのアドレスにジャンプするようにコンパイルされ、コンパイラが相対ジャンプオペランドを使用してコマンド間にオフセットを配置するほどスマートであるため、リンクを変更する必要がない呼び出しが現在の命令に対して相対的であり、オブジェクトファイルのコマンド間のオフセットがリンクステージを介して静的なままであるため、コードがロードされるアドレスとは無関係です。物事はもう少し複雑な取得する場所

は今ここに、私たちは、リンカは今何m1.oの両方で定義されてm2.o通話機能が実行可能であり、地球上の方法は、コンパイラことがない場合は、m1.o内のアドレスを変更する回避方法を紹介してきたですどれだけ多くの他のモデルがリンクされているか全く分からないので、それらの間のオフセットを取ることができます。これはどのように解決されますか?シンボルテーブルとリロケーションテーブルが導入されました。

  • 記号表 - モデル内のすべてのシンボルを含むテーブル - 記号は、他のモデルは、名前によって、このような関数やグローバル変数として を認識する必要があるかもしれないものです。
  • リロケーションテーブル - 一部のモデル内の シンボルの「発生」をすべて含むテーブル。

これまで聞いたことがあるかもしれませんが、今私はこれらについてあなたに説明します。 これに入る前に、私はELF形式のファイルに精通していることを警告する必要がありますが、私が知る限り、概念的にPEファイルは同じように動作します。 - foo

すると、オブジェクトファイル内でm1.oをコンパイルするとき、この

する記号のようなものを言って、いくつかのテーブルが存在することになるのは、このサンプルコードで

#include <stdio.h> 
/** file: m1.c **/ 

extern void goo(); 

void foo() 
{ 
    printf("I am foo()!\n"); 
    goo(); 
} 

#include <stdio.h> 
/** file: m2.c **/ 

void goo() 
{ 
    printf("I am goo()!\n"); 
} 

を見てみましょう>ファイル内のオフセットXでgoo - >定義なし 移動:goo - >ファイル内のオフセットYで

これは、モデルが使用するすべての関数を収集し、それらが定義されているかどうかを判断するテーブルを生成することを意味します。

また、このモデル内でgooがオフセットXで呼び出されており、再配置する必要があることを明示しています(私は私のところで答えます。あなたの質問!)

実行可能ファイルにリンクする、リンカは、すべてのオブジェクトファイルのすべてのシンボルを取り、その中にいくつかのアドレスを解決し、各オブジェクトファイルの各シンボルテーブルを通過し、見て、シンボルは、その後、まだ定義されていないかを判断すること再配置テーブルを調べて、未定義のシンボルにどの呼び出しが行われたかを調べ、ファイル内のその場所に移動し、呼び出されたアドレスを解決したアドレスに書き直すだけで済みます。シンボル解決した後m1.o

call 0x000000 ;undefined goo address 

は、リンカは、おそらくあなたがラインX上のグーアドレスを再配置する必要があると言って再配置テーブルにいくつかのエントリを持っているでしょうし、我々はまた...未定義の参照リンカエラーを持つとき、それはあなたがあなたのシンボルテーブル内いくつかの未定義のシンボルを持っており、リンカはそれのためのマッチング関数の定義を解決できないことを意味し、FYI

call 0x400100 ;actual goo address 

になります私が明らかにしていない場合、これはグローバル変数と静的変数でまったく同じですが、シンボルであるとも考えられます

+0

これは完璧です、あなたはメダルに値する!ありがとう。 – Pyjong