Come visualizzare l'assembly dietro il codice utilizzando Visual C ++?


117

Stavo leggendo un'altra domanda relativa all'efficienza di due righe di codice e l'OP ha detto di aver guardato l'assieme dietro il codice ed entrambe le righe erano identiche nell'assemblaggio. Digressione a parte, come posso visualizzare il codice assembly creato quando un programma viene compilato.

Sto usando Visual C ++ di Microsoft, ma vorrei anche sapere se è possibile visualizzare l'assembly dietro il codice scritto in Visual Basic.

Quindi, come faccio a visualizzare il codice assembly dietro un programma scritto in linguaggi di livello superiore come C ++ e Visual Basic?


Si chiama un elenco di assembly in msvc come altri hanno già menzionato. Ho creato un semplice plugin aggiungendo voci al menu contestuale dell'editor per automatizzare quei noiosi passaggi: marketplace.visualstudio.com/items?itemName=Trass3r.DevUtils
Trass3r

Risposte:


149

Esistono diversi approcci:

  1. Normalmente puoi vedere il codice assembly durante il debug di C ++ in Visual Studio (e anche eclipse). Per questo in Visual Studio, metti un punto di interruzione sul codice in questione e quando il debugger lo colpisce, fai clic e trova "Vai all'assembly" (o premi CTRL + ALT + D)

  2. Il secondo approccio consiste nel generare elenchi di assembly durante la compilazione. Per questo vai alle impostazioni del progetto -> C / C ++ -> File di output -> Posizione elenco ASM e inserisci il nome del file. Selezionare anche "Assembly Output" su "Assembly With Source Code".

  3. Compilare il programma e utilizzare qualsiasi debugger di terze parti. Puoi usare OllyDbg o WinDbg per questo. Inoltre è possibile utilizzare IDA (Interactive Disassembler). Ma questo è un modo hardcore per farlo.


5
Si noti che l'approccio n. 2 non funziona quando si compila una libreria statica con l'ottimizzazione dell'intero programma abilitata (almeno in VS2010). Il che ha senso: il compilatore non ha ancora generato il codice finale.
dhaffey

3
Si chiama "Goto Disassembly" in Visual Studio 2017
Matthias

Con l'approccio n. 2, come posso vedere l'assieme?
user1507435

Dovrebbe vedere un file .asm nella directory di debug se hai usato la posizione predefinita.
user3015682

28

Nota aggiuntiva: c'è una grande differenza tra l'output dell'assembler di debug e il rilascio uno. Il primo è utile per imparare come il compilatore produce codice assembler da C ++. Il secondo è utile per imparare come il compilatore ottimizza i vari costrutti C ++. In questo caso alcune trasformazioni da C ++ ad asm non sono ovvie.


Ho notato che quando si disassembla l'eseguibile di debug sembra che il codice venga decompresso mentre è in esecuzione, ciò non accade nella versione di rilascio. Inoltre, quando si aprono entrambi con PEiD solo la versione Debug mostra "Microsoft Visual C ++ 8.0 [Debug]".
jyz

9
Questo è assolutamente vero. Ma non risponde affatto alla domanda.
imallett

25

Specificare l'opzione / FA per il compilatore cl. A seconda del valore dell'interruttore vengono integrati solo il codice assembly o il codice di alto livello e il codice assembly. Il nome del file ottiene l'estensione del file .asm. Ecco i valori supportati:


  • / FA codice assemblaggio; .asm
  • / FAc Codice macchina e assemblaggio; .merluzzo
  • / FAs codice sorgente e assembly; .asm
  • / FAcs Macchina, codice sorgente e codice assembly; .merluzzo

10

Il modo più semplice è avviare il debugger e controllare la finestra di disassemblaggio .


8

La versione precedente di questa risposta (un "hack" per rextester.com) è per lo più ridondante ora che http://gcc.godbolt.org/ fornisce CL 19 RC per ARM, x86 e x86-64 (mirando alla convenzione di chiamata di Windows , a differenza di gcc, clang e icc su quel sito).

L'esploratore del compilatore Godboltèprogettato per formattare bene l'output asm del compilatore, rimuovendo il "rumore" delle direttive, quindi consiglio vivamente di usarlo per guardare asm per funzioni semplici che accettano argomenti e restituiscono un valore (quindi non saranno ottimizzato lontano).

Per un po ', CL è stato disponibile su http://gcc.beta.godbolt.org/ ma non sul sito principale, ma ora è su entrambi.


Per ottenere l'output asm di MSVC dal compilatore online http://rextester.com/l/cpp_online_compiler_visual : Aggiungi /FAsalle opzioni della riga di comando. Fai in modo che il tuo programma trovi il suo percorso, elabori il percorso per .asme scaricalo. Oppure esegui un disassemblatore sul file .exe.

ad es. 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è la versione DOS di cat. Non volevo includere più codice che avrebbe reso più difficile trovare le funzioni per le quali volevo vedere asm. (Sebbene l'utilizzo di std :: string e boost sia contrario a questi obiettivi! Alcune manipolazioni di stringhe in stile C che fanno più ipotesi sulla stringa che sta elaborando (e ignora la sicurezza / allocazione della lunghezza massima utilizzando un grande buffer) sul risultato di GetModuleFileNameAsarebbe essere molto meno codice macchina totale.)

IDK perché, ma cout << p.string() << endlmostra solo il nome di base (cioè il nome del file, senza le directory), anche se stamparne la lunghezza mostra che non è solo il nome semplice. (Chromium48 su Ubuntu 15.10). Probabilmente c'è un po 'di elaborazione backslash-escape ad un certo punto couto tra lo stdout del programma e il browser web.


@MichaelPetch: oh, risulta che è quello che avevo provato. .c_str()stampa quello che sembra un puntatore. Se segui il collegamento, vedrai il codice per eseguire il dump esadecimale a std::string(disabilitato con #if 0). Si scopre che la stringa va bene, ma coutnon la porta al browser web. Non ci sono nemmeno caratteri non ASCII, solo barre rovesciate.
Peter Cordes,

Potrei perdere qualcosa ma quando l'hai subdir--; p /= *subdir;fatto non hai ridotto p solo al nome del file? O forse sto fraintendendo ciò che stai cercando di stampare.
Michael Petch

Immagino di non capire del tutto il subdir--seguito da p /= *subdirquando subdirera originariamentep.end()
Michael Petch

@MichaelPetch: commenti aggiornati. Avevo bisogno di ottenere l'ultimo componente della directory del percorso da utilizzare come nome di file. Funziona, ma mi ci è voluto molto tempo per allenarmi perché pensavo GetModuleFileNameAfosse appena tornato a.exe. Non è stato fino a quando non l'ho scaricato in modo esadecimale e ho stampato la lunghezza che sapevo che funzionava, e potevo fare in modo che il programma manipolasse il percorso, semplicemente non potevo stampare il percorso
Peter Cordes,

1
Sì, sembra essere la \\r(beh, \rquando il compilatore lo restituisce) parte del nome del file che è stata tradotta male durante il rendering per il browser web. Usare p.generic_string()funziona ma i backslash sono in avanti.
Michael Petch

5

In Visual C ++ le opzioni del progetto in File di output credo abbia un'opzione per l'output dell'elenco ASM con il codice sorgente. Quindi vedrai il codice sorgente C / C ++ e l'ASM risultante nello stesso file.


5

Per MSVC puoi usare il linker.

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

foo.pdb deve essere disponibile per ottenere i simboli


1

.NET Reflector di Red Gate è uno strumento davvero fantastico che mi ha aiutato più di un paio di volte. Il lato positivo di questa utility al di fuori della semplice visualizzazione di MSIL è che puoi analizzare molte DLL di terze parti e fare in modo che il Reflector si occupi della conversione di MSIL in C # e VB.

Non prometto che il codice sarà chiaro come la fonte, ma non dovresti avere molti problemi a seguirlo.


2
Nota: applicabile solo agli assiemi gestiti, non allo smontaggio come in assembler, asm.
sean e

Buon punto, l'ho letto come un "le due righe di codice sono uguali nell'assembly" invece di "le due righe di codice sono uguali nell'assembly"
Dave L

Funzionerà solo su app dotnet, non linker o compilatore Visual C ++.
Muhammad Ali

1

Se stai parlando di debug per vedere il codice assembly, il modo più semplice è Debug-> Windows-> Disassembly (o Alt-8). Questo ti permetterà di entrare in una funzione chiamata e rimanere in Disassembly.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.