私は探していましたが、ランダムなベースアドレスでロードするために、想定されるコンパイラフラグまたはFORTRAN DLLを構築できるようなものを見つけることができませんでした(Intel Visual Fortran Composer XE 2013コンパイラを使用)毎回。FORTRAN DLL を C++ コードに明示的にロードしており、正常にロード/アンロードされますが、毎回ロードされるアドレスがまったく同じ場所であることに気付きました。プログラムを複数回同時に実行すると、FORTRAN DLL が正常にロードされる場合と失敗する場合があるのはそのためではないでしょうか。インテル Fortran コンパイラー用のランダム・ベース・アドレス・コンパイラー・オプションはありますか? リリースノートを読みましたが、運もありません。
1 に答える
あなたの当面の質問に答えるには: はい、DLL をマークして、最近の Windows バージョンがわずかにランダム化されたベース アドレスにロードするようにすることができます。これは、/DYNAMICBASEオプションをリンカーに渡すことによって実現されます ( link.exe
)。Visual Studio でこの機能を有効にする方法については、リンク先のページを参照してください。ifort
makefile のコマンド ラインで を使用すると、オプション/link
を使用してリンカーにフラグを渡すことができます。
ifort.exe ... /link /DYNAMICBASE
/link
以降のすべてがリンカーに渡されるため、オプションはコマンド ラインの最後のオプションである必要があることに注意してください。また/DYNAMICBASE
、デフォルトでは ON であり、ibrary はわずかにランダムなアドレスで読み込まれることに注意してください (Windows XP を実行していますか?)
ただし、実際には必要ありません。理由の説明は次のとおりです。
コメントを明確に要約するだけです。Windows (および Windows だけでなく、*BSD、Linux、OS X などのようなほぼすべての最新の OS) の各プロセスには、独自の仮想線形アドレス空間があり、ユーザー空間内のすべてのメモリはそれらの仮想アドレスを使用して操作されます。 . 仮想メモリはページに分割され、物理メモリのフレームによってサポートされます。1 つの物理メモリ フレームは、異なるプロセスのアドレス空間からでも、多数の仮想メモリ ページにマップされる可能性があるため、プロセス間のメモリ共有が容易になります。仮想メモリ ページと物理メモリ フレーム間のマッピングは、いわゆるページ テーブルで維持されます。これらはプロセスに対してローカルであるため、マッピングはローカルです。つまり、2 つの異なるプロセスの同じ仮想メモリ アドレスは、完全に異なる物理メモリ アドレスにマップされる可能性が最も高くなります。一部のオペレーティング システム (Windows を含む) は、各プロセスの仮想アドレス空間を 2 つの部分 (下位と上位) に分割します。下部はプロセスに属し、すべてのプロセスの上部はオペレーティング システムのカーネル メモリ領域にマップされます。アプリケーション開発者は必要な権限を持っていないため、ユーザー空間からカーネルメモリにアクセスできないため、アプリケーション開発者にはほとんど関心がありません。 32 ビット システムでは 4 GiB)。他のオペレーティング システム (OS X が最も一般的なデスクトップ OS です) では、プロセス専用の仮想アドレス空間全体があり、カーネルは独自の個別の仮想メモリ空間で実行されます。
Windows (および仮想メモリ管理を実装する他のほとんどの OS) の実行可能ファイルは、通常、さまざまなセクションで構成され、セクションはセグメントにグループ化されます。実行可能ファイル形式は、その一部を仮想アドレス空間に直接マッピングすることによってメモリにロードできるように設計されています。これは、メモリ マッピングと呼ばれるプロセスです。通常、プログラム命令を含む実行可能ファイルのセクション (多くの場合、名前が付けられ.text
ているなど) は読み取り専用であるため、同じ実行可能ファイルから作成されたすべてのプロセス、または同じ DLL をロードしたすべてのプロセス間で共有できます (DLL も同じ実行可能ファイルとして構造化されていますが、異なるセクションのセットが含まれており、単独では実行できません) 物理メモリを節約するためです。さまざまなデータを含む他の多くのセクションが存在する可能性があります。.data
初期化された静的 (グローバル) 変数.bss
を含むセクション、初期化されていない静的変数を含むセクション、デバッグ情報を含むセクション、再配置セクション、インポートおよびエクスポート テーブルなど。読み取り/書き込み (データ) セクションは通常、異なるプロセス間で共有されることはありません。明確な措置が取られました。
Fortran COMMON ブロックは、.bss
初期化されていない静的データであるため、通常はセクションに存在します。COMMON ブロックがBLOCK DATA
構文を使用してデータで初期化される場合、.data
代わりにセクションに配置されます。いずれにせよ、COMMON ブロックは、DLL をロードするさまざまなプロセス間で共有できないセクションで終了します。最終的に、2 つのプロセスが依存関係の一部として暗黙的に、または明示的に を使用して DLL をロードするLoadLibrary()
と、読み取り専用セクションは 2 つのプロセス間で共有されますが、読み取り/書き込みデータ セクション (COMMON ブロックを含む) は異なります。 DLL が両方のプロセスで同じベース アドレスにロードされている場合でも、一方のプロセスでのデータへの変更は他方のプロセスでは表示されません。
Windows DLL には、「優先ベース アドレス」と呼ばれる機能があります。OS がそのような DLL をロードするときはいつでも、指定された優先ベース アドレスに配置しようとします。それができない場合 (たとえば、必要な仮想アドレス空間の一部が既に占有されている場合)、ライブラリを別のベース アドレスに再配置します。この動作の理由は、グローバル シンボルへのアクセスに絶対アドレス指定が使用され、ライブラリの再配置が必要になるたびに、ローダーによってアドレスにパッチを適用 (修正) する必要があるため、Windows では DLL の再配置にコストがかかるためです。対照的に、多くの Unix システムには動的ライブラリが PIC (位置独立コード) としてあり、それらは任意のベース仮想アドレスにロードできます。ただし、PIC コードの実行は、通常の位置依存コードよりも少し遅くなります。
古い Windows バージョンには、 のような最も基本的なライブラリがUSER32.DLL
あり、KERNEL32.DLL
常に同じベース アドレスにロードされます。それらのローダーは非常に予測可能であり、起動時と実行時に同じライブラリ セットを同じ順序でロードすると、通常、ライブラリは実行のたびに同じベース仮想アドレスにロードされます。これは、アドレス空間レイアウトのランダム化を導入した Vista 以降に変更されました。これは、リモート ネットワーク攻撃が見つけにくくするために、特別にマークされた実行可能ファイル (および DLL) をランダム化された仮想ベース アドレスにロードできるようにするオプション機能です。さまざまな OS またはユーザー API 呼び出しの正しいアドレス。