ロード時の再配置と仮想メモリのサポートは、2 つの異なる概念です。最近のほとんどすべての CPU と OS は、仮想メモリをサポートしています。仮想メモリについて理解すべき唯一の本当に重要な点は、物理アドレスを忘れることです。これは現在、ハードウェアと OS の責任であり、ページング システムを作成している場合を除き、物理アドレスを忘れることができます。プログラムが使用するすべてのアドレスは仮想アドレスです。これは大きな利点であり、プログラミング モデルが大幅に簡素化されます。0x00000000
32 ビット システムでは、これは単純に、各プロセスが からまでの範囲の独自の 4 GiB メモリ空間を取得することを意味します0xffffffff
。
An.exe
はプロセスを表します。リンカはファイルから生成.exe
し.obj
ます。どちらもバイナリ ファイル.obj
ですが、すべての変数と関数のアドレスが含まれていないため、ファイルは実行可能ではありません。これらのアドレスを提供するのはリンカの仕事です。リンカは、これらの.obj
ファイルを端から端まで配置し、すべてのシンボル (関数と変数) の正確なアドレスを計算することによって決定します。したがって、.exe
作成される には、関数と変数のすべてのアドレスが「ハードコーディング」されています。ただし、 を作成する前に必要な重要な情報が 1 つあり.exe
ます。リンカーは、メモリ内のどこにロードされるかについての内部知識を持っている必要があり.exe
ます。それはアドレス0x00000000
にありますか、それともにありますか0xffff0000
、または他の場所?たとえば、Windows では、すべて.exe
の は常に の絶対開始アドレスにロードされます0x00400000
。これをベースアドレスと呼びます。リンカーは、シンボル (関数と変数) の最終アドレスを生成するときに、このアドレスからそれらを計算します。
現在、.exe
s を他のアドレスにロードする必要はほとんどありません。しかし、.dll
s についてはそうではありません。.ddl
s は s と同じ.exe
です (どちらも移植可能な実行可能 (PE) ファイル形式でフォーマットされており、たとえば、テキストがどこにあるのか、データがどこにあるのか、どちらを見つける方法など、メモリ レイアウトが記述されています)。.dll
にも優先アドレスがあります。これは単に、リンカが .xml 内のシンボルのアドレスを計算するときにこの値を使用することを意味します.dll
。.dll
がこのアドレスにロードされていれば、準備は完了です。
しかし、他のものがこのアドレスに既にロードされているため.dll
に、このアドレスに をロードできない場合 ( だったとします)、ローダーはメモリ内の他のスペースを見つけてそこに をロードします。ただし、 の関数とシンボルのグローバル アドレスは正しくありません。したがって、ローダーは再配置(「フィックスアップ」とも呼ばれます) を実行する必要があります。この再配置では、すべてのグローバル シンボルと関数のアドレスを実際のアドレスを反映するように調整します。0x10000000
.dll
.dll
.dll
この調整を行うために、ローダーは.dll
. PE ファイルには、.reloc
そのようなすべてのシンボルの内部オフセットを含むセクションがあります。
もちろん、他の詳細もあります。たとえば、コンパイラがコードを生成したときに間接呼び出しを使用して、直接呼び出しを行う代わりに、呼び出しが間接的であり、.exe
.
最後に、要点は次のとおりです。コードが予想された位置 (4 GiB アドレス空間内) にロードされない場合は、呼び出しとジャンプのアドレスと変数アクセス命令を調整するために、(何らかの) 再配置が必要です。ロード。OS.exe
が.exe
.