Pregunta

Quería escribir algo básico en el ensamblaje en Windows, estoy usando NASM, pero no puedo hacer que nada funcione.

¿Cómo escribir y compilar hello world sin la ayuda de las funciones de C en Windows?

¿Fue útil?

Solución

NASM ejemplos .

Llamando a libc stdio printf , implementando int main () {return printf (mensaje); }

; ----------------------------------------------------------------------------
; helloworld.asm
;
; This is a Win32 console program that writes "Hello, World" on one line and
; then exits.  It needs to be linked with a C library.
; ----------------------------------------------------------------------------

    global  _main
    extern  _printf

    section .text
_main:
    push    message
    call    _printf
    add     esp, 4
    ret
message:
    db  'Hello, World', 10, 0

Luego ejecuta

nasm -fwin32 helloworld.asm
gcc helloworld.obj
a

También hay The Clueless Guía para principiantes de Hello World en Nasm sin el uso de una biblioteca C. Entonces el código se vería así.

Código de 16 bits con llamadas al sistema MS-DOS: funciona en emuladores de DOS o en Windows de 32 bits con soporte NTVDM . No se puede ejecutar " directamente " (transparente) en cualquier Windows de 64 bits, porque un núcleo x86-64 no puede usar el modo vm86.

org 100h
mov dx,msg
mov ah,9
int 21h
mov ah,4Ch
int 21h
msg db 'Hello, World!',0Dh,0Ah,'

Cree esto en un ejecutable .com para que se cargue en cs: 100h con todos los registros de segmentos iguales entre sí (modelo de memoria pequeña).

Buena suerte.

Cree esto en un ejecutable .com para que se cargue en cs: 100h con todos los registros de segmentos iguales entre sí (modelo de memoria pequeña).

Buena suerte.

Otros consejos

Este ejemplo muestra cómo ir directamente a la API de Windows y no vincular en la Biblioteca estándar de C.

    global _main
    extern  _GetStdHandle@4
    extern  _WriteFile@20
    extern  _ExitProcess@4

    section .text
_main:
    ; DWORD  bytes;    
    mov     ebp, esp
    sub     esp, 4

    ; hStdOut = GetstdHandle( STD_OUTPUT_HANDLE)
    push    -11
    call    _GetStdHandle@4
    mov     ebx, eax    

    ; WriteFile( hstdOut, message, length(message), &bytes, 0);
    push    0
    lea     eax, [ebp-4]
    push    eax
    push    (message_end - message)
    push    message
    push    ebx
    call    _WriteFile@20

    ; ExitProcess(0)
    push    0
    call    _ExitProcess@4

    ; never here
    hlt
message:
    db      'Hello, World', 10
message_end:

Para compilar, necesitará NASM y LINK.EXE (de Visual Studio Standard Edition)

   nasm -fwin32 hello.asm
   link /subsystem:console /nodefaultlib /entry:main hello.obj 

Estos son ejemplos de Win32 y Win64 que utilizan llamadas API de Windows. Son para MASM en lugar de NASM, pero échales un vistazo. Puede encontrar más detalles en this artículo.

;---ASM Hello World Win32 MessageBox

.386
.model flat, stdcall
include kernel32.inc
includelib kernel32.lib
include user32.inc
includelib user32.lib

.data
title db 'Win32', 0
msg db 'Hello World', 0

.code

Main:
push 0            ; uType = MB_OK
push offset title ; LPCSTR lpCaption
push offset msg   ; LPCSTR lpText
push 0            ; hWnd = HWND_DESKTOP
call MessageBoxA
push eax          ; uExitCode = MessageBox(...)
call ExitProcess

End Main

;---ASM Hello World Win64 MessageBox

extrn MessageBoxA: PROC
extrn ExitProcess: PROC

.data
title db 'Win64', 0
msg db 'Hello World!', 0

.code
main proc
  sub rsp, 28h  
  mov rcx, 0       ; hWnd = HWND_DESKTOP
  lea rdx, msg     ; LPCSTR lpText
  lea r8,  title   ; LPCSTR lpCaption
  mov r9d, 0       ; uType = MB_OK
  call MessageBoxA
  add rsp, 28h  
  mov ecx, eax     ; uExitCode = MessageBox(...)
  call ExitProcess
main endp

End

Para ensamblar y vincular estos utilizando MASM, use esto para el ejecutable de 32 bits:

ml.exe [filename] /link /subsystem:windows 
/defaultlib:kernel32.lib /defaultlib:user32.lib /entry:Main

o esto para el ejecutable de 64 bits:

ml64.exe [filename] /link /subsystem:windows 
/defaultlib:kernel32.lib /defaultlib:user32.lib /entry:main

Flat Assembler no necesita un vinculador adicional. Esto hace que la programación del ensamblador sea bastante fácil. También está disponible para Linux.

Esto es hello.asm de los ejemplos de Fasm:

include 'win32ax.inc'

.code

  start:
    invoke  MessageBox,HWND_DESKTOP,"Hi! I'm the example program!",invoke GetCommandLine,MB_OK
    invoke  ExitProcess,0

.end start

Fasm crea un ejecutable:

>fasm hello.asm
flat assembler  version 1.70.03  (1048575 kilobytes memory)
4 passes, 1536 bytes.

Y este es el programa en IDA :

ingrese la descripción de la imagen aquí

Puede ver las tres llamadas: GetCommandLine , MessageBox y ExitProcess .

Para obtener un .exe con NASM'compiler y el enlazador de Visual Studio, este código funciona bien:

global WinMain
extern ExitProcess  ; external functions in system libraries 
extern MessageBoxA

section .data 
title:  db 'Win64', 0
msg:    db 'Hello world!', 0

section .text
WinMain:
    sub rsp, 28h  
    mov rcx, 0       ; hWnd = HWND_DESKTOP
    lea rdx,[msg]    ; LPCSTR lpText
    lea r8,[title]   ; LPCSTR lpCaption
    mov r9d, 0       ; uType = MB_OK
    call MessageBoxA
    add rsp, 28h  

    mov  ecx,eax
    call ExitProcess

    hlt     ; never here

Si este código se guarda en, p. " test64.asm " ;, luego para compilar:

nasm -f win64 test64.asm

Produce " test64.obj " Luego, para vincular desde el símbolo del sistema:

path_to_link\link.exe test64.obj /subsystem:windows /entry:WinMain  /libpath:path_to_libs /nodefaultlib kernel32.lib user32.lib /largeaddressaware:no

donde path_to_link podría ser C: \ Archivos de programa (x86) \ Microsoft Visual Studio 10.0 \ VC \ bin o donde sea que esté su programa link.exe en su máquina, path_to_libs podría ser C: \ Archivos de programa (x86) \ Windows Kits \ 8.1 \ Lib \ winv6.3 \ um \ x64 o donde sea que estén sus bibliotecas (en este caso, ambas kernel32.lib y user32.lib están en el mismo lugar; de lo contrario, use una opción para cada ruta que necesite) y la opción / largeaddressaware: no es necesaria para evitar que el enlazador se queje de las direcciones por mucho tiempo (para user32 .lib en este caso). Además, como se hace aquí, si se invoca el vinculador de Visual desde el símbolo del sistema, es necesario configurar el entorno previamente (ejecutar una vez vcvarsall.bat y / o ver MS C ++ 2010 y mspdb100.dll ).

A menos que llame a alguna función, esto no es en absoluto trivial. (Y, en serio, no existe una diferencia real en la complejidad entre llamar a printf y llamar a una función win32 api).

Incluso DOS int 21h es realmente solo una llamada de función, incluso si es una API diferente.

Si desea hacerlo sin ayuda, necesita hablar directamente con su hardware de video, probablemente escribiendo mapas de bits de las letras de "Hola mundo". en un framebuffer. Incluso entonces, la tarjeta de video está haciendo el trabajo de traducir esos valores de memoria en señales VGA / DVI.

Tenga en cuenta que, en realidad, ninguna de estas cosas hasta el hardware es más interesante en ASM que en C. A '' hola mundo '' El programa se reduce a una llamada de función. Una cosa buena de ASM es que puede usar cualquier ABI que desee con bastante facilidad; solo necesita saber qué es ese ABI.

Si desea utilizar el enlazador de NASM y Visual Studio (link.exe) con el ejemplo Hello World de anderstornvig, deberá vincularlo manualmente con la biblioteca en tiempo de ejecución de C que contiene la función printf ().

nasm -fwin32 helloworld.asm
link.exe helloworld.obj libcmt.lib

Espero que esto ayude a alguien.

Los mejores ejemplos son aquellos con fasm, porque fasm no usa un enlazador, lo que oculta la complejidad de la programación de Windows por otra capa opaca de complejidad. Si estás contento con un programa que escribe en una ventana gui, entonces hay un ejemplo para eso en el directorio de ejemplo de fasm.

Si desea un programa de consola, eso también permite la redirección de entrada y salida estándar. Hay un programa de ejemplo (helas altamente no trivial) disponible que no utiliza una interfaz gráfica de usuario y funciona estrictamente con la consola, es decir, el propio fasm. Esto se puede reducir a lo esencial. (He escrito un cuarto compilador que es otro ejemplo que no es GUI, pero que tampoco es trivial).

Dicho programa tiene el siguiente comando para generar un encabezado ejecutable adecuado, normalmente realizado por un vinculador.

FORMAT PE CONSOLE 

Una sección llamada '.idata' contiene una tabla que ayuda a Windows durante el inicio a acoplar nombres de funciones a las direcciones de tiempo de ejecución. También contiene una referencia a KERNEL.DLL, que es el sistema operativo Windows.

 section '.idata' import data readable writeable
    dd 0,0,0,rva kernel_name,rva kernel_table
    dd 0,0,0,0,0

  kernel_table:
    _ExitProcess@4    DD rva _ExitProcess
    CreateFile        DD rva _CreateFileA
        ...
        ...
    _GetStdHandle@4   DD rva _GetStdHandle
                      DD 0

Windows impone el formato de tabla y contiene nombres que se buscan en los archivos del sistema cuando se inicia el programa. FASM oculta algunas de las complejidad detrás de la palabra clave rva. Entonces _ExitProcess @ 4 es una etiqueta fasm y _exitProcess es una cadena que Windows busca.

Su programa está en la sección '.text'. Si declara que esa sección es legible, escribible y ejecutable, es la única sección que necesita agregar.

    section '.text' code executable readable writable

Puede llamar a todas las instalaciones que declaró en la sección .idata. Para un programa de consola, necesita _GetStdHandle para encontrar los descriptores de archivos para entrada y salida estándar (usando nombres simbólicos como STD_INPUT_HANDLE que fasm encuentra en el archivo de inclusión win32a.inc). Una vez que tenga los descriptores de archivo, puede hacer WriteFile y ReadFile. Todas las funciones se describen en la documentación de kernel32. Probablemente lo sepa o no probaría la programación del ensamblador.

En resumen: hay una tabla con nombres ASCI que se acoplan al sistema operativo Windows. Durante el inicio, esto se transforma en una tabla de direcciones invocables, que utiliza en su programa.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top