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

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.

Related

VC2019 address sanitizer 64 bit link error on windows "unresolved external symbol __asan_shadow_memory_dynamic_address"

The following simple program
#include <malloc.h>
int main(int argc, char **argv)
{
char* arr=malloc(10);
arr[10]='\0';
return 0;
}
builds fine with VC2019 16.8.2 in 32 bit dynamic linking
cl -Zi -fsanitize=address -MD clang_rt.asan_dynamic-i386.lib xx.c
and reports the memory error when running the program.
However when using the 64bit variant I get a linking error
> cl -Zi -fsanitize=address -MD clang_rt.asan_dynamic-x86_64.lib xx.c
Microsoft (R) C/C++ Optimizing Compiler Version 19.28.29336 for x64
Copyright (C) Microsoft Corporation. All rights reserved.
xx.c
Microsoft (R) Incremental Linker Version 14.28.29336.0
Copyright (C) Microsoft Corporation. All rights reserved.
/out:xx.exe
/debug
clang_rt.asan_dynamic-x86_64.lib
xx.obj
xx.obj : error LNK2019: unresolved external symbol __asan_shadow_memory_dynamic_address referenced in function main
xx.exe : fatal error LNK1120: 1 unresolved externals
Looking in the clang_rt.asan_dynamic-x86_64.lib with dumpbin the missing symbol appears.
Note that on both architectures static linking of the sample (without the _dynamic libs) works, but I need dynamic linking because of larger dependencies (Qt dlls).
Anyone stumbled across that already ?
Regards, Leo
turned out I need another link library for 64 bit in addition clang_rt.asan_dynamic_runtime_thunk-x86_64.lib
cl -MD -fsanitize=address clang_rt.asan_dynamic-x86_64.lib clang_rt.asan_dynamic_runtime_thunk-x86_64.lib xx.c
links the program correctly and brings up the sanitizer error after starting the program.
The page https://devblogs.microsoft.com/cppblog/asan-for-windows-x64-and-debug-build-support/ has a nice table which enumerates all the different build models and which asan libs are needed.

Visual C linker behaves differently on 32-bit and 64-bit

Take a look at the following example code:
__declspec(dllexport) FreeLibrary(void)
{
}
I build it as a DLL with the following little script:
cl /EHsc /MT /c test.c /Fotest.o
link /dll /out:test.dll test.o
This works fine when compiling for the 32-bit architecture. When compiling for the 64-bit architecture, however, the DLL isn't built and I get the following error:
Microsoft (R) Incremental Linker Version 9.00.30729.01
Copyright (C) Microsoft Corporation. All rights reserved.
kernel32.lib(KERNEL32.dll) : error LNK2005: FreeLibrary already defined in test.o
Creating library test.lib and object test.exp
test.dll : fatal error LNK1169: one or more multiply defined symbols found
Why is that? Why does it work on 32-bit but not on 64-bit? Shouldn't the FreeLibrary symbol be defined in the 32-bit kernel32.dll as well? But why doesn't the 32-bit linker complain then and builds the DLL just fine?
This is really confusing to me...
Edited to correct error spotted by IInspectable and for clarity
32-bit
The default calling convention is __cdecl, which causes the symbol name to be prepended with an underscore: _FreeLibrary.
>dumpbin /symbols test.o | find "FreeLibrary"
008 00000000 SECT3 notype () External | _FreeLibrary
The FreeLibrary in kernel32.dll is declared with WINAPI. In 32-bit, WINAPI expands to __stdcall, so kernel32's function is named _FreeLibrary#4.
>dumpbin /exports kernel32.lib | find "FreeLibrary"
_FreeLibrary#4
_FreeLibraryAndExitThread#8
_FreeLibraryWhenCallbackReturns#8
Since _FreeLibrary doesn't match _FreeLibrary#4, there's no conflict.
64-bit
The default calling convention is a four-register fastcall scheme that does not decorate the name of a plain C function. Thus test.o defines a symbol named FreeLibrary:
>dumpbin /symbols test.o | find "FreeLibrary"
008 00000000 SECT3 notype () External | FreeLibrary
Also, the WINAPI macro expands to nothing, so kernel32.dll uses the same default calling convention as your plugin code. Thus it gets the same, unadorned symbol:
>dumpbin /exports kernel32.lib | find "FreeLibrary"
FreeLibrary
FreeLibraryAndExitThread
FreeLibraryWhenCallbackReturns
This gives you two FreeLibrary symbols and results in the linker error.

Clang, Microsoft linker and standard library

I have successfully built Clang with Microsoft C++ and I'm trying to get it to compile a hello world test case; it gets as far as generating an object file, linking with the standard library being the remaining stumbling block:
hello-202520.o : error LNK2019: unresolved external symbol _printf referenced in function _main
LINK : error LNK2001: unresolved external symbol _mainCRTStartup
There are comments from previous years saying Clang doesn't yet do Windows linking at all, but I get the impression those are outdated, and indeed it does now seem to be able to generate Windows format object files:
clang -c hello.c
ren hello.o hello.obj
link hello.obj
... doesn't barf, so the file format seems to be correct, but still gets the unresolved external symbol errors. Likely guess is the Microsoft compiler tags its output object files with an indication of the standard library they need to be linked with whereas Clang doesn't, and eyeballing a hex dump of the respective object files seems to confirm this and gives a hint of the linker command line to use:
link /defaultlib:libcmt /defaultlib:oldnames hello.obj
I had high hopes by this stage but alas it still gives the same unresolved external symbol errors.
What am I still missing?
Turns out Clang was by default generating 32-bit code but I was using 64-bit MSC, and the leading _ on C symbols has been dropped with the move to x64, so specifying -m64 on the clang command line did the job.

Visual Studio C++ link with psapi.lib

I have written a C Program which calls the function, GetModuleInformation() which is defined in psapi.h
I am using Microsoft Visual Studio C++ command line compiler (cl.exe) for compiling and linking the program.
I have included the psapi.h header file:
#include <psapi.h>
when I try to compile using:
cl program.c
It generates the object file, however fails during the linking stage with the error:
program.obj : error LNK2019: unresolved external symbol _GetModuleInformation#16 ref
erenced in function _main
program.exe : fatal error LNK1120: 1 unresolved externalsprogram.obj : error LNK2019: unresolved external symbol _GetModuleInformation#16 ref
I also place the psapi.lib file in the same folder where the source code file (program.c) is placed, however even then I get the same error message as above.
How do I successfully link it using the command line compiler (cl.exe)?
Method 1
If you want to compile from the command line with cl.exe you can use the /link option to specify linker options :
cl /TC program.c /link psapi.lib
Method 2
The following pragma directive causes the linker to search in your source file for the psapi.lib library while linking .
#pragma comment( lib, "psapi.lib" )
Possible reason for your errors can be, if psapi.lib is missing in a list of additional libraries of linker.
To resolve this, use the following /LIBPATH option :
cl /TC program.c /link Psapi.Lib /LIBPATH:C:\MyLibFolder\
Where C:\MyLibFolder specifies a path to the folder, that contains your psapi.lib .
Also, you can try to set the proper /SUBSYSTEM option .
For a Console application use :
/SUBSYSTEM:CONSOLE
Solution to similar problem here .
Example on using the GetModuleInformation function :
#include <windows.h>
#include <stdio.h>
#include <psapi.h>
#pragma comment( lib, "psapi.lib" )
int main(void)
{
MODULEINFO minfo = {0};
GetModuleInformation( GetCurrentProcess(), GetModuleHandle( "psapi.dll" ), &minfo, sizeof(minfo) );
/* printf("%X", minfo.lpBaseOfDll); /* The load address of the module */
return 0;
}
The code has been tested on Windows 7 and XP .
The output from linking session is :
program.c
/out:program.exe
psapi.lib
/LIBPATH:C:\MyLibFolder\
/SUBSYSTEM:CONSOLE
/VERBOSE
program.obj
Starting pass 1
Processed /DEFAULTLIB:uuid.lib
Processed /DEFAULTLIB:LIBCMT
Processed /DEFAULTLIB:OLDNAMES
Searching libraries
Searching C:\MyLibFolder\psapi.lib:
Found _GetModuleInformation#16
Referenced in program.obj
Loaded psapi.lib(PSAPI.DLL)
Found __IMPORT_DESCRIPTOR_PSAPI
Referenced in psapi.lib(PSAPI.DLL)
Loaded psapi.lib(PSAPI.DLL)
Found __NULL_IMPORT_DESCRIPTOR
Referenced in psapi.lib(PSAPI.DLL)
Loaded psapi.lib(PSAPI.DLL)
...
If vsvars32.bat and all appropriate environment variables in your Visual Studio are set correctly the above linker options will produce a valid executable(.exe) file.

GetUserName under Win64

I am trying to compile a C program using the Intel icl compiler under MINGW/64. The program uses the following code:
#include <Userenv.h>
HANDLE process;
HANLDE token;
GetUserProfileDirectory(process, TOKEN_QUERY, &ptoken)
I am using the following compile command:
$ icl -g -DMINGW32 -DTESTMAIN user.c -o user -UserEnv.Lib
and I am linking against the UserEnv.Lib from the Microsoft SDK.
Intel(R) C++ Intel(R) 64 Compiler XE for applications running on Intel(R) 64, Version Microsoft (R) Incremental Linker Version 9.00.21022.08
-out:user.exe
user.obj
user.obj : error LNK2019: unresolved external symbol __imp_GetUserProfileDirectoryA referenced in function main
Any idea how to solve this problem?
SOLUTION:
The solution is to use
/link /c/Program\ Files/Microsoft\ SDKs/Windows/v6.0A/Lib/x64/UserEnv.Lib /c/Program\ Files/Microsoft\ SDKs/Windows/v6.0A/Lib/x64/A
I copied the file UserEnv.lib from the Microsoft SDK (x64, 6.0) into the current working directory and compiled the program with
$ icl test.c -DMINGW32 ./UserEnv.Lib
LNK2019: unresolved external symbol __imp_GetUserNameA referenced in function main test.obj : error LNK2019: unresolved external symbol __imp_OpenProcessToken referenced in function main test.obj : error LNK2019: unresolved external symbol –
and I am still getting the unresolved symbols.
Olaf
You need to add userenv.lib to your input libraries for the linker to see GetUserProfileDirectory().
EDIT: It's been a while since I've touched an Intel compiler, but IIRC you're supposed to use /link to introduce linker options:
$ icl test.c -DMINGW32 /link ./UserEnv.Lib

Resources