2

次の基本的な質問があります:

  • デバッグに逆アセンブルを含める必要がある場合

  • 分解の解釈方法、たとえば以下では、各セグメントは何を表していますか

00637CE3 8B 55 08             mov         edx,dword ptr [arItem]
00637CE6 52                   push        edx
00637CE7 6A 00                push        0
00637CE9 8B 45 EC             mov         eax,dword ptr [result]
00637CEC 50                   push        eax
00637CED E8 3E E3 FF FF       call        getRequiredFields (00636030)
00637CF2 83 C4 0C             add 

言語:C ++

プラットフォーム:Windows

4

4 に答える 4

4

コンパイラーによって発行されたコードがどれほど効率的であるかを見積もることは非常に役立ちます。

たとえば、std::vector::operator[]分解せずにinループを使用する場合、への各呼び出しに実際には2回のメモリアクセスが必要であると推測するのは非常に困難ですがoperator[]、同じためにイテレータを使用すると1回のメモリアクセスが必要になります。

あなたの例では:

mov         edx,dword ptr [arItem] // value stored at address "arItem" is loaded onto the register
push        edx // that register is pushes into stack
push        0 // zero is pushed into stack
mov         eax,dword ptr [result] // value stored at "result" address us loaded onto the register
push        eax // that register is pushed into stack
call        getRequiredFields (00636030) // getRequiredFields function is called

これは、関数を呼び出すための一般的なシーケンスです。パラメーターがスタックにプッシュされてから、制御がその関数コード(call命令)に転送されます。

また、分解を使用することは、「コンパイル後にどのように機能するか」についての議論に参加するときに非常に役立ちます-この質問に対する彼の答えのcafポイントのように。

于 2009-10-14T10:59:13.020 に答える
3

1-最後の手段として、(I)デバッグに逆アセンブルを含める必要があります。一般に、最適化コンパイラは、人間の目に理解するのが簡単ではないコードを生成します。命令の並べ替え、デッドコードの削除、特定のコードのインライン化など。したがって、逆アセンブルされたコードを理解する必要はなく、必要な場合は簡単ではありません。たとえば、逆アセンブルを調べて、定数がオペコードの一部であるか、const変数に格納されているかを確認することがあります。

2-そのコードはgetRequiredFields(result、0、arItem)のような関数を呼び出します。必要なプロセッサのアセンブリ言語を学ぶ必要があります。x86の場合は、www.intel.comにアクセスして、IA32のマニュアルを入手してください。

于 2009-10-14T11:01:29.780 に答える
2

分解を行う必要がある場合:プログラムの実行時にCPUが何を実行しているかを正確に知りたい場合、またはプログラムが記述された高水準言語(この場合はC ++)のソースコードがない場合。

アセンブリコードの解釈方法:アセンブリ言語を学びます。Intel x86 CPU命令の完全なリファレンスは、Intelのプロセッサマニュアルにあります。

投稿したコードは、関数呼び出しの引数を準備し(スタックにいくつかの値を取得してプッシュし、レジスターに値を入れることによってeax)、関数を呼び出しますgetRequiredFields

于 2009-10-14T11:00:11.940 に答える
1

私は1982年にCP/M-80以降のDigitalResearchOSでのPL/Mプログラムのアセンブリデバッグから始めました。これは、Microsoftがソースとアセンブリを同時に表示するコマンドラインデバッガであるsymdebを導入するまで、MS-DOSの初期の頃と同じでした。Symdebは飛躍的な進歩でしたが、以前のデバッガーでは、どのアセンブリコードがどのソースコード行に属しているかを認識することを強制されていたため、それほど大きくはありませんでした。CodeViewの前は、PhoenixTechnologiesのpfix86が最適なデバッガーでした。NuMegas SoftIceは、(純粋なハードウェアICEを除いて)これまでに出会った中で最高のデバッガーであり、アプリケーションをデバッグするだけでなく、Windowsの内部動作も簡単にガイドしてくれました。しかし、私は逸脱します。

1990年の終わりに、私が取り組んでいたプロジェクトのコンサルタントが私に近づき、彼が何日も取り組んできたこの(非常に初期の)C ++バグがあると言いましたが、問題が何であるか理解できませんでした。彼は私のために(ウィンドウ化された非グラフィックDOSデバッガーで)ソースコードをシングルステップで実行しましたが、私はすべて焦りました。最後に、私は彼に割り込んでデバッガオプションを調べ、レジスタとすべてを備えたソース/アセンブリの混合モードが十分にあることを確認しました。これにより、アプリケーションがNULLを含む内部ポインター(ローカル変数用)を解放しようとしていることが簡単にわかりました。この問題では、ソースコードモードはまったく役に立ちませんでした。今日のC++コンパイラには、おそらくこのようなバグは含まれていませんが、他のバグはあります。

アセンブリレベルのデバッグを知っていると、コンパイラが生成するコードを予測できる範囲で、ソース-コンパイラ-アセンブリの関係を理解できます。ここスタックオーバーフローの多くの人は「profile-profile-profile」と言いますが、これはさらに一歩進んで、どのソースコード構造(私はCで書いています)をいつ、どれを避けるべきかを学びます。これは、開発者が何も疑わずに大量のコードを生成できるC++ではさらに重要だと思います。たとえば、オブジェクトのリストを処理するための標準クラスがありますが、これには欠点がないように見えます。ほんの数行のコードとこの素晴らしい機能です。-それが生成する奇妙なプロシージャコールのスコアを見るまで。私はそれらを使うのが間違っていると言っているのではありません、私は」m開発者は、それらを使用することの長所と短所を認識している必要があると言っているだけです。演算子のオーバーロードは優れた機能かもしれませんが(私のようなWYSIWYGプログラマーにとっては少し奇妙です)、実行速度の代償は何ですか?あなたが「何もない」と言うなら、私は「それを証明する」と言います。

デバッグ時に混合または純粋なアセンブリモードを使用することは決して間違いではありません。難しいバグは通常見つけやすく、開発者はより効率的なコードを書くことを学びます。インタプリタキャンプ(C#およびJava)の開発者は、コードはコンパイルされた言語と同じくらい効率的であると言うでしょうが、アセンブリを知っていれば、なぜそれらが間違っているのか、なぜ完全に間違っているのかもわかります。あなたは微笑んで「ええ、それについて教えてください!」と考えることができます。

さまざまなコンパイラを使用した後、最も驚くべきコード生成機能を備えたコンパイラに出くわします。1つのPowerPCコンパイラーは、オプティマイザーの優れたコード解釈によって、3つのネストされたループを1つのループに凝縮しました。私は...まあ、別のリーグで言ってみようと書いた人の隣に。

約10年前まで、私はかなりの純粋なアセンブリを作成しましたが、多段パイプライン、複数の実行ユニット、そしてCコンパイラと競合する複数のコアを使用して私を打ち負かしました。一方、私はコンパイラーが何をうまく処理できるか、そして何を処理する必要がないかを知っています。GarbageInはGarbageOutと同じです。これは、アセンブリ出力を生成するすべてのコンパイラに当てはまります。

于 2011-02-21T19:15:41.823 に答える