Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
975 views
in Technique[技术] by (71.8m points)

winapi - Linking to Kernel32.lib in assembler

I started learning assembly today and have ran many tests on linux that worked very well! I moved over to my PC and started to attempt to write some here. I ran into a problem when attempting to call external functions (which again, worked fine on linux) where I would get LINK 2001 Unresolved External errors telling me that WriteConsoleA is not defined when after compiling with nasm:

nasm -f win32 test.asm -o test.obj

and with cl.exe:

cl test.obj /link libcmt.lib kernel32.lib

I get these errors:

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

The assembly:

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

Copied almost exactly from here. Any help is much appreciated! Thanks!

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

First off, cl is not a linker but a compiler. Why not just use GoLink as I shown in the post you linked to? It is much easier to use. You could use ld as the linker, but your externs will change a bit.

Windows API functions use function name decorations - an underscore + FunctionName + @sizeof parameters, this is a linker thing.

So, ExitProcess is really exported as _ExitProcess@4 since it takes 1 DWORD parameter. WriteConsoleA takes 5 parameters DWORD sized, so it would be _WriteConsole@20

Change your code to:

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

To link with ld, tell it where the lib directory is, a good bet is: -L "C:Program FilesMicrosoft SDKsWindowsv6.0Lib"

then just use the -l flag with the library -l kernel32

My makefile using NASM and ld for your sample code:

APP= Sample

all: $(APP) clean


$(APP): $(APP).obj
    "C:MinGWinld" $(APP).obj -o $(APP).exe -L "C:Program FilesMicrosoft SDKsWindowsv6.0Lib" -l kernel32

$(APP).obj: $(APP).asm
    nasm -f win32 $(APP).asm -o $(APP).obj

clean:
    rm $(APP).obj

If you were to use GoLink as in the other post, you could just use the API Function names as they appear in the docs.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...