Visual C ++を使用してコードの背後にあるアセンブリを表示する方法は?


116

2行のコードの効率に関する別の質問を読んでいて、OPは、コードの背後にあるアセンブリを調べたところ、両方の行のアセンブリが同じであると述べました。余談ですが、プログラムのコンパイル時に作成されたアセンブリコードを表示するにはどうすればよいですか。

MicrosoftのVisual C ++を使用していますが、Visual Basicで記述されたコードの背後にあるアセンブリを表示できるかどうかも知りたいです。

では、C ++やVisual Basicなどの高水準言語で記述されたプログラムの背後にあるアセンブリコードをどのように表示しますか?


他の人がすでに述べたように、これはmsvcではアセンブリリストと呼ばれます。:私はそれらの面倒な手順を自動化するために、エディタのコンテキストメニューに項目を追加するプラグインを作成したシンプルなmarketplace.visualstudio.com/items?itemName=Trass3r.DevUtils
Trass3r

回答:


149

いくつかのアプローチがあります:

  1. 通常、Visual StudioでC ++をデバッグしているときにアセンブリコードを確認できます(Eclipseも同様です)。Visual Studioでこれを行うには、問題のコードにブレークポイントを設定し、デバッガーがヒットしたときに「アセンブリに移動」をクリックして見つけます(またはCTRL + ALT + Dを押します)。

  2. 2番目のアプローチは、コンパイル中にアセンブリリストを生成することです。これを行うには、プロジェクト設定-> C / C ++->出力ファイル-> ASMリストの場所に移動し、ファイル名を入力します。また、「Assembly Output」から「Assembly With Source Code」を選択します。

  3. プログラムをコンパイルし、サードパーティのデバッガを使用します。これには、OllyDbgまたはWinDbgを使用できます。また、IDA(インタラクティブ逆アセンブラー)を使用することもできます。しかし、これはハードコアな方法です。


5
プログラム全体の最適化を有効にして(少なくともVS2010では)静的ライブラリをコンパイルする場合、アプローチ2は機能しないことに注意してください。これは理にかなっています-コンパイラはまだ最終的なコードを生成していません。
dhaffey 2013年

3
Visual Studio 2017で「Goto Disassembly」と呼ばれています
Matthias

アプローチ#2では、アセンブリをどのように確認できますか?
user1507435

デフォルトの場所を使用した場合、デバッグディレクトリに.asmファイルが表示されます。
user3015682

28

追記:デバッグアセンブラーの出力とリリース1の間には大きな違いがあります。最初の方法は、コンパイラがC ++からアセンブラコードを生成する方法を学ぶのに適しています。2番目の方法は、コンパイラーがさまざまなC ++構造を最適化する方法を学ぶのに適しています。この場合、一部のC ++からasmへの変換は明白ではありません。


Debug実行可能ファイルを逆アセンブルすると、実行中にコードが解凍されるようですが、これはリリースバージョンでは発生しません。また、両方をPEiDで開くと、デバッグバージョンに「Microsoft Visual C ++ 8.0 [Debug]」と表示されます。
jyz

9
これは絶対に本当です。しかし、それは質問にまったく答えません。
イマレット

25

clコンパイラの/ FAスイッチを指定します。スイッチの値に応じて、アセンブリコードのみ、または高レベルコードとアセンブリコードのどちらかが統合されます。ファイル名には.asmファイル拡張子が付きます。サポートされている値は次のとおりです。


  • / FAアセンブリコード; .asm
  • / FAcマシンおよびアセンブリコード。.cod
  • / FAsソースコードとアセンブリコード。.asm
  • / FAcsマシン、ソース、およびアセンブリコード。.cod

10

最も簡単な方法は、デバッガを起動して逆アセンブリウィンドウを確認することです。


8

この回答の以前のバージョン(rextester.comの「ハック」)は、http://gcc.godbolt.org/がCL 19 RCを提供するようになったため、ほとんど冗長です ARM、x86、およびx86-64(Windows呼び出し規約を対象とをため、、そのサイトのgcc、clang、iccとは異なります)。

Godboltコンパイラエクスプローラは、コンパイラのasm出力を適切にフォーマットし、ディレクティブの「ノイズ」を取り除くように設計されているため、argsを受け取って値を返す単純な関数のasmを調べるために使用することを強くお勧めします(そうしないと、最適化された)。

しばらくの間、CLはhttp://gcc.beta.godbolt.org/で利用できましたが、メインサイトではありませんでしたが、現在は両方で利用できます。


http://rextester.com/l/cpp_online_compiler_visualオンラインコンパイラからMSVC asm出力を取得/FAsするには:コマンドラインオプションに追加します。プログラムに独自のパスを見つけさせ、へのパスを.asm計算してダンプします。または、で逆アセンブラを実行し.exeます。

例:http : //rextester.com/OKI40941

#include <string>
#include <boost/filesystem.hpp>
#include <Windows.h>

using namespace std;

static string my_exe(void){
    char buf[MAX_PATH];
    DWORD tmp = GetModuleFileNameA( NULL, // self
                                  buf, MAX_PATH);
    return buf;
}

int main() {
    string dircmd = "dir ";
    boost::filesystem::path p( my_exe() );
    //boost::filesystem::path dir = p.parent_path();

    // transform c:\foo\bar\1234\a.exe 
    // into      c:\foo\bar\1234\1234.asm
    p.remove_filename();
    system ( (dircmd + p.string()).c_str() );

    auto subdir = p.end();      // pointing at one-past the end
    subdir--;                   // pointing at the last directory name
    p /= *subdir;               // append the last dir name as a filename
    p.replace_extension(".asm");
    system ( (string("type ") + p.string()).c_str() );
//    std::cout << "Hello, world!\n";
}

... code of functions you want to see the asm for goes here ...

typeはのDOSバージョンですcat。asmを確認したい関数を見つけるのが難しくなるようなコードを追加したくありませんでした。(ただし、これらの目標に対してstd :: stringおよびboost runカウンターを使用します!処理する文字列についてより多くの仮定を行う(および大きなバッファーを使用して最大長の安全性/割り当てを無視する)Cスタイルの文字列操作GetModuleFileNameAますマシンコードの合計がはるかに少なくなります。)

IDKが理由ですがcout << p.string() << endl、ベース名(つまり、ディレクトリなしのファイル名)のみが表示されますが、その長さを印刷すると、単なる名前ではないことが示されます。(Ubuntu 15.10上のChromium48)。のある時点cout、またはプログラムのstdoutとWebブラウザの間にバックスラッシュエスケープ処理が存在する可能性があります。


@MichaelPetch:ああ、それ私が試したものです。 .c_str()ポインタのように表示されます。リンクをクリックすると、aを16進ダンプするコードが表示されますstd::string(で無効化#if 0)。文字列は問題coutありませんが、Webブラウザーに取得されていません。ASCII以外の文字もありません。バックスラッシュだけです。
Peter Cordes

私は何かが足りないかもしれませんが、あなたがsubdir--; p /= *subdir;しなかったとき、pをファイル名だけに減らしませんか?あるいは、あなたが何を印刷しようとしているのか誤解しているのかもしれません。
Michael Petch、2016

私がsubdir--その後に続いp /= *subdirたのsubdirはもともといつだったかがよくわかりませんp.end()
マイケルペッチ

@MichaelPetch:コメントを更新しました。ファイル名として使用するパスの最後のディレクトリコンポーネントを取得する必要がありました。効果はありますが、GetModuleFileNameA戻るだけだと思ったので、解決に長い時間がかかりましたa.exe。それは私がそれをhexdumpedまでではなかったと私はそれが働いていた知っていた長さを印刷して、私はプログラムのパスを操作するかもしれない、私はちょうどことができなかった印刷パス
ピーター・コルド

1
ええ、Webブラウザー用にレンダリングするときに翻訳が不十分だったファイル名の一部\\r\rコンパイラーが出力した場合)のようです。p.generic_string()作品を使用していますが、バックスラッシュはスラッシュです。
Michael Petch、2016

5

Visual C ++のプロジェクトオプション、[出力ファイル]には、ASMリストをソースコードで出力するオプションがあると思います。したがって、C / C ++ソースコードと結果のASMがすべて同じファイルに表示されます。


5

MSVCの場合、リンカーを使用できます。

link.exe / dump / linenumbers / disasm /out:foo.dis foo.dll

シンボルを取得するには、foo.pdbが使用可能である必要があります


1

Red Gateの.NETリフレクターは、非常に優れたツールであり、何度も助けてくれました。MSILを簡単に表示する以外のこのユーティリティのプラス面は、多くのサードパーティDLLを分析して、ReflectorでMSILをC#およびVBに変換できるようにすることです。

コードがソースと同じくらい明確になるとは約束していませんが、コードに従うのにそれほど問題はないはずです。


2
注:アセンブラーasmのように分解しないマネージアセンブリにのみ適用されます。
ショーンe '06 / 06/20

良い点、私はそれを「2行のコードがアセンブリで同じである」ではなく、「2行のコードがアセンブリで同じである」と読んだ
Dave L

ドットネットアプリでのみ機能し、Visual C ++リンカーやコンパイラでは機能しません。
ムハンマドアリ

1

アセンブリコードを確認するためのデバッグについて話している場合、最も簡単な方法は、Debug-> Windows-> Disassembly(またはAlt-8)です。これにより、呼び出された関数にステップインして、逆アセンブリのままにすることができます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.