Environment: Windows 10. I happen to be using a MinGW version of ld
for linking, but I'm happy to use the visual studio link.exe
if it makes things simpler.
I have the following basic program in nasm:
global _main
extern _printf
section .text
_main:
push message
call _printf
add esp, 4
ret
message:
db 'Hello, World', 10, 0
And it builds fine using
nasm -f win32 test.nasm
When trying to link it to the windows CRT (ucrt.lib), I get the following error:
$ ld -o test.exe test.obj
test.obj:test.nasm:(.text+0x6): undefined reference to `printf'
Ok, so I need to point the linker at the ucrt library:
$ ld -o test.exe /c/Program\ Files\ \(x86\)/Windows\
Kits/10/Lib/10.0.14393.0/ucrt/x86/ucrt.lib test.obj
test.obj:test.nasm:(.text+0x6): undefined reference to `printf'
Trying the equivalent with the visual studio linker:
d:\Code\nasm>link -out:test.exe -entry:main -subsystem:console test.obj
Microsoft (R) Incremental Linker Version 14.10.25017.0
Copyright (C) Microsoft Corporation. All rights reserved.
test.obj : error LNK2001: unresolved external symbol _printf
test.exe : fatal error LNK1120: 1 unresolved externals
This raises a couple of questions:
Why does one of these try to find printf
and the other, _printf
? I get that there's an underscore convention, but it doesn't seem to be understood by both linkers.
I used objdump -t
to look at the symbols in the ucrt.lib file. I won't paste the entire list, but it contains entries such as:
[ 4](sec 1)(fl 0x00)(ty 0)(scl 2) (nx 0) 0x00000000 __imp____conio_common_vcprintf
[ 5](sec 3)(fl 0x00)(ty 0)(scl 2) (nx 0) 0x00000000 ___conio_common_vcprintf
[ 4](sec 1)(fl 0x00)(ty 0)(scl 2) (nx 0) 0x00000000 __imp____conio_common_vcprintf_p
Neither printf
nor _printf
appears in the list. Does this mean it's not exported by that library? If not, which library should I be linking?
According to this MS article, ucrt.lib
is the de-facto library for the c runtime and C standard library.
Thanks to a comment from Michael Petch, it looks like I need to manually link 1 or more extra libs which are in a completely separate location from the ucrt.lib
library. The relevant one for printf is legacy_stdio_definitions.lib
, which I found deep in a sub-dir of my VS2017 install directory, as opposed to the ucrt.lib
which is in the Windows SDK install directory.
The definition of printf
is provided inline in stdio.h
unless the macro _NO_CRT_STDIO_INLINE
is defined, which I guess it usually is when building inside the VS toolchain.