9

プログラム (C や C++ など) は、コンピューターのメモリ内でどのように構成されていますか? セグメントや変数などについては少し知っていますが、基本的に全体の構造をしっかりと理解しているわけではありません。

メモリ内の構造が異なる場合があるため、Windows の C++ コンソール アプリケーションを想定してみましょう。

私が具体的に求めているものへのいくつかのポインタ:

  • 関数の概要とその呼び方
  • 各関数にはスタック フレームがあり、そこには何が含まれており、メモリ内でどのように配置されているのでしょうか?
  • 関数の引数と戻り値
  • グローバル変数とローカル変数?
  • const静的変数?
  • スレッドローカルストレージ..

チュートリアル的なものなどへのリンクは大歓迎ですが、アセンブラなどの知識を前提としたリファレンス的なものはご遠慮ください。

4

6 に答える 6

12

これはあなたが探しているものかもしれません:

http://en.wikipedia.org/wiki/Portable_Executable

PEファイル形式は、Windowsバイナリ(.exe、.dllなど)のバイナリファイル構造です。基本的に、それらはそのようにメモリにマッピングされます。ここでは、メモリにロードされたdllのバイナリ表現を自分で確認する方法について、詳細を説明します。

http://msdn.microsoft.com/en-us/magazine/cc301805.aspx

編集:

これで、ソースコードがPEファイルのバイナリコードにどのように関連しているかを知りたいと思います。それは巨大な分野です。

まず、アセンブリコードの一般的な基本を学ぶことを含むコンピュータアーキテクチャの基本を理解する必要があります。「コンピュータアーキテクチャ入門」の大学のコースならどれでも構いません。文献には、たとえば「ジョンL.ヘネシーとデイビッドA.パターソン。コンピューターアーキテクチャ:定量的アプローチ」または「アンドリュータネンバウム、構造化コンピューター組織」が含まれます。

これを読んだ後、スタックとは何か、そしてスタックとの違いを理解する必要があります。スタックポインタとベースポインタとは何か、リターンアドレスとは何か、レジスタの数など。

これを理解したら、ピースをまとめるのは比較的簡単です。

C ++オブジェクトには、コードとデータ、つまりメンバー変数が含まれています。クラス

class SimpleClass {
     int m_nInteger;
     double m_fDouble;

     double SomeFunction() { return m_nInteger + m_fDouble; }
}

メモリ内の4+8連続バイトになります。あなたがするとき何が起こるか:

SimpleClass c1;
c1.m_nInteger = 1;
c1.m_fDouble = 5.0;
c1.SomeFunction();

最初に、オブジェクトc1がスタック上に作成されます。つまり、スタックポインタespが12バイト減少してスペースが確保されます。次に、定数「1」がメモリアドレスesp-12に書き込まれ、定数「5.0」がesp-8に書き込まれます。

次に、2つのことを意味する関数を呼び出します。

  1. コンピューターは、バイナリPEファイルの一部を関数SomeFunction()を含むメモリにロードする必要があります。作成したSimpleClassのインスタンスの数に関係なく、SomeFunctionは一度だけメモリに存在します。

  2. コンピューターは関数SomeFunction()を実行する必要があります。それはいくつかのことを意味します:

    1. 関数を呼び出すことは、すべてのパラメーターを渡すことも意味します。多くの場合、これはスタックで行われます。SomeFunctionには1つの(!)パラメータ、thisポインタ、つまり、値「1」と「5.0」を書き込んだスタック上のメモリアドレスへのポインタがあります。
    2. 現在のプログラム状態、つまり、SomeFunctionが戻った場合に実行されるコードアドレスである現在の命令アドレスを保存します。関数を呼び出すとは、スタック上のリターンアドレスをプッシュし、命令ポインタ(レジスタeip)を関数SomeFunctionのアドレスに設定することを意味します。
    3. 関数SomeFunction内で、古いスタックは、古いベースポインター(ebp)をスタックに格納し(push ebp)、スタックポインターを新しいベースポインター(mov ebp、esp)にすることで保存されます。
    4. SomeFunctionの実際のバイナリコードが実行され、m_nIntegerをdoubleに変換してm_fDoubleに追加するマシン命令が呼び出されます。m_nIntegerとm_fDoubleは、スタックのebp--xバイトにあります。
    5. 加算の結果はレジスタに格納され、関数が戻ります。これは、スタックが破棄されることを意味します。これは、スタックポインタがベースポインタに戻されることを意味します。ベースポインタが戻され(スタックの次の値)、次に命令ポインタがリターンアドレス(スタックの次の値)に設定されます。これで元の状態に戻りましたが、一部のレジスタにはSomeFunction()の結果が潜んでいます。

このような単純な例を自分で作成し、分解を実行することをお勧めします。デバッグビルドでは、コードが理解しやすくなり、VisualStudioは逆アセンブリビューに変数名を表示します。レジスタesp、ebp、eipの機能、メモリ内のオブジェクトの割り当て場所、コードの場所などを確認してください。

于 2009-11-20T10:43:13.550 に答える
4

なんて大きな質問でしょう。

まず、仮想メモリについて学びたいと思います。それがなければ、他に何も意味がありません。つまり、C /C++ポインタは物理メモリアドレスではありません。ポインタは仮想アドレスです。それらを物理メモリに透過的にマッピングする特別なCPU機能(MMU、メモリ管理ユニット)があります。オペレーティングシステムのみがMMUの構成を許可されています。

これは安全性を提供し(そのプロセスが意図的にメモリを共有している場合を除いて、そのポイントを別のプロセスの仮想アドレス空間にポイントさせることができるC / C ++ポインタ値はありません)、OSに今や当たり前のように魔法のようなことをさせます(プロセスのメモリの一部を透過的にディスクにスワップし、プロセスがそれを使用しようとしたときに透過的にロードし直すなど)。

プロセスのアドレス空間(別名仮想アドレス空間、別名アドレス可能メモリ)には、次のものが含まれます。

  • プロセスが触れることを許可されていない、Windowsカーネル用に予約されているメモリの巨大な領域。

  • 「マッピングされていない」仮想メモリの領域。つまり、そこには何もロードされておらず、それらのアドレスに物理メモリが割り当てられておらず、それらにアクセスしようとするとプロセスがクラッシュします。

  • ロードされたさまざまなモジュール(EXEファイルとDLLファイル)を分割します(これらにはそれぞれ、マシンコード、文字列定数、およびその他のデータが含まれています)。と

  • プロセスがシステムから割り当てたその他のメモリ。

現在、通常、プロセスにより、CランタイムライブラリまたはWin32ライブラリが、次の設定を含む超低レベルのメモリ管理のほとんどを実行できます。

  • ローカル変数と関数の引数および戻り値が格納されるスタック(スレッドごと)。と

  • mallocヒープ。プロセスが呼び出すか実行する場合にメモリが割り当てられますnew X

スタックの構造について詳しくは、呼び出し規約をご覧ください。ヒープの構造について詳しくは、mallocの実装をご覧ください。一般に、スタックは実際にはスタックであり、後入れ先出しのデータ構造であり、引数、ローカル変数、および時折の一時的な結果を含みますが、それ以上のものはありません。プログラムがスタックの終わりを超えて直接書き込むのは簡単なので(このサイトに名前が付けられる一般的なC / C ++のバグ)、システムライブラリは通常、スタックに隣接してマップされていないページがあることを確認します。これにより、このようなバグが発生したときにプロセスが即座にクラッシュするため、デバッグがはるかに簡単になります(プロセスは、それ以上のダメージを与える前に強制終了されます)。

ヒープは、データ構造の意味では実際にはヒープではありません。これは、CRTまたはWin32ライブラリによって維持されるデータ構造であり、オペレーティングシステムからメモリのページを取得し、プロセスが友人を介して小さなメモリを要求するたびにそれらを分割しますmalloc。(OSはこれを細かく管理しないことに注意してください。プロセスは、CRTの方法が気に入らない場合は、必要に応じてアドレス空間を大部分管理できます。)

VirtualAllocプロセスは、またはのようなAPIを使用して、オペレーティングシステムから直接ページを要求することもできますMapViewOfFile

もっとありますが、やめたほうがいいです!

于 2009-11-20T11:49:17.657 に答える
1

別の良いイラスト http://www.cs.uleth.ca/~holzmann/C/system/memorylayout.pdf

于 2009-11-21T05:34:58.480 に答える
1

スタック フレーム構造を理解するには、 http://en.wikipedia.org/wiki/Call_stackを参照してください。

呼び出しスタックの構造、 locals 、 globals 、戻りアドレスが呼び出しスタックに格納される方法に関する情報を提供します

于 2009-11-20T12:04:58.733 に答える
0

最も正確な情報ではないかもしれませんが、MS Press は、本Inside Microsoft® Windows® 2000, Third Editionのいくつかのサンプル章を提供しています。これには、プロセスとその作成に関する情報と、いくつかの重要なデータ構造の画像が含まれています。

また、上記の情報の一部を素敵な表にまとめたこの PDFも偶然見つけました。

ただし、提供される情報はすべて OS の観点からのものであり、アプリケーションの側面についてはあまり詳しくありません。

于 2009-11-20T11:09:25.043 に答える
0

実際には、アセンブラーの知識が少しでもあれば、この問題を解決することはできません。OpenRCE.org などのリバース (チュートリアル) サイトをお勧めします。

于 2009-11-20T11:37:33.183 に答える