web-dev-qa-db-ja.com

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

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

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

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

105
user98188

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

  1. 通常、Visual Studio(およびEclipseも)でC++のデバッグ中にアセンブリコードを確認できます。 Visual Studioでこれを行うには、問題のコードにブレークポイントを設定し、デバッガーがヒットした場合、クリックして「Go To Assembly」を見つけます(またはCtrl + Alt + Dを押します)

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

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

140
inazaruk

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

26

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


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

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

9
diapir

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

Godboltコンパイラエクスプローラは、コンパイラのasm出力を適切にフォーマットし、ディレクティブの「ノイズ」を除去するように設計されているため、引数を使用して値を返す単純な関数の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 counterをこれらの目標に使用しますが、GetModuleFileNameAの結果に対して、処理中の文字列についてより多くの仮定を行う(および大きなバッファーを使用して最大長の安全性/割り当てを無視する)Cスタイルの文字列操作マシンコードの合計がはるかに少なくなります。)

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

6
Peter Cordes

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

4
jcopenha

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

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

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

4
Steve Steiner

Red Gateの.NET Reflector は、数回以上私を助けてくれた非常に素晴らしいツールです。 MSILを簡単に表示する以外のこのユーティリティのプラス面は、多数のサードパーティDLLを分析し、MSILをC#およびVBに変換するようにReflectorに任せることができることです。

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

1
Dave L