¿Cómo ver el ensamblado detrás del código usando Visual C ++?

116

Estaba leyendo otra pregunta relacionada con la eficiencia de dos líneas de código, y el OP dijo que miró el ensamblaje detrás del código y que ambas líneas eran idénticas en ensamblaje. Aparte de la digresión, ¿cómo podría ver el código ensamblador creado cuando se compila un programa?

Estoy usando Visual C ++ de Microsoft, pero también me gustaría saber si es posible ver el ensamblaje detrás del código escrito en Visual Basic.

Entonces, ¿cómo veo el código ensamblador detrás de un programa escrito en lenguajes de nivel superior como C ++ y Visual Basic?

Bart
fuente
Se llama una lista de ensamblado en msvc como ya han mencionado otros.
Creé

Respuestas:

149

Hay varios enfoques:

  1. Normalmente puede ver el código ensamblador mientras depura C ++ en Visual Studio (y también eclipse). Para esto, en Visual Studio, ponga un punto de interrupción en el código en cuestión y cuando el depurador lo golpee, haga clic derecho y busque "Ir al ensamblaje" (o presione CTRL + ALT + D)

  2. El segundo enfoque consiste en generar listas de ensamblado durante la compilación. Para esto, vaya a la configuración del proyecto -> C / C ++ -> Archivos de salida -> Ubicación de la lista ASM y complete el nombre del archivo. También seleccione "Salida de ensamblado" a "Ensamblado con código fuente".

  3. Compile el programa y use cualquier depurador de terceros. Puede usar OllyDbg o WinDbg para esto. También puede utilizar IDA (desensamblador interactivo). Pero esta es una forma incondicional de hacerlo.

inazaruk
fuente
5
Tenga en cuenta que el enfoque n. ° 2 no funciona cuando se compila una biblioteca estática con la optimización de todo el programa habilitada (al menos en VS2010). Lo que tiene sentido: el compilador aún no ha generado el código final.
Dhaffey
3
Se llama "Ir a desmontaje" en Visual Studio 2017
Matthias
Con el enfoque n. ° 2, ¿cómo puedo ver el montaje?
user1507435
Debería ver un archivo .asm en el directorio de depuración si usó la ubicación predeterminada.
user3015682
28

Nota adicional: existe una gran diferencia entre la salida del ensamblador de depuración y la versión uno. El primero es bueno para aprender cómo el compilador produce código ensamblador a partir de C ++. El segundo es bueno para aprender cómo el compilador optimiza varias construcciones de C ++. En este caso, algunas transformaciones de C ++ a conjunto no son obvias.

Vladimir Obrizan
fuente
Noté que al desensamblar el ejecutable Debug parece descomprimir el código mientras se está ejecutando, esto no sucede en la versión de lanzamiento. Además, al abrir ambos con PEiD, solo la versión Debug muestra "Microsoft Visual C ++ 8.0 [Debug]".
jyz
9
Esto es absolutamente cierto. Pero no responde la pregunta en absoluto.
imallett
25

Especifique el modificador / FA para el compilador cl. Dependiendo del valor del interruptor, solo se integra el código de ensamblaje o el código de alto nivel y el código de ensamblaje. El nombre de archivo obtiene la extensión de archivo .asm. Estos son los valores admitidos:


  • / Código de ensamblaje FA; .asm
  • / FAc Código de máquina y ensamblaje; .bacalao
  • / FAs Código fuente y ensamblador; .asm
  • / FAcs Código de ensamblaje, fuente y máquina; .bacalao
steve
fuente
10

La forma más sencilla es activar el depurador y comprobar la ventana de desmontaje .

diapir
fuente
8

La versión anterior de esta respuesta (un "truco" para rextester.com) es mayormente redundante ahora que http://gcc.godbolt.org/ proporciona CL 19 RC para ARM, x86 y x86-64 (dirigido a la convención de llamadas de Windows , a diferencia de gcc, clang y icc en ese sitio).

El explorador de compiladores de Godbolt está diseñado para formatear muy bien la salida de asm del compilador, eliminando el "ruido" de las directivas, por lo que recomiendo encarecidamente usarlo para buscar en asm funciones simples que toman argumentos y devuelven un valor (para que no sean optimizado).

Durante un tiempo, CL estuvo disponible en http://gcc.beta.godbolt.org/ pero no en el sitio principal, pero ahora está en ambos.


Para obtener la salida MSVC asm del compilador en línea http://rextester.com/l/cpp_online_compiler_visual : Agregue /FAslas opciones de la línea de comandos. Haga que su programa encuentre su propia ruta y calcule la ruta al .asmy lo descargue. O ejecute un desensamblador en el .exe.

por ejemplo, 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 ...

typees la versión DOS de cat. No quería incluir más código que dificultaría la búsqueda de las funciones para las que quería ver el asm. (¡Aunque usa std :: string y boost run en contra de esos objetivos! Alguna manipulación de cadena de estilo C que hace más suposiciones sobre la cadena que está procesando (e ignora la seguridad / asignación de longitud máxima mediante el uso de un búfer grande) en el resultado de GetModuleFileNameAwould ser mucho menos código de máquina total).

IDK por qué, pero cout << p.string() << endlsolo muestra el nombre base (es decir, el nombre del archivo, sin los directorios), aunque imprimir su longitud muestra que no es solo el nombre simple. (Chromium48 en Ubuntu 15.10). Probablemente haya algún procesamiento de escape de barra invertida en algún momento couto entre la salida estándar del programa y el navegador web.

Peter Cordes
fuente
@MichaelPetch: oh, resulta que eso es lo que había intentado. .c_str()imprime lo que parece un puntero. Si sigue el enlace, verá el código para hexdump a std::string(desactivado con #if 0). Resulta que la cadena está bien, pero coutno llega al navegador web. Tampoco hay caracteres que no sean ascii, solo barras invertidas.
Peter Cordes
Puede que me falte algo, pero cuando lo hizo, subdir--; p /= *subdir;¿no redujo p al nombre del archivo? O tal vez no entiendo bien lo que está intentando imprimir.
Michael Petch
Supongo que no entiendo bien lo subdir--seguido de p /= *subdircuándo subdirfue originalmentep.end()
Michael Petch
@MichaelPetch: comentarios actualizados. Necesitaba obtener el último componente de directorio de la ruta para usarlo como nombre de archivo. Funciona, pero me tomó mucho tiempo hacerlo porque pensé que GetModuleFileNameAestaba regresando a.exe. No fue hasta que lo descargué e imprimí la longitud que sabía que estaba funcionando, y podía hacer que el programa manipulara la ruta, simplemente no podía imprimir la ruta
Peter Cordes
1
Sí, parece ser \\r(bueno, \rcuando el compilador lo genera) parte del nombre de archivo que se tradujo mal al renderizar para el navegador web. El uso p.generic_string()funciona, pero las barras invertidas son barras inclinadas hacia adelante.
Michael Petch
5

En Visual C ++, las opciones del proyecto en Archivos de salida creo que tienen una opción para generar la lista de ASM con el código fuente. Entonces verá el código fuente de C / C ++ y el ASM resultante, todos en el mismo archivo.

jcopenhague
fuente
5

Para MSVC puede utilizar el vinculador.

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

foo.pdb debe estar disponible para obtener símbolos

Steve Steiner
fuente
1

.NET Reflector de Red Gate es una herramienta bastante impresionante que me ha ayudado más de un par de veces. El lado positivo de esta utilidad fuera de mostrarte fácilmente MSIL es que puedes analizar muchas DLL de terceros y hacer que Reflector se encargue de convertir MSIL a C # y VB.

No prometo que el código sea tan claro como la fuente, pero no debería tener muchos problemas para seguirlo.

Dave L
fuente
2
Nota: solo se aplica a ensamblajes administrados, no al desmontaje como en ensamblador, asm.
sean e
Buen punto, lo leí como "son las dos líneas de código iguales en el ensamblado" en lugar de "son las dos líneas de código iguales en el ensamblaje"
Dave L
Solo funcionará en aplicaciones dotnet, no en el enlazador o compilador de Visual C ++.
Muhammad Ali
1

Si está hablando de depurar para ver el código ensamblador, la forma más fácil es Debug-> Windows-> Disassembly (o Alt-8). Esto le permitirá ingresar a una función llamada y permanecer en Desmontaje.

Aabbee
fuente