Wie kann ich die Assembly hinter dem Code mit Visual C ++ anzeigen?


116

Ich las eine andere Frage bezüglich der Effizienz von zwei Codezeilen, und das OP sagte, dass er die Baugruppe hinter dem Code betrachtete und beide Zeilen in der Baugruppe identisch waren. Abgesehen von Exkurs, wie könnte ich den Assembler-Code anzeigen, der beim Kompilieren eines Programms erstellt wurde?

Ich verwende Visual C ++ von Microsoft, möchte aber auch wissen, ob es möglich ist, die in Visual Basic geschriebene Assembly hinter dem Code anzuzeigen.

Wie kann ich den Assembler-Code hinter einem Programm anzeigen, das in höheren Sprachen wie C ++ und Visual Basic geschrieben wurde?


Es wird eine Assembly-Liste in msvc genannt, wie andere bereits erwähnt haben. Ich habe ein einfaches Plugin Hinzufügen von Einträgen in dem Menü - Editor Kontext diese mühsame Schritte zu automatisieren: marketplace.visualstudio.com/items?itemName=Trass3r.DevUtils
Trass3r

Antworten:


149

Es gibt verschiedene Ansätze:

  1. Normalerweise können Sie beim Debuggen von C ++ in Visual Studio (und auch Eclipse) Assembler-Code sehen. Setzen Sie dazu in Visual Studio einen Haltepunkt auf den betreffenden Code. Wenn der Debugger ihn trifft, klicken Sie auf "Gehe zu Baugruppe" (oder drücken Sie STRG + ALT + D).

  2. Der zweite Ansatz besteht darin, beim Kompilieren Baugruppenlisten zu generieren. Gehen Sie dazu zu Projekteinstellungen -> C / C ++ -> Ausgabedateien -> Speicherort der ASM-Liste und geben Sie den Dateinamen ein. Wählen Sie außerdem "Baugruppenausgabe" bis "Baugruppe mit Quellcode".

  3. Kompilieren Sie das Programm und verwenden Sie einen Debugger eines Drittanbieters. Sie können hierfür OllyDbg oder WinDbg verwenden. Sie können auch IDA (Interactive Disassembler) verwenden. Aber das ist eine Hardcore-Methode.


5
Beachten Sie, dass Ansatz 2 nicht funktioniert, wenn eine statische Bibliothek mit aktivierter Programmoptimierung kompiliert wird (zumindest in VS2010). Was Sinn macht - der Compiler hat den endgültigen Code noch nicht generiert.
Dhaffey

3
Es heißt "Gehe zu Disassembly" in Visual Studio 2017
Matthias

Wie kann ich bei Ansatz 2 die Baugruppe sehen?
user1507435

Sollte eine .asm-Datei im Debug-Verzeichnis sehen, wenn Sie den Standardspeicherort verwendet haben.
user3015682

28

Zusätzlicher Hinweis: Es gibt einen großen Unterschied zwischen der Ausgabe des Debug-Assemblers und der Ausgabe von Release 1. Der erste ist gut zu lernen, wie der Compiler Assembler-Code aus C ++ erzeugt. Der zweite ist gut zu lernen, wie der Compiler verschiedene C ++ - Konstrukte optimiert. In diesem Fall sind einige C ++ - to-asm-Transformationen nicht offensichtlich.


Ich habe festgestellt, dass beim Zerlegen der ausführbaren Debug-Datei der Code während der Ausführung offenbar entpackt wird. Dies ist in der Release-Version nicht der Fall. Auch wenn beide mit PEiD geöffnet werden, zeigt nur die Debug-Version "Microsoft Visual C ++ 8.0 [Debug]".
Jyz

9
Das ist absolut wahr. Aber es beantwortet die Frage überhaupt nicht.
Imallett

25

Geben Sie den Schalter / FA für den cl-Compiler an. Abhängig vom Wert des Schalters ist entweder nur der Baugruppencode oder der übergeordnete Code und der Baugruppencode integriert. Der Dateiname erhält die Dateierweiterung .asm. Hier sind die unterstützten Werte:


  • / FA Montagecode; .asm
  • / FAc Maschinen- und Montagecode; .Kabeljau
  • / FAs Quell- und Assembler-Code; .asm
  • / FAcs Maschinen-, Quell- und Baugruppencode; .Kabeljau

10

Am einfachsten ist es, den Debugger zu starten und das Demontagefenster zu überprüfen .


8

Die frühere Version dieser Antwort (ein "Hack" für rextester.com) ist jetzt, da http://gcc.godbolt.org/ CL 19 RC für ARM, x86 und x86-64 bereitstellt (für die Windows-Aufrufkonvention ), größtenteils überflüssig im Gegensatz zu gcc, clang und icc auf dieser Site).

Der Godbolt-Compiler-Explorer wurde entwickelt, um die asm-Ausgabe des Compilers gut zu formatieren und das "Rauschen" von Direktiven zu entfernen. Ich würde daher dringend empfehlen, ihn zu verwenden, um asm nach einfachen Funktionen zu durchsuchen, die Argumente annehmen und einen Wert zurückgeben (dies ist also nicht der Fall) weg optimiert).

Für eine Weile war CL auf http://gcc.beta.godbolt.org/ verfügbar, aber nicht auf der Hauptseite, aber jetzt ist es auf beiden.


So erhalten Sie eine MSVC-ASM-Ausgabe vom Online-Compiler http://rextester.com/l/cpp_online_compiler_visual : Fügen Sie /FAsden Befehlszeilenoptionen hinzu. Lassen Sie Ihr Programm seinen eigenen Pfad finden und den Pfad zum ermitteln .asmund sichern. Oder führen Sie einen Disassembler auf dem .exe.

zB 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 ...

typeist die DOS-Version von cat. Ich wollte keinen weiteren Code einfügen, der es schwieriger macht, die Funktionen zu finden, für die ich den ASM sehen wollte. (Obwohl die Verwendung von std :: string und Boost - Laufzähler auf diese Ziele! Einige C-String - Manipulation , die mehr Annahmen über die Saite macht es der Verarbeitung (und ignoriert Maximallänge Sicherheit / Zuteilung durch einen großen Puffer) auf dem Ergebnis der GetModuleFileNameAWould viel weniger Gesamtmaschinencode sein.)

IDK warum, cout << p.string() << endlzeigt aber nur den Basisnamen (dh den Dateinamen ohne die Verzeichnisse) an, obwohl das Drucken seiner Länge zeigt, dass es nicht nur der bloße Name ist. (Chromium48 unter Ubuntu 15.10). Es gibt wahrscheinlich irgendwann in coutoder zwischen dem Standard des Programms und dem Webbrowser eine Backslash-Escape-Verarbeitung .


@MichaelPetch: oh, zeigt sich, dass ist , was ich versucht habe. .c_str()druckt etwas, das wie ein Zeiger aussieht. Wenn Sie dem Link folgen, sehen Sie Code zum Hexdump a std::string(deaktiviert mit #if 0). Es stellt sich heraus, dass die Zeichenfolge in Ordnung ist, aber coutnicht an den Webbrowser gesendet wird. Es gibt auch keine Nicht-ASCII-Zeichen, nur Backslashes.
Peter Cordes

Ich vermisse vielleicht etwas, aber als Sie es subdir--; p /= *subdir;getan haben, haben Sie p nicht nur auf den Dateinamen reduziert ? Oder vielleicht verstehe ich falsch, was Sie zu drucken versuchen.
Michael Petch

Ich glaube , ich verstehe nicht ganz das verstehen , subdir--gefolgt von , p /= *subdirwenn subdirursprünglichp.end()
Michael Petch

@ MichaelPetch: aktualisierte Kommentare. Ich musste die letzte Verzeichniskomponente des Pfads als Dateinamen verwenden. Es funktioniert, aber ich habe lange gebraucht, um zu trainieren, weil ich dachte, ich kehre GetModuleFileNameAgerade zurück a.exe. Erst als ich es hexdumpte und die Länge druckte, wusste ich, dass es funktioniert, und ich konnte das Programm den Pfad manipulieren lassen, ich konnte den Pfad einfach nicht drucken
Peter Cordes

1
Ja, scheint der \\r(nun, \rwenn der Compiler ihn ausgibt) Teil des Dateinamens zu sein, den er beim Rendern für den Webbrowser schlecht übersetzt hat. Verwenden von p.generic_string()Arbeiten, aber die umgekehrten Schrägstriche sind Schrägstriche.
Michael Petch

5

In Visual C ++ bieten die Projektoptionen unter Ausgabedateien meines Erachtens eine Option zum Ausgeben der ASM-Liste mit Quellcode. Sie sehen also den C / C ++ - Quellcode und den resultierenden ASM in derselben Datei.


5

Für MSVC können Sie den Linker verwenden.

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

foo.pdb muss verfügbar sein, um Symbole zu erhalten


1

Der .NET Reflector von Red Gate ist ein ziemlich großartiges Tool, das mir mehr als ein paar Mal geholfen hat. Das Plus an diesem Dienstprogramm ist, dass Sie viele DLLs von Drittanbietern analysieren können und der Reflector sich um die Konvertierung von MSIL in C # und VB kümmert.

Ich verspreche nicht, dass der Code so klar wie die Quelle sein wird, aber Sie sollten keine großen Probleme haben, ihm zu folgen.


2
Hinweis: Gilt nur für verwaltete Baugruppen, nicht für die Demontage wie in Assembler, asm.
Sean e

Guter Punkt, ich habe es gelesen als "Sind die beiden Codezeilen in der Assembly gleich" statt "Sind die beiden Codezeilen in der Assembly gleich"
Dave L

Es funktioniert nur mit Dotnet-Apps, nicht mit Visual C ++ - Linkern oder Compilern.
Muhammad Ali

1

Wenn Sie über das Debuggen sprechen, um den Assemblycode anzuzeigen, ist Debug-> Windows-> Disassembly (oder Alt-8) der einfachste Weg. Auf diese Weise können Sie in eine aufgerufene Funktion eintreten und in der Demontage bleiben.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.