Ensamblar para obtener el código fuente
Primero, veamos un ensamblador Win32 "complejo".
Este programa se utiliza para mostrar un cuadro de mensaje
-
Nombre del archivo: 3.asm
.386
. Plano modelo, llamada estándar
NULL equ 0
MB_OK equ 0
ExitProcess PROTO:Dword
Cuadro de mensaje A PROTO:DWORD, :DWORD, :DWORD, :DWORD
includelib kernel32.lib
includelib user32.lib
. datos
szText db "Hola mundo!",0
szCaption db "Win32Asm ",0
. Contraseña
Inicio:
Presione MB_OK
lea eax, szCaption
Presione eax
lea eax, Shenzhen texto
Empujar eax
Empujar valor nulo
Llamar cuadro de mensajea
Operación XOR
Empujar eax
Llamar proceso de salida
Finalizar e iniciar
-
Enlace de compilación:
Se realiza en los siguientes dos pasos :
ml /c /coff 3.asm
link/subsystem:Windows/libpath:d:\ masm 7 \ lib 3
El primero. El paso es compilar y generar el archivo 3.obj.
/c significa solo compilar, no vincular.
/COFF significa generar un archivo de destino en formato COFF.
El segundo paso es vincular y generar el archivo 3.exe.
/subsystem:windows significa generar un archivo de Windows.
/libpath:d:\masm7\lib significa que la ruta a la biblioteca importada es: d:\masm7\lib.
Después de instalar Masm32, la biblioteca de importación se encuentra en el directorio Masm32\Lib.
También puede establecer el valor de la variable de entorno Lib: escriba Set Lib=d:\masm7\lib en el símbolo del sistema DOS, por lo que "enlace" se puede escribir simplemente como:
Enlace /subsystem:Windows 3.obj Imagínese, en el proceso de depuración del programa, es común modificar el programa fuente. Cada vez que compila un enlace, debe traer /libpath:... Qué molesto sería. . Por supuesto, también podemos dar directamente la ubicación de la biblioteca de importación en el programa fuente, lo que facilita el enlace, de la siguiente manera:
include lib d:\ masm 7 \ lib \ kernel 32. lib
Incluir lib d:\masm7\lib\user32.lib
-
Ejecución: escriba 3 en el indicador de dos y presione Enter, aparecerá un cuadro de mensaje, jaja , un ¡Un verdadero programa Win32!
-
Análisis en profundidad:
Mirando el programa fuente, hay dos líneas: call messageboxa\call exitprocess. Todo el mundo sabe que se trata de una llamada a una subrutina, pero nosotros no escribimos dicha subrutina. De hecho, estas son funciones API. Como función, es posible que necesitemos pasar algunos parámetros a la función al llamarla.
¿Cómo sabe el programa qué parámetros se pasan y qué tipos? Está definido por el prototipo de función de la siguiente manera:
ExitProcess PROTO :Dword
Cuadro de mensaje A PROTO :DWORD, :DWORD, :DWORD, :DWORD
Sí. Como puede ver, ExitProcess tiene un parámetro y MessageBoxA tiene cuatro parámetros, todos de tipo Dword.
En Win32, los parámetros se pasan a través de la pila. Una función como MessageBoxA toma cuatro parámetros. ¿Es el primero de la izquierda o el primero de la derecha? . Muere plano, stdcall da la respuesta. Los parámetros especificados por Stdcall se insertan en la pila de derecha a izquierda y el ajuste de la pila se completa cuando regresa la subrutina. No es necesario utilizar "agregar sp, valor" en el programa fuente para mantener la pila equilibrada. Para MessageBox, se define en el manual de API de la siguiente manera:
int MessageBox(
HWND hWnd, //El identificador de la ventana del propietario
LPCTSTR lpText ,/ /La dirección del texto en el cuadro de mensaje
LPCTSTR lpCaption, //La dirección del título del cuadro de mensaje
UINT uType & ampn
El El lenguaje ensamblador que estás viendo es: ¡Hola mundo! Subprograma ensamblador Win32
bsp//Estilo del cuadro de mensaje
)
;
Presiona MB_OK
lea eax, szCaption
Presiona eax
Lea eax, Shenzhen text
Presiona eax
Enviar un valor nulo
Llamar al cuadro de mensajea
Mirando el programa anterior, no es difícil imaginar que si se inserta un dato menos en la pila cuando Al escribir el programa, será un error fatal. ¿Puedo dejarle a usted la tarea de comprobar que el número de parámetros coincide con el del ordenador? Esto es posible, la instrucción INVOKE nos puede ayudar a hacerlo. Si tiene una cantidad incorrecta de parámetros, el conector dará un error. Por lo tanto, se recomienda encarecidamente utilizar invoke en lugar de call para invocar subrutinas. Por supuesto, esto no es absoluto. El uso del comando anterior invocar se puede abreviar de la siguiente manera, lo que parece mucho más simple y facilita la verificación de errores.
Llame a messageboxa, NULL, addr szText, addr szCaption, MB_OK
Además, NULL y MB_OK son constantes. Existen muchas constantes de este tipo y muchas estructuras. Si escribimos tantas cosas en nuestro programa desde el principio, es posible que nos asustemos de inmediato y es fácil cometer errores, lo que hace que sea incómodo ver las partes principales del programa. Windows.inc compilado por hutch contiene las definiciones de constantes y estructuras necesarias para la programación WIN32. Simplemente podemos insertar estas constantes y definiciones de estructura en nuestros archivos usando la directiva include:
include d:\masm 32\include\windows Inc
Pero Windows.inc Para declaraciones que. no contiene prototipos de funciones, debe obtener las declaraciones del prototipo de función de otros archivos de encabezado. Por ejemplo, el prototipo de messageboxa se declara en el archivo user32.inc y el proceso de salida se declara en el archivo kernel32.inc. Estos archivos de encabezado se colocan en la carpeta \masm32\include.
Además, para usar Windows.inc, se debe usar la opción casemap:none, lo que significa decirle a MASM que distinga el caso de los símbolos, por ejemplo, inicio y INICIO son diferentes. De lo contrario, ¡un programa pequeño puede cometer cientos de errores!
Del resto no entraré en detalles. En este momento, el programa anterior se puede modificar de la siguiente manera:
-
; El resultado final
.386 indica que se debe ejecutar la instrucción 386; usado.
.
Modelo de avión, programa stdcall de 32 bits, ¡usa avión! ;Llamada estándar
Diagrama de casos de opciones: Ninguno;Distingue entre mayúsculas y minúsculas
Incluye Windows.inc, incluidas constantes y definiciones de estructuras.
Incluir declaración de prototipo de función kernel32.inc
Incluir user32.inc
incluir lib kernel 32. lib biblioteca de introducción usada
includelib; usuario32.lib
. Datos; área de datos, define 2 cadenas.
szText db "¡Hola mundo!",0
szCaption db "Win32Asm ",0
. Código; posición de ejecución del código
Inicio:
Llamar a MessageBox, NULL, addr szText, addr szCaption, MB_OK
Llamar a la función MessageBoxAPI
Llame al proceso de salida, NULL. Salida del programa
Fin inicio; fin
-
Enlace de compilación:
ml/c/coff/I d:\ masm 7 \include 3. ASM; tenga en cuenta que los caracteres de cambio distinguen entre mayúsculas y minúsculas.
link/subsystem:Windows/libpath:d:\masm7\lib3.obj
/I d:\masm7\include indica la ubicación de *. inc, o puede configurar la variable de entorno Set include=d:\masm7\include para simplificar la operación, o puede indicar claramente la ubicación del archivo *. inc en el programa.
Todas las instrucciones anteriores se utilizan para completar el proceso de compilación, pero de hecho también puedes usar una instrucción, de la siguiente manera:
ml/coff/I d:\ masm 7 \ incluya 3 . ASM/link/subsystem:Windows/libpath:lib
if *. Las bibliotecas inc e import indican claramente su ubicación en el programa fuente, que se puede simplificar a:
ml /coff 3.asm /link /subsystem: