linkernasmcrtuniversal-crt

How to link Windows universal CRT to obj file compiled with nasm


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:

  1. 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.

  2. 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.


Solution

  • 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.