Consulte también el kit básico de montaje de ventanas Small Is Beautiful de Steve Gibson .
Jeremy
No usar bibliotecas c es una restricción algo extraña. Uno tiene que llamar a alguna biblioteca dentro del sistema operativo MS-Windows. probablemente kernel32.dll. Si Microsoft ha escrito esto en c o Pascal parece irrelevante. ¿Significa que solo se pueden llamar funciones proporcionadas por el sistema operativo, lo que en un sistema tipo Unix se llamarían llamadas al sistema?
Albert van der Horst
Con las bibliotecas C, supongo que quiere decir sin usar bibliotecas en tiempo de ejecución C como las que vienen con GCC o MSVC. Por supuesto, tendrá que utilizar algunas DLL estándar de Windows, como kernel32.dll.
Rudy Velthuis
2
La distinción entre kernel32.dll y una biblioteca en tiempo de ejecución gcc no está en el formato (ambos son dll) y no en el idioma (ambos son probablemente c, pero eso está oculto). La diferencia está entre el sistema operativo o no.
Albert van der Horst
He estado buscando esto también jajaja no pude encontrar nada con fasm sin incluye
; ----------------------------------------------------------------------------
; helloworld.asm
;
; This is a Win32 console program that writes "Hello, World"on one lineand
; 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
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" (de forma transparente) en cualquier Windows de 64 bits, porque un kernel x86-64 no puede usar el modo vm86.
La pregunta menciona explícitamente "sin usar bibliotecas C"
Mehrdad Afshari
25
Incorrecto. La biblioteca de C en sí, obviamente, puede, por lo que es posible. De hecho, es solo un poco más difícil. Solo necesita llamar a WriteConsole () con los 5 parámetros correctos.
MSalters
12
Aunque el segundo ejemplo no llama a ninguna función de la biblioteca C, tampoco es un programa de Windows. Se activará la máquina virtual DOS para ejecutarla.
Rômulo Ceccon
7
@Alex Hart, su segundo ejemplo es para DOS, no para Windows. En DOS, los programas en modo minúsculo (archivos .COM, menos de 64 KB de código total + datos + pila) comienzan en 0x100h porque los primeros 256 bytes del segmento los toma la PSP (argumentos de línea de comandos, etc.). Vea este enlace: en.wikipedia.org/wiki/Program_Segment_Prefix
zvolkov
7
Esto no es lo que se pidió. El primer ejemplo usa la biblioteca C y el segundo es MS-DOS, no Windows.
Paulo Pinto
131
Este ejemplo muestra cómo ir directamente a la API de Windows y no vincular en la biblioteca estándar de C.
es probable que deba incluir kernel32.lib para vincular esto (lo hice). enlace / subsistema: consola / nodefaultlib / entrada: principal hello.obj kernel32.lib
Estos son ejemplos de Win32 y Win64 que utilizan llamadas a la API de Windows. Son para MASM en lugar de NASM, pero échales un vistazo. Puede encontrar más detalles en este artículo.
Esto usa MessageBox en lugar de imprimir en stdout.
Win32 MASM
;---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:
push0 ; uType = MB_OK
push offset title ; LPCSTR lpCaption
push offset msg ; LPCSTR lpText
push0 ; hWnd = HWND_DESKTOP
call MessageBoxA
push eax ; uExitCode = MessageBox(...)
call ExitProcess
End Main
Win64 MASM
;---ASM Hello World Win64 MessageBox
extrn MessageBoxA: PROC
extrn ExitProcess: PROC
.data
title db 'Win64', 0
msg db 'Hello World!', 0
.code
main proc
subrsp, 28hmovrcx, 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 usando MASM, use esto para el ejecutable de 32 bits:
¿Por qué Windows x64 necesita reservar 28h bytes de espacio de pila antes de un call? Eso es 32 bytes (0x20) de espacio de sombra, también conocido como espacio doméstico, como lo requiere la convención de llamadas. Y otros 8 bytes para realinear la pila en 16, porque la convención de llamada requiere que RSP esté alineado con 16 bytes antes de a call. (Nuestro mainllamador (en el código de inicio CRT) hizo eso. La dirección de retorno de 8 bytes significa que RSP está a 8 bytes de un límite de 16 bytes al ingresar a una función).
Espacio de sombraUna función puede usar el para volcar sus argumentos de registro junto a donde estaría cualquier argumento de pila (si lo hubiera). A system callrequiere 30 h (48 bytes) para reservar también espacio para r10 y r11 además de los 4 registros mencionados anteriormente. Pero las llamadas a DLL son solo llamadas a funciones, incluso si son envolturas de syscallinstrucciones.
Dato curioso: no Windows, es decir, la convención de llamadas de System V x86-64 (por ejemplo, en Linux) no usa espacio de sombra en absoluto, y usa hasta 6 argumentos de registro de enteros / punteros, y hasta 8 argumentos de FP en registros XMM .
Usando MASM's invoke directiva (que conoce la convención de llamada), puede usar un ifdef para hacer una versión de esto que se puede construir como 32 bits o 64 bits.
La variante macro es la misma para ambos, pero no aprenderá a ensamblar de esta manera. En su lugar, aprenderá ASM estilo C. invokees para stdcallo fastcallmientras cinvokees para cdeclo argumento variable fastcall. El ensamblador sabe cuál usar.
Puede desmontar la salida para ver cómo se invokeexpande.
+1 por tu respuesta. ¿Puede agregar código de ensamblaje para Windows en ARM (WOA) también?
Annie
1
¿Por qué rsp requiere 0x28 bytes y no 0x20? Todas las referencias en la convención de llamada dicen que debería ser 32 pero parece requerir 40 en la práctica.
douggard
En su código de cuadro de mensaje de 32 bits, por alguna razón, cuando lo uso titlecomo nombre de etiqueta, me encuentro con errores. Sin embargo, cuando uso algo más como nombre de etiqueta mytitle, todo funciona bien.
user3405291
¿Cómo hacerlo sin incluir?
Bluejayke
14
Flat Assembler no necesita un enlazador adicional. Esto hace que la programación en ensamblador sea bastante sencilla. También está disponible para Linux.
Esto es hello.asmde 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 hola.asm
ensamblador plano versión 1.70.03 (1048575 kilobytes de memoria)
4 pasadas, 1536 bytes.
donde ruta_a_vínculo podría ser C: \ Archivos de programa (x86) \ Microsoft Visual Studio 10.0 \ VC \ bin o donde esté su programa link.exe en su máquina,
ruta_a_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, tanto kernel32.lib como user32.lib están en el mismo lugar; de lo contrario, use una opción para cada ruta que necesite) y / largeaddressaware: no opción necesario para evitar que el vinculador se queje de direcciones demasiado largas (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 ).
Recomiendo encarecidamente usarlo default relen la parte superior de su archivo para que esos modos de direccionamiento ( [msg]y [title]) utilicen direccionamiento relativo a RIP en lugar de absoluto de 32 bits.
Peter Cordes
¡Gracias por explicar cómo vincular! Salvaste mi salud mental. Estaba empezando a tirarme de los pelos por el 'error LNK2001: símbolo externo no resuelto ExitProcess' y errores similares ...
Nik
5
A menos que llame a alguna función, esto no es en absoluto trivial. (Y, en serio, no hay una diferencia real en complejidad entre llamar a printf y llamar a una función api win32).
Incluso DOS int 21h es en realidad solo una llamada de función, incluso si es una API diferente.
Si desea hacerlo sin ayuda, debe 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, nada de todo esto hasta el hardware es más interesante en ASM que en C. Un programa de "hola mundo" 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.
Este es un punto excelente: ASM y C dependen de una función proporcionada por el sistema operativo (_WriteFile en Windows). Entonces, ¿dónde está la magia? Está en el código del controlador del dispositivo para la tarjeta de video.
Assad Ebrahim
2
Esto está completamente fuera del punto. El cartel pide un programa ensamblador que se ejecuta "bajo Windows". Eso significa que se pueden usar las instalaciones de Windows (por ejemplo, kernel32.dll), pero no otras instalaciones como libc en Cygwin. Por gritar en voz alta, el cartel dice explícitamente que no hay bibliotecas c.
Albert van der Horst
5
Los mejores ejemplos son aquellos con fasm, porque fasm no usa un enlazador, lo que oculta la complejidad de la programación de Windows mediante otra capa opaca de complejidad. Si está satisfecho con un programa que escribe en una ventana de interfaz gráfica de usuario, entonces hay un ejemplo para eso en el directorio de ejemplo de fasm.
Si desea un programa de consola, que permita la redirección de entrada y salida estándar, también es posible. Hay un programa de ejemplo (helas muy no trivial) disponible que no usa una interfaz gráfica de usuario y funciona estrictamente con la consola, es decir, fasm. Esto se puede reducir a lo esencial. (Escribí un cuarto compilador que es otro ejemplo que no es de interfaz gráfica de usuario, pero tampoco es trivial).
Dicho programa tiene el siguiente comando para generar un encabezado adecuado para un ejecutable de 32 bits, normalmente realizado por un enlazador.
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.
El formato de tabla lo imponen las ventanas y contiene nombres que se buscan en los archivos del sistema cuando se inicia el programa. FASM oculta parte de la complejidad detrás de la palabra clave rva. Entonces, _SalirProcess @ 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, se puede escribir y ejecutar, es la única sección que necesita agregar.
section '.text' code executable readable writable
Puedes llamar a todas las instalaciones que declaraste en la sección .idata. Para un programa de consola, necesita _GetStdHandle para encontrar los descriptores de archivo para la 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 sea consciente de eso o no probaría la programación en 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 a las que se puede llamar, que utiliza en su programa.
Es posible que FASM no use un enlazador, pero aún tiene que ensamblar un archivo PE. Lo que significa que en realidad no solo ensambla código, sino que también asume un trabajo que normalmente realizaría un vinculador, y como tal, en mi humilde opinión, es engañoso llamar a la ausencia de un vinculador "ocultar complejidad", todo lo contrario. - el trabajo de un ensamblador es ensamblar un programa, pero deja que el enlazador incruste el programa en una imagen de programa que puede depender de muchas cosas. Como tal, considero que la separación entre un enlazador y un ensamblador es algo bueno , y parece que no estás de acuerdo.
AMN
@amn Piénsalo de esta manera. Si usa un enlazador para crear el programa anterior, ¿le brinda más información sobre lo que hace el programa o en qué consiste? Si miro la fuente de fasm, conozco la estructura completa del programa.
Albert van der Horst
Punto justo. Por otro lado, separar los enlaces de todo lo demás también tiene sus beneficios. Normalmente tiene acceso a un archivo de objeto (lo que contribuye en gran medida a permitir que uno inspeccione la estructura de un programa también, independientemente del formato del archivo de imagen del programa), puede invocar un enlazador diferente de su preferencia, con diferentes opciones. Se trata de reutilización y componibilidad. Con eso en mente, FASM haciendo todo porque es "conveniente" rompe esos principios. No estoy principalmente en contra de ello, veo su justificación para ello, pero yo, por mi parte, no lo necesito.
amn
obtener un error por una instrucción ilegal en la línea superior en fasm windows de 64 bits
bluejayke
@bluejayke Probablemente no tenía la documentación para fasm a mano. FORMAT PE genera un ejecutable de 32 bits, que una ventana de 64 bits se niega a ejecutar. Para un programa de 64 bits, desea FORMAT PE64. También asegúrese de utilizar las instrucciones adecuadas de 64 bits en su programa.
Albert van der Horst
3
Si desea utilizar NASM y el enlazador de Visual Studio (link.exe) con el ejemplo de Hello World de anderstornvig, tendrá que enlazar manualmente con la biblioteca de tiempo de ejecución de C que contiene la función printf ().
El cartel de las preguntas quiere saber cómo alguien escribiría printf en función de las facilidades que proporciona Windows, así que esto es totalmente distinto al punto.
Respuestas:
Ejemplos de NASM .
Llamar libc stdio
printf
, implementarint main(){ return printf(message); }
; ---------------------------------------------------------------------------- ; 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
Entonces corre
nasm -fwin32 helloworld.asm gcc helloworld.obj a
También está la guía Clueless Newbies para 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" (de forma transparente) en cualquier Windows de 64 bits, porque un kernel 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,'$'
Construya esto en un
.com
ejecutable para que se carguecs:100h
con todos los registros de segmento iguales entre sí (modelo de memoria pequeña).Buena suerte.
fuente
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)
fuente
gcc hello.obj
Estos son ejemplos de Win32 y Win64 que utilizan llamadas a la API de Windows. Son para MASM en lugar de NASM, pero échales un vistazo. Puede encontrar más detalles en este artículo.
Esto usa MessageBox en lugar de imprimir en stdout.
Win32 MASM
;---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
Win64 MASM
;---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 usando 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 ejecutables de 64 bits:
ml64.exe [filename] /link /subsystem:windows /defaultlib:kernel32.lib /defaultlib:user32.lib /entry:main
¿Por qué Windows x64 necesita reservar 28h bytes de espacio de pila antes de un
call
? Eso es 32 bytes (0x20) de espacio de sombra, también conocido como espacio doméstico, como lo requiere la convención de llamadas. Y otros 8 bytes para realinear la pila en 16, porque la convención de llamada requiere que RSP esté alineado con 16 bytes antes de acall
. (Nuestromain
llamador (en el código de inicio CRT) hizo eso. La dirección de retorno de 8 bytes significa que RSP está a 8 bytes de un límite de 16 bytes al ingresar a una función).Espacio de sombraUna función puede usar el para volcar sus argumentos de registro junto a donde estaría cualquier argumento de pila (si lo hubiera). A
system call
requiere 30 h (48 bytes) para reservar también espacio para r10 y r11 además de los 4 registros mencionados anteriormente. Pero las llamadas a DLL son solo llamadas a funciones, incluso si son envolturas desyscall
instrucciones.Dato curioso: no Windows, es decir, la convención de llamadas de System V x86-64 (por ejemplo, en Linux) no usa espacio de sombra en absoluto, y usa hasta 6 argumentos de registro de enteros / punteros, y hasta 8 argumentos de FP en registros XMM .
Usando MASM's
invoke
directiva (que conoce la convención de llamada), puede usar un ifdef para hacer una versión de esto que se puede construir como 32 bits o 64 bits.ifdef rax extrn MessageBoxA: PROC extrn ExitProcess: PROC else .386 .model flat, stdcall include kernel32.inc includelib kernel32.lib include user32.inc includelib user32.lib endif .data caption db 'WinAPI', 0 text db 'Hello World', 0 .code main proc invoke MessageBoxA, 0, offset text, offset caption, 0 invoke ExitProcess, eax main endp end
La variante macro es la misma para ambos, pero no aprenderá a ensamblar de esta manera. En su lugar, aprenderá ASM estilo C.
invoke
es parastdcall
ofastcall
mientrascinvoke
es paracdecl
o argumento variablefastcall
. El ensamblador sabe cuál usar.Puede desmontar la salida para ver cómo se
invoke
expande.fuente
title
como nombre de etiqueta, me encuentro con errores. Sin embargo, cuando uso algo más como nombre de etiquetamytitle
, todo funciona bien.Flat Assembler no necesita un enlazador adicional. Esto hace que la programación en ensamblador sea bastante sencilla. 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:
Y este es el programa en IDA :
Se puede ver las tres llamadas:
GetCommandLine
,MessageBox
yExitProcess
.fuente
Para obtener un .exe con NASM'compiler y el vinculador 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, por ejemplo, "test64.asm", entonces 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 ruta_a_vínculo podría ser C: \ Archivos de programa (x86) \ Microsoft Visual Studio 10.0 \ VC \ bin o donde esté su programa link.exe en su máquina, ruta_a_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, tanto kernel32.lib como user32.lib están en el mismo lugar; de lo contrario, use una opción para cada ruta que necesite) y / largeaddressaware: no opción necesario para evitar que el vinculador se queje de direcciones demasiado largas (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 ).
fuente
default rel
en la parte superior de su archivo para que esos modos de direccionamiento ([msg]
y[title]
) utilicen direccionamiento relativo a RIP en lugar de absoluto de 32 bits.A menos que llame a alguna función, esto no es en absoluto trivial. (Y, en serio, no hay una diferencia real en complejidad entre llamar a printf y llamar a una función api win32).
Incluso DOS int 21h es en realidad solo una llamada de función, incluso si es una API diferente.
Si desea hacerlo sin ayuda, debe 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, nada de todo esto hasta el hardware es más interesante en ASM que en C. Un programa de "hola mundo" 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.
fuente
Los mejores ejemplos son aquellos con fasm, porque fasm no usa un enlazador, lo que oculta la complejidad de la programación de Windows mediante otra capa opaca de complejidad. Si está satisfecho con un programa que escribe en una ventana de interfaz gráfica de usuario, entonces hay un ejemplo para eso en el directorio de ejemplo de fasm.
Si desea un programa de consola, que permita la redirección de entrada y salida estándar, también es posible. Hay un programa de ejemplo (helas muy no trivial) disponible que no usa una interfaz gráfica de usuario y funciona estrictamente con la consola, es decir, fasm. Esto se puede reducir a lo esencial. (Escribí un cuarto compilador que es otro ejemplo que no es de interfaz gráfica de usuario, pero tampoco es trivial).
Dicho programa tiene el siguiente comando para generar un encabezado adecuado para un ejecutable de 32 bits, normalmente realizado por un enlazador.
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
El formato de tabla lo imponen las ventanas y contiene nombres que se buscan en los archivos del sistema cuando se inicia el programa. FASM oculta parte de la complejidad detrás de la palabra clave rva. Entonces, _SalirProcess @ 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, se puede escribir y ejecutar, es la única sección que necesita agregar.
section '.text' code executable readable writable
Puedes llamar a todas las instalaciones que declaraste en la sección .idata. Para un programa de consola, necesita _GetStdHandle para encontrar los descriptores de archivo para la 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 sea consciente de eso o no probaría la programación en 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 a las que se puede llamar, que utiliza en su programa.
fuente
Si desea utilizar NASM y el enlazador de Visual Studio (link.exe) con el ejemplo de Hello World de anderstornvig, tendrá que enlazar manualmente con la biblioteca de 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.
fuente