これはあなたが探しているものかもしれません:
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つのことを意味する関数を呼び出します。
コンピューターは、バイナリPEファイルの一部を関数SomeFunction()を含むメモリにロードする必要があります。作成したSimpleClassのインスタンスの数に関係なく、SomeFunctionは一度だけメモリに存在します。
コンピューターは関数SomeFunction()を実行する必要があります。それはいくつかのことを意味します:
- 関数を呼び出すことは、すべてのパラメーターを渡すことも意味します。多くの場合、これはスタックで行われます。SomeFunctionには1つの(!)パラメータ、thisポインタ、つまり、値「1」と「5.0」を書き込んだスタック上のメモリアドレスへのポインタがあります。
- 現在のプログラム状態、つまり、SomeFunctionが戻った場合に実行されるコードアドレスである現在の命令アドレスを保存します。関数を呼び出すとは、スタック上のリターンアドレスをプッシュし、命令ポインタ(レジスタeip)を関数SomeFunctionのアドレスに設定することを意味します。
- 関数SomeFunction内で、古いスタックは、古いベースポインター(ebp)をスタックに格納し(push ebp)、スタックポインターを新しいベースポインター(mov ebp、esp)にすることで保存されます。
- SomeFunctionの実際のバイナリコードが実行され、m_nIntegerをdoubleに変換してm_fDoubleに追加するマシン命令が呼び出されます。m_nIntegerとm_fDoubleは、スタックのebp--xバイトにあります。
- 加算の結果はレジスタに格納され、関数が戻ります。これは、スタックが破棄されることを意味します。これは、スタックポインタがベースポインタに戻されることを意味します。ベースポインタが戻され(スタックの次の値)、次に命令ポインタがリターンアドレス(スタックの次の値)に設定されます。これで元の状態に戻りましたが、一部のレジスタにはSomeFunction()の結果が潜んでいます。
このような単純な例を自分で作成し、分解を実行することをお勧めします。デバッグビルドでは、コードが理解しやすくなり、VisualStudioは逆アセンブリビューに変数名を表示します。レジスタesp、ebp、eipの機能、メモリ内のオブジェクトの割り当て場所、コードの場所などを確認してください。