winapi - Vinculación a Kernel32.lib en ensamblador
assembly nasm (1)
¡Empecé a aprender ensamblaje hoy y realicé muchas pruebas en Linux que funcionaron muy bien! Me mudé a mi PC y comencé a intentar escribir algunos aquí. Me encontré con un problema al intentar llamar a funciones externas (que una vez más, funcionó bien en Linux) donde obtendría LINK 2001 Errores externos no resueltos que me indicaban que WriteConsoleA no está definido cuando después de compilar con nasm:
nasm -f win32 test.asm -o test.obj
y con cl.exe:
cl test.obj /link libcmt.lib kernel32.lib
Obtengo estos errores:
test.obj : error LNK2001: unresolved external symbol ExitProcess
test.obj : error LNK2001: unresolved external symbol GetStdHandle
test.obj : error LNK2001: unresolved external symbol WriteConsoleA
test.exe : fatal error LNK1120: 3 unresolved externals
La Asamblea:
extern ExitProcess, GetStdHandle, WriteConsoleA
NULL equ 0
STD_OUTPUT_HANDLE equ -11
section .data
msg db "Hello world!",0xa
msgLen equ $-msg
section .bss
dummy resd 1
section .text
global _main
_main:
push STD_OUTPUT_HANDLE
call GetStdHandle
push NULL
push dummy
push msgLen
push msg
push eax
call WriteConsoleA
push NULL
call ExitProcess
Copiado casi exactamente desde aquí . ¡Cualquier ayuda es muy apreciada! ¡Gracias!
En primer lugar, cl no es un enlazador sino un compilador. ¿Por qué no simplemente usar GoLink como lo mostré en la publicación a la que se vinculó? Es mucho más fácil de usar. Podría usar ld como el enlazador, pero sus externos cambiarán un poco.
Las funciones de API de Windows usan decoraciones de nombre de función - un guión bajo + Nombre de Función + @ tamaño de parámetros, esta es una cosa enlazadora.
Entonces, ExitProcess se exporta realmente como _ExitProcess @ 4 ya que toma 1 parámetro DWORD. WriteConsoleA toma 5 parámetros de tamaño DWORD, por lo que sería _WriteConsole @ 20
Cambia tu código a:
extern _ExitProcess@4, _GetStdHandle@4, _WriteConsoleA@20
%define ExitProcess _ExitProcess@4
%define GetStdHandle _GetStdHandle@4
%define WriteConsoleA _WriteConsoleA@20
NULL equ 0
STD_OUTPUT_HANDLE equ -11
section .data
msg db "Hello world!",0xa
msgLen equ $-msg
section .bss
dummy resd 1
section .text
global _main
_main:
push STD_OUTPUT_HANDLE
call GetStdHandle
push NULL
push dummy
push msgLen
push msg
push eax
call WriteConsoleA
push NULL
call ExitProcess
Para vincular con ld, dígale dónde está el directorio lib, una buena apuesta es: -L "C: / Archivos de programa / Microsoft SDKs / Windows / v6.0 / Lib"
entonces solo usa la bandera -l
con la biblioteca -l kernel32
Mi archivo make usando NASM y ld para su código de muestra:
APP= Sample
all: $(APP) clean
$(APP): $(APP).obj
"C:/MinGW/bin/ld" $(APP).obj -o $(APP).exe -L "C:/Program Files/Microsoft SDKs/Windows/v6.0/Lib" -l kernel32
$(APP).obj: $(APP).asm
nasm -f win32 $(APP).asm -o $(APP).obj
clean:
rm $(APP).obj
Si utilizara GoLink como en la otra publicación, podría simplemente usar los nombres de la Función API tal como aparecen en los documentos.