0

edit: I finally was able to resolve all unresolved symbols - see my answer below. However the behavior of the MS tools remains mysterious and not like documented.

I have an ANT project, that uses the Visual Studio (C++) 2022 toolchain on Win 10 to build.
So there is no VS project - every setting is done via ANT.

I want an exe and a dll sharing the same CRT. So therefore I use the /MD compiler switch.

Currently I struggle with the dll.
Unfortunately, at the end I get many unresolved externals, i.e. _floor, _memset, _memcpy,
and also _terminate, which is referenced by LIBCMT.LIB (is this a hint already?).

With the /VERBOSE:LIB linker switch I analysed the libs that are used, which are the following:

    Searching C:\Program Files (x86)\Windows Kits\10\\lib\10.0.19041.0\\um\x86\kernel32.lib:
    Searching C:\Program Files (x86)\Windows Kits\10\\lib\10.0.19041.0\\um\x86\rpcns4.lib:
    Searching C:\Program Files (x86)\Windows Kits\10\\lib\10.0.19041.0\\um\x86\rpcrt4.lib:
    Searching C:\Program Files (x86)\Windows Kits\10\\lib\10.0.19041.0\\um\x86\oleaut32.lib:
    Searching C:\Program Files (x86)\Windows Kits\10\\lib\10.0.19041.0\\um\x86\uuid.lib:
    Searching C:\Program Files (x86)\Windows Kits\10\\lib\10.0.19041.0\\um\x86\user32.lib:
    Searching C:\Program Files (x86)\Windows Kits\10\\lib\10.0.19041.0\\um\x86\gdi32.lib:
    Searching C:\Program Files (x86)\Windows Kits\10\\lib\10.0.19041.0\\um\x86\winspool.lib:
    Searching C:\Program Files (x86)\Windows Kits\10\\lib\10.0.19041.0\\um\x86\comdlg32.lib:
    Searching C:\Program Files (x86)\Windows Kits\10\\lib\10.0.19041.0\\um\x86\advapi32.lib:
    Searching C:\Program Files (x86)\Windows Kits\10\\lib\10.0.19041.0\\um\x86\shell32.lib:
    Searching C:\Program Files (x86)\Windows Kits\10\\lib\10.0.19041.0\\um\x86\ole32.lib:
    Searching C:\Program Files (x86)\Windows Kits\10\\lib\10.0.19041.0\\um\x86\odbc32.lib:
    Searching C:\Program Files (x86)\Windows Kits\10\\lib\10.0.19041.0\\um\x86\odbccp32.lib:
    Searching C:\Program Files (x86)\Windows Kits\10\\lib\10.0.19041.0\\um\x86\Ws2_32.lib:
    Searching C:\Program Files (x86)\Windows Kits\10\\lib\10.0.19041.0\\um\x86\Psapi.lib:
    Searching C:\Program Files (x86)\Windows Kits\10\\lib\10.0.19041.0\\um\x86\IPHlpApi.Lib:
    Searching C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\14.32.31326\lib\x86\delayimp.lib:
    Searching C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\14.32.31326\lib\x86\LIBCMT.lib:
    Searching C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\14.32.31326\lib\x86\OLDNAMES.lib:
    Searching C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\14.32.31326\lib\x86\msvcprt.lib:
    Searching C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\14.32.31326\lib\x86\MSVCRT.lib:

msvcrt.lib seems to be the suitable one according to this MS doc. And it obviously was picked by the linker automatically.
However I don't understand under which circumstances the other mentioned libs should be picked: ucrt.lib and vcruntime.lib.

Using dumpbin /symbols "..." | find /i " _memset" I can see, that neither
C:\Program Files (x86)\Windows Kits\10\Lib\10.0.19041.0\ucrt\x86\ucrt.lib nor
C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\14.32.31326\lib\x86\vcruntime.lib contain it.
But I can find it in libvcruntime.lib:

> dumpbin /symbols "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\14.32.31326\lib\x86\libvcruntime.lib"  | find /i " _memset"
011 00000000 SECT6  notype ()    External     | _memset

But this should be the static one, so not suitable for me, right?

Any hint how to get the missing functions??

MattTT
  • 339
  • 3
  • 9

1 Answers1

0

At first, the LIBCMT.lib you see in my question resulted from an old object, that still was compiled with /MT. After I updated this object, the LIBCMT.lib disappeared from linker output.


vcruntime.lib indeed contained symbols like _memset, _memcpy.
And ucrt.lib contained symbols like __imp__calloc, _terminate & _floor.

The exported symbols contained in the libs could finally be viewed by dumpbin /linkermember:1.
(dumpbin /exports did not show e.g. __imp__calloc in ucrt.lib.)

Although msvcrt.lib was picked by the linker automatically, I had to specify vcruntime.lib & ucrt.lib manually. (Does anyone know why?)


After that I was left with the following 11 unresolved symbols:

msvcrt.lib(utility.obj) : error LNK2019: unresolved external symbol ___vcrt_initialize referenced in function ___scrt_initialize_crt
msvcrt.lib(utility.obj) : error LNK2019: unresolved external symbol ___vcrt_uninitialize referenced in function ___scrt_initialize_crt
msvcrt.lib(utility.obj) : error LNK2019: unresolved external symbol ___vcrt_uninitialize_critical referenced in function ___scrt_dllmain_uninitialize_critical
msvcrt.lib(utility.obj) : error LNK2019: unresolved external symbol ___vcrt_thread_attach referenced in function ___scrt_dllmain_crt_thread_attach
msvcrt.lib(utility.obj) : error LNK2019: unresolved external symbol ___vcrt_thread_detach referenced in function ___scrt_dllmain_crt_thread_attach
msvcrt.lib(utility.obj) : error LNK2019: unresolved external symbol __is_c_termination_complete referenced in function ___scrt_dllmain_uninitialize_c
msvcrt.lib(utility.obj) : error LNK2019: unresolved external symbol ___acrt_initialize referenced in function ___scrt_initialize_crt
msvcrt.lib(utility.obj) : error LNK2019: unresolved external symbol ___acrt_uninitialize referenced in function ___scrt_uninitialize_crt
msvcrt.lib(utility.obj) : error LNK2019: unresolved external symbol ___acrt_uninitialize_critical referenced in function ___scrt_dllmain_uninitialize_critical
msvcrt.lib(utility.obj) : error LNK2019: unresolved external symbol ___acrt_thread_attach referenced in function ___scrt_dllmain_crt_thread_attach
msvcrt.lib(utility.obj) : error LNK2019: unresolved external symbol ___acrt_thread_detach referenced in function ___scrt_dllmain_crt_thread_detach

This seems to be the same problem like in this SO question. It has no real good answer (currently), but a comment there refers to this MS community question. There the solution was to remove the /ENTRY:myEntryPoint.


Following this I end up with the unresolved external _DllMainCRTStartup.

I could not find this symbol in vcruntime.lib as the MS doc stated, however I found __DllMainCRTStartup@12 in msvcrt.lib.
vcruntime.lib was already used; and msvcrt.lib was also already used. The sticking point is:
msvcrt.lib contains the __stdcall variant of the function – what I need is the __cdecl variant.

So I decided to build a little bridge like this:

extern "C" BOOL __stdcall _DllMainCRTStartup(
    HINSTANCE hinstDLL, 
    DWORD fdwReason,    
    LPVOID lpvReserved );

extern "C" BOOL __cdecl DllMainCRTStartup(
    HINSTANCE hinstDLL,  // handle to DLL module
    DWORD fdwReason,     // reason for calling function
    LPVOID lpvReserved )  // reserved
{
      return _DllMainCRTStartup( hinstDLL,  
                                 fdwReason,     
                                 lpvReserved ); 
}

This linked without error, however I got a warning

warning LNK4086: entrypoint '_DllMainCRTStartup' is not __stdcall with 12 bytes of arguments; image may not run

which brought me to the solution to specify the msvcrt.lib function as entrypoint:

/ENTRY:__DllMainCRTStartup@12

I deleted my bridge and made an ordinary DllMain.


which finally linked fine.


So all that's left to do is to explain this unexpected behavior:

  1. Why does the linker choose _DllMainCRTStartup as default entrypoint, but does not comply with its calling convention?
    (Remember: The unresolved external _DllMainCRTStartup disappears when I simply specify the (already existing) function __DllMainCRTStartup@12 as entrypoint.)
  2. Why does the linker miss those 11 unresolved externals, while they are no problem when I simply specify another function (__DllMainCRTStartup@12) as entrypoint.
  3. Where do those 11 symbols reside, if I would indeed use my own entry function?
MattTT
  • 339
  • 3
  • 9