Comment afficher l'assembly derrière le code à l'aide de Visual C ++?

117

Je lisais une autre question concernant l'efficacité de deux lignes de code, et l'OP a dit qu'il regardait l'assemblage derrière le code et que les deux lignes étaient identiques dans l'assemblage. Digression à part, comment pourrais-je voir le code d'assemblage créé lors de la compilation d'un programme.

J'utilise Visual C ++ de Microsoft, mais j'aimerais également savoir s'il est possible d'afficher l'assembly derrière le code écrit en Visual Basic.

Alors, comment afficher le code d'assemblage derrière un programme écrit dans des langages de niveau supérieur tels que C ++ et Visual Basic?

Bart
la source
Cela s'appelle une liste d'assemblages dans msvc comme d'autres l'ont déjà mentionné. J'ai créé un simple plugin en ajoutant des entrées au menu contextuel de l'éditeur pour automatiser ces étapes fastidieuses: marketplace.visualstudio.com/items?itemName=Trass3r.DevUtils
Trass3r

Réponses:

149

Il existe plusieurs approches:

  1. Vous pouvez normalement voir le code d'assembly lors du débogage de C ++ dans Visual Studio (et aussi Eclipse). Pour cela dans Visual Studio, mettez un point d'arrêt sur le code en question et lorsque le débogueur le frappe, cliquez et trouvez «Aller à l'assemblage» (ou appuyez sur CTRL + ALT + D)

  2. La deuxième approche consiste à générer des listes d'assembly lors de la compilation. Pour cela, allez dans les paramètres du projet -> C / C ++ -> Fichiers de sortie -> Emplacement de la liste ASM et remplissez le nom du fichier. Sélectionnez également «Sortie d'assemblage» sur «Assemblage avec code source».

  3. Compilez le programme et utilisez n'importe quel débogueur tiers. Vous pouvez utiliser OllyDbg ou WinDbg pour cela. Vous pouvez également utiliser IDA (désassembleur interactif). Mais c'est une façon hardcore de le faire.

inazaruk
la source
5
Notez que l'approche n ° 2 ne fonctionne pas lors de la compilation d'une bibliothèque statique avec l'optimisation de l'ensemble du programme activée (au moins dans VS2010). Ce qui est logique - le compilateur n'a pas encore généré le code final.
dhaffey
3
Il s'appelle "Goto Disassembly" dans Visual Studio 2017
Matthias
Avec l'approche n ° 2, comment puis-je voir l'assemblage?
user1507435
Devrait voir un fichier .asm dans le répertoire de débogage si vous avez utilisé l'emplacement par défaut.
user3015682
28

Remarque supplémentaire: il existe une grande différence entre la sortie de l'assembleur de débogage et la version 1. Le premier est bon pour apprendre comment le compilateur produit du code assembleur à partir de C ++. Le second est bon pour apprendre comment le compilateur optimise diverses constructions C ++. Dans ce cas, certaines transformations C ++ vers asm ne sont pas évidentes.

Vladimir Obrizan
la source
J'ai remarqué que lors du désassemblage de l'exécutable Debug, il semble décompresser le code pendant son exécution, cela ne se produit pas sur la version Release. De plus, lors de l'ouverture des deux avec PEiD, seule la version de débogage affiche "Microsoft Visual C ++ 8.0 [Debug]".
jyz
9
C'est absolument vrai. Mais cela ne répond pas du tout à la question.
imallett
25

Spécifiez le commutateur / FA pour le compilateur cl. En fonction de la valeur du commutateur, seul le code d'assemblage ou le code de haut niveau et le code d'assemblage sont intégrés. Le nom de fichier obtient l'extension de fichier .asm. Voici les valeurs prises en charge:


  • / FA Code d'assemblage; .asm
  • / FAc Code machine et assemblage; .la morue
  • / FAs Source et code d'assemblage; .asm
  • / FAcs Code machine, source et assemblage; .la morue
Steve
la source
10

Le moyen le plus simple est de lancer le débogueur et de vérifier la fenêtre de désassemblage .

diapir
la source
8

La version antérieure de cette réponse (un "hack" pour rextester.com) est principalement redondante maintenant que http://gcc.godbolt.org/ fournit CL 19 RC pour ARM, x86 et x86-64 (ciblant la convention d'appel Windows , contrairement à gcc, clang et icc sur ce site).

L'explorateur de compilateur Godbolt est conçu pour formater joliment la sortie asm du compilateur, en supprimant le «bruit» des directives, je vous recommande donc vivement de l'utiliser pour rechercher des fonctions simples qui prennent des arguments et renvoient une valeur (donc ils ne seront pas optimisé loin).

Pendant un certain temps, CL était disponible sur http://gcc.beta.godbolt.org/ mais pas sur le site principal, mais maintenant c'est sur les deux.


Pour obtenir la sortie asm MSVC à partir du compilateur en ligne http://rextester.com/l/cpp_online_compiler_visual : Ajoutez /FAsaux options de ligne de commande. Demandez à votre programme de trouver son propre chemin, de trouver le chemin vers le .asmet de le vider. Ou exécutez un désassembleur sur le .exe.

par exemple 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 ...

typeest la version DOS de cat. Je ne voulais pas inclure plus de code qui rendrait plus difficile la recherche des fonctions pour lesquelles je voulais voir l'asm. (Bien que l'utilisation de std :: string et boostent les exécutions à l'encontre de ces objectifs! Une certaine manipulation de chaîne de style C qui fait plus d'hypothèses sur la chaîne qu'il traite (et ignore la sécurité / allocation de longueur maximale en utilisant un grand tampon) sur le résultat de GetModuleFileNameAserait être beaucoup moins de code machine total.)

IDK pourquoi, mais cout << p.string() << endlne montre que le nom de base (c'est-à-dire le nom de fichier, sans les répertoires), même si l'impression de sa longueur montre que ce n'est pas seulement le nom nu. (Chromium48 sur Ubuntu 15.10). Il y a probablement un traitement d'échappement par anti-slash à un moment donné cout, ou entre la sortie standard du programme et le navigateur Web.

Peter Cordes
la source
@MichaelPetch: oh, il s'avère que c'est ce que j'avais essayé. .c_str()imprime ce qui ressemble à un pointeur. Si vous suivez le lien, vous verrez le code pour hexdump a std::string(désactivé avec #if 0). Il s'avère que la chaîne est correcte, mais coutne la parvient pas au navigateur Web. Il n'y a pas non plus de caractères non ascii, juste des barres obliques inverses.
Peter Cordes
Il me manque peut-être quelque chose, mais quand vous l'avez fait, subdir--; p /= *subdir;n'avez-vous pas réduit p au nom du fichier? Ou peut-être que je ne comprends pas ce que vous essayez d'imprimer.
Michael Petch le
Je suppose que je ne comprends pas très bien le subdir--suivi de p /= *subdirquand subdirétait à l'originep.end()
Michael Petch
@MichaelPetch: commentaires mis à jour. J'avais besoin d'obtenir le dernier composant de répertoire du chemin à utiliser comme nom de fichier. Cela fonctionne, mais il m'a fallu beaucoup de temps pour m'entraîner parce que je pensais que je GetModuleFileNameArevenais a.exe. Ce n'est que lorsque je l'ai vidé et imprimé la longueur que je savais que cela fonctionnait et que je pouvais faire manipuler le chemin par le programme, je ne pouvais tout simplement pas imprimer le chemin
Peter Cordes
1
Ouais, semble être la partie \\r(enfin \rquand le compilateur le sort) du nom de fichier qu'il a mal traduit lors du rendu pour le navigateur Web. L'utilisation p.generic_string()fonctionne mais les barres obliques inverses sont des barres obliques.
Michael Petch
5

Dans Visual C ++, les options de projet sous, Fichiers de sortie, je crois, ont une option pour la sortie de la liste ASM avec le code source. Vous verrez donc le code source C / C ++ et l'ASM résultant dans le même fichier.

jcopenha
la source
5

Pour MSVC, vous pouvez utiliser l'éditeur de liens.

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

foo.pdb doit être disponible pour obtenir des symboles

Steve Steiner
la source
1

.NET Reflector de Red Gate est un outil assez génial qui m'a aidé plus de quelques fois. Le côté positif de cet utilitaire en dehors de vous montrer facilement MSIL est que vous pouvez analyser un grand nombre de DLL tierces et que Reflector se charge de convertir MSIL en C # et VB.

Je ne promets pas que le code sera aussi clair que la source, mais vous ne devriez pas avoir beaucoup de mal à le suivre.

Dave L
la source
2
Remarque: s'applique uniquement aux assemblages gérés et non au démontage comme dans l'assembleur, asm.
sean e
Bon point, je l'ai lu comme un "sont les deux lignes de code identiques dans l'assemblage" au lieu de "sont les deux lignes de code identiques dans l'assemblage"
Dave L
Il ne fonctionnera que sur les applications dotnet, pas sur l'éditeur de liens ou le compilateur Visual C ++.
Muhammad Ali
1

Si vous parlez de débogage pour voir le code d'assemblage, le moyen le plus simple est Debug-> Windows-> Disassembly (ou Alt-8). Cela vous permettra d'entrer dans une fonction appelée et de rester en désassemblage.

Aabbee
la source