2009-06-19 13 views
80

Estaba leyendo otra pregunta sobre 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 el ensamblaje. Dejando a un lado la digresión, ¿cómo podría ver el código ensamblador creado cuando se compila un programa?¿Cómo ver el ensamblaje detrás del código usando Visual C++?

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 de ensamblaje detrás de un programa escrito en lenguajes de nivel superior como C++ y Visual Basic?

Respuesta

114

Existen varios enfoques:

  1. normalmente se puede ver el código de montaje durante la depuración de C++ en Visual Studio (y Eclipse también). Para esto en Visual Studio ponga un punto de interrupción en el código en cuestión y cuando el depurador lo haga, haga clic y encuentre "Ir al ensamblaje" (o presione CTRL + ALT + D)

  2. Segundo enfoque es generar listados de ensamblaje 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. Seleccione también "Salida de conjunto" a "Ensamblaje con código fuente".

  3. Compila el programa y utiliza cualquier depurador de terceros. Puede usar OllyDbg o WinDbg para esto. También puede usar IDA (desensamblador interactivo). Pero esta es una manera hardcore de hacerlo.

+5

Tenga en cuenta que el enfoque # 2 no funciona al compilar una biblioteca estática con la optimización de todo el programa habilitada (en VS2010 al menos). Lo cual tiene sentido: el compilador aún no ha generado el código final. – dhaffey

+2

Se llama "Ir a desarmado" en Visual Studio 2017 – Matthias

4

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

9

La manera más fácil es desencadenar el depurador y comprobar ventana de desensamblaje.

1

Red Gate's .NET Reflector es una herramienta bastante impresionante que me ha ayudado más de una vez. El lado positivo de esta utilidad además de mostrarle fácilmente MSIL es que puede analizar una gran cantidad de archivos DLL de terceros y hacer que el reflector se encargue de convertir MSIL a C# y VB.

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

+2

Nota: solo se aplica a los ensamblados administrados para no desmontarlos como en el ensamblador, asm. –

+0

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 ensamblado" –

17

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


  • /FA Asamblea; .asm
  • /FAc Código máquina y ensamblado; .cod
  • /FAs Código fuente y de ensamblaje; .asm
  • /FAcs Código de máquina, fuente y ensamblaje; .cod
24

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 el código ensamblador 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 asm no son obvias.

+0

Me di cuenta de que al desmontar el ejecutable Debug parece descomprimir el código mientras se está ejecutando, esto no ocurre en la versión de lanzamiento. Además, al abrir ambos con PEiD, solo la versión de depuración muestra "Microsoft Visual C++ 8.0 [Depurar]". – jyz

+5

Esto es absolutamente cierto. Pero no responde la pregunta en absoluto. – imallett

2

Para MSVC puede usar el vinculador.

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

foo.pdb tiene que estar disponible para obtener símbolos

6

La versión anterior de esta respuesta (un "truco "para rextester.com) es en su mayoría redundante ahora que http://gcc.godbolt.org/ proporciona CL 19 RC para ARM, x86 y x86-64 (se dirige a la convención de llamadas de Windows, a diferencia de gcc, clang e icc en ese sitio). El explorador de compilador Godbolt está diseñado para formatear muy bien la salida de compilador asm, eliminando el "ruido" de las directivas, así que recomiendo usarlo para ver asm para funciones simples que toman argumentos y devuelven un valor (por lo que no será optimizado de distancia).

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


Para obtener una salida asm MSVC del compilador de línea http://rextester.com/l/cpp_online_compiler_visual: Añadir /FAs a las opciones de línea de comandos. Haga que su programa encuentre su propio camino y encuentre la ruta al .asm y vacíelo. O ejecuta un desensamblador en el .exe.

p. Ej. 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 es la versión DOS de cat. No quería incluir más código que dificultaría encontrar las funciones para las que quería ver el asm. (Aunque usa std :: string e impulsa contrarrestar esos objetivos! Algún tipo de manipulación de cadena 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 gran búfer) en el resultado de GetModuleFileNameA sería mucho menos código de máquina total.)

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

+0

@MichaelPetch: oh, resulta que * es * lo que había intentado. '.c_str()' imprime lo que parece un puntero. Si sigues el enlace, verás el código para hexdump a 'std :: string' (deshabilitado con' #if 0'). Resulta que la cadena está bien, pero 'cout' no está llegando al navegador web. Tampoco hay ningún personaje que no sea ascii, solo barras invertidas. –

+0

Me podría estar perdiendo algo, pero cuando lo hizo 'subdir--; p/= * subdir; '¿no redujo _p_ solo al nombre del archivo?O tal vez estoy malinterpretando lo que estás tratando de imprimir. –

+0

Supongo que no entiendo muy bien el 'subdir -' seguido de 'p/= * subdir' cuando' subdir' era originalmente 'p.end()' –

Cuestiones relacionadas