none
cannot link *.obj file produced from *.asm having beeen generated by MSVisual Studio 2017 C++ RRS feed

  • Question

  • Hello, everybody, I am a student and I tried to get *.asm code by compilation C++ project in MS Visual Studio 2017. ASM code was got OK. It also was compiled OK with ml.exe (MASM32). But I stuck on linking: there were multiple unresolved externals with very long and pretentious names like: "__imp____stdio_common_vfprintf", "__imp____stdio_common_vfscanf" and so on. My source C code is simple: it opens file, read it (vfscanf), and then writes (vprintf) to another file. It also uses new() and delete() functions (they are also unresolved!). How to fix this problem? I did not write even a letter in this asm source code - all was completely generated by MS VC++ 2017. So, why it cannot resolve it's own code? it is srange. Pls help...
    Sunday, March 18, 2018 11:47 AM

All replies

  • I suppose if you don't understand the tricks that the compiler does behind the scenes then it does seem strange. But if you run dumpbin /directives on the object file(s) generated by the C++ compiler, you will actually get this output:

       Linker Directives
       -----------------
       /FAILIFMISMATCH:_MSC_VER=1900
       /FAILIFMISMATCH:_ITERATOR_DEBUG_LEVEL=0
       /FAILIFMISMATCH:RuntimeLibrary=MD_DynamicRelease
       /DEFAULTLIB:msvcprt
       /FAILIFMISMATCH:_CRT_STDIO_ISO_WIDE_SPECIFIERS=0
       /DEFAULTLIB:MSVCRT
       /DEFAULTLIB:OLDNAMES

    So what does this mean? Well, these are commands for the linker, and the important ones are the /defaultlib ones. The compiler is telling the linker that it should automatically link against msvcrt (this will cause the linker to automatically link against msvcrt.lib, vcruntime.lib and ucrt.lib) and msvcprt (this will cause the linker to link against msvcprt.lib). So the compiler tells the linker to automatically link against several important libraries.

    If you do the same thing with an object created from ml.exe, you won't find any of this. The assembler doesn't do any of this default library stuff automatically. What you have to do is manually link against these default libraries.

    To do this you must add these libraries to the linker command line:

    link (options) <object file>.obj msvcrt.lib vcruntime.lib ucrt.lib msvcprt.lib <other libraries needed>

    This will resolve the names for stdio, and new/delete.


    This is a signature. Any samples given are not meant to have error checking or show best practices. They are meant to just illustrate a point. I may also give inefficient code or introduce some problems to discourage copy/paste coding. This is because the major point of my posts is to aid in the learning process.

    Sunday, March 18, 2018 1:06 PM
  • Thank you very much for your answer, but it did not help. All libraries were included to *.asm file (as includelib E:\masm32\lib\user32.lib ) and so on... (this is only an example - actually there are 20 lib files there) and also to *.bat file for link. and - no effect - see, what the link.exe responded:

    E:\masm32\bin>link.exe /LIBPATH:E:\masm32\lib fs.obj kernel32.lib user32.lib gdi
    32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib
     uuid.lib odbc32.lib odbccp32.lib
    Microsoft (R) Incremental Linker Version 5.12.8078
    Copyright (C) Microsoft Corp 1992-1998. All rights reserved.
    fs.obj : error LNK2001: unresolved external symbol "void * __cdecl operator new[
    ](unsigned int)" (??_U@YAPAXI@Z)
    fs.obj : error LNK2001: unresolved external symbol "void __cdecl operator delete
    [](void *)" (??_V@YAXPAX@Z)
    fs.obj : error LNK2001: unresolved external symbol __imp____acrt_iob_func
    fs.obj : error LNK2001: unresolved external symbol __imp____stdio_common_vfprint
    f
    fs.obj : error LNK2001: unresolved external symbol __imp____stdio_common_vfscanf

    fs.obj : error LNK2001: unresolved external symbol __RTC_CheckEsp
    fs.obj : error LNK2001: unresolved external symbol __fltused
    LINK : error LNK2001: unresolved external symbol _mainCRTStartup
    fs.exe : fatal error LNK1120: 8 unresolved externals

    E:\masm32\bin>pause
    Press any key to continue . . .

    == so, never happened after your advice applying.....(((((( ====

    Do you need me to show you my *.asm code, generated by C++ project (MS VS 2017)? It is rather long sized.

    Sunday, March 18, 2018 2:21 PM
  • Obviously not all require lib files were provided right?

    You said that you generated this assembly from Visual Studio 2017, why are you using the masm32 package and not the Visual Studio 2017 assembler for this?

    Visual Studio 2017 does come with the assembler (ml.exe, ml64.exe). The versions that it come with are much newer versions too. The versions of ml.exe and link.exe that come with Visual Studio 2017 are:

    C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.13.26128\bin\Hostx86\x86>ml
    Microsoft (R) Macro Assembler Version 14.13.26128.0
    Copyright (C) Microsoft Corporation.  All rights reserved.

    C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.13.26128\bin\Hostx86\x86>link.exe
    Microsoft (R) Incremental Linker Version 14.13.26128.0
    Copyright (C) Microsoft Corporation.  All rights reserved.

    So instead of trying to use the masm32 package, try to use the Visual Studio command line tools to see if this helps solve your issue. The environment would be set up correctly to link the right libraries after all.


    This is a signature. Any samples given are not meant to have error checking or show best practices. They are meant to just illustrate a point. I may also give inefficient code or introduce some problems to discourage copy/paste coding. This is because the major point of my posts is to aid in the learning process.

    • Edited by Darran Rowe Monday, March 19, 2018 12:25 AM
    • Proposed as answer by Baron Bi Wednesday, March 21, 2018 8:59 AM
    Monday, March 19, 2018 12:23 AM
  • Hi AAA BBB XXX YYY,

    Welcome to the MSDN forum.

    This forum is discussing Visual Studio WPF/SL Designer, Visual Studio Guidance Automation Toolkit, Developer Documentation and Help System, and Visual Studio Editor.

    According to your description, it related to C++ development, I will move this thread to corresponding forum for a professional answer.

    Thanks for your understanding.

    Regards,

    Judyzh


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Monday, March 19, 2018 8:38 AM
  • Where did you learn this?  Where is the public accessible documentation? I am having the same problems. I can write code in COBOL, FORTRAN, basic, c, c++, Java, Pascal, & Intel '86 Processor Assembly Source Code. I can compile in every one of these & more. But, I have the same problem. What does the Linker do & where is the Documentation?
    Sunday, September 22, 2019 9:25 PM
  • One big note before I start, these are details of the workings of Visual C++. These are obviously not how other compilers and linkers are meant to work.

    This is one of those cases where this isn't fully documented in how it is implemented, but you can put two and two together to figure out how things work.

    First of all, the whole /DEFAULTLIB can easily be implied from the linker's /DEFAULTLIB option. Using this with a library name tells the linker to treat that library as a default library to always search. So putting two and two together, you can see that maybe this is used as a linker parameter.

    This gets answerd when you look at the C++ compiler's preprocessor. The preprocessor has a #pragma directive, and one of the options for this is comment. This can be used to communicate some information between compilation phases. To tell the linker to do something, you can use #pragma comment(linker, <linker option>) to do something. As you can see from the link, /DEFAULTLIB is one of these options.

    If you compile:

    #pragma comment(linker, "/DEFAULTLIB:user32.lib")
    
    int wmain()
    {
    	return 0;
    }

    and check the directives:

    C:\Users\Darran\source\repos\meh\meh\x64\Debug>dumpbin /directives main.obj
    Microsoft (R) COFF/PE Dumper Version 14.23.28105.4
    Copyright (C) Microsoft Corporation.  All rights reserved.


    Dump of file main.obj

    File Type: COFF OBJECT

       Linker Directives
       -----------------
       /DEFAULTLIB:user32.lib
       /DEFAULTLIB:MSVCRTD
       /DEFAULTLIB:OLDNAMES
       /EDITANDCONTINUE
       /alternatename:__CheckForDebuggerJustMyCode=__JustMyCode_Default

    notice how the library that I named a default library is there? By the way, the /DIRECTIVES option is fully documented for dumpbin.

    So putting this together you can get the workings of the linker.

    The big thing is with /DEFAULTLIB:MSVCRT(D). When you run a C/C++ application, before it gets to the main function (main, wman, WinMain, wWinMain) it has to initialise things first. This means that the function that a C/C++ application starts off in isn't one of these. (Other languages have their own implementation details, but they are in a similar situation.)

    The Microsoft PE header (this is the executable format) has a field which tells Windows where to start running the application from, this is the entry point of the executable. The linker controls this, however it can be overridden with the /ENTRY linker option.

    If you read this then you will notice that it names 5 function names. mainCRTStartum, wmainCRTStartup and so on. These are the Microsoft provided entry point functions that do the initialisation for the application (this does things like initialises global variables and the like) and then calls the main function. This is where MSVCRT.lib comes in as important for the entry point. If you run:

    C:\Program Files (x86)\Microsoft Visual Studio\2019\Preview\VC\Tools\MSVC\14.23.28105\lib\x86>dumpbin /symbols msvcrt.lib | find "CRTStartup"
    084 00000000 SECT1F notype ()    External     | _wWinMainCRTStartup
    085 00000000 SECT1F notype ()    External     | _wmainCRTStartup
    084 00000000 SECT1F notype ()    External     | _WinMainCRTStartup
    085 00000000 SECT1F notype ()    External     | _mainCRTStartup
    04A 00000000 SECT14 notype ()    External     | __DllMainCRTStartup@12

    Notice how it lists the 5 function names that the linker's /ENTRY documentation listed (with the extra _ since this is the x86 version of the library.) As a note, I used the x86 version because there are extra symbols that clutter things up in the x64 library.

    Anyway, the linker has to get the startup code from somewhere, and MSVCRT.lib is where it gets it.

    But why does this expand to 3 libraries in Visual Studio 2017? Well technically it expands to 3 libraries from Visual Studio 2015 and newer. This was first announced back in 2014 in a blog post. The Visual C++ runtime first started off as a mix of three things, the C Runtime, the Visual C++ runtime and the Visual C++ startup code.

    The importance of this shouldn't be underestimated, this included the startup code, which was used to get the application running, the C Runtime, which contained functions like strcpy, and the Visual C++ runtime, which contained the exception handling code, operator new, operator delete and some other things. Because of issues, this went through several iterations.

    First this library was called MSVCRT.dll, you can still find this as a library in the Windows directory. But this was a bad idea due to DLL hell. From Visual Studio .NET onwards these were versioned (msvcr80.dll, msvcr90.dll as examples). However this still had issues. So Microsoft finally decided to split out MSVCRT into the individual components and have the CRT become part of Windows itself.

    There was an update in 2015 in the Introducing the Universal CRT blog post which updates the previous post stating that MSVCRT was split into three, the startup code which is still in the library named msvcrt.lib, the exception handling, operator new, operator delete and other things needed for the compiler's operation went into vcruntime.lib and finally the C Runtime went into the Universal C Runtime which you link to using ucrt.lib.

    However, if you compile an source file with nothing in it using Visual Studio 2015 and newer, you will get:

    C:\Users\Darran\source\repos\meh\meh\x64\Debug>dumpbin /directives main.obj
    Microsoft (R) COFF/PE Dumper Version 14.23.28105.4
    Copyright (C) Microsoft Corporation.  All rights reserved.


    Dump of file main.obj

    File Type: COFF OBJECT

       Linker Directives
       -----------------
       /DEFAULTLIB:MSVCRTD
       /DEFAULTLIB:OLDNAMES
       /EDITANDCONTINUE
       /alternatename:__CheckForDebuggerJustMyCode=__JustMyCode_Default

    But as you can see, there is no mention of vcruntime or ucrt. However, if you use functions that are now in the Universal CRT (using printf will do this):

    #include <cstdio>
    
    int wmain()
    {
    	wprintf(L"Hello World!\n");
    	return 0;
    }

    We see that not only does the default library not change:

    C:\Users\Darran\source\repos\meh\meh\x64\Debug>dumpbin /directives main.obj
    Microsoft (R) COFF/PE Dumper Version 14.23.28105.4
    Copyright (C) Microsoft Corporation.  All rights reserved.


    Dump of file main.obj

    File Type: COFF OBJECT

       Linker Directives
       -----------------
       /FAILIFMISMATCH:_CRT_STDIO_ISO_WIDE_SPECIFIERS=0
       /DEFAULTLIB:MSVCRTD
       /DEFAULTLIB:OLDNAMES
       /EDITANDCONTINUE
       /alternatename:__CheckForDebuggerJustMyCode=__JustMyCode_Default

    but it builds successfully too. If you then look at the build log that Visual Studio keeps for each of the projects, the linker reports that it uses vcruntime.lib and ucrt.lib. This means that the linker has to be using MSVCRT as a code for msvcrt.lib, vcruntime.lib and ucrt.lib.

    As a note, there was some interchange between names here, but names with a d on the end (MSVCRTD) are the debug versions of the names without the d. This means that the debug and non debug versions of these libraries can be substituted for each other. It is also true that the static versions of the runtime can be substituted for the dynamic version of the runtime. So in order to cut down things like MSVCRT, MSVCRTD, LIBCMT, LIBCMTD, then I just used MSVCRT even if copy/pasted things showed the d on the end.

    TL;DR: it's complicated and a lot of the time there is no direct documentation, only things that you put together yourself.


    This is a signature. Any samples given are not meant to have error checking or show best practices. They are meant to just illustrate a point. I may also give inefficient code or introduce some problems to discourage copy/paste coding. This is because the major point of my posts is to aid in the learning process.

    Monday, September 23, 2019 2:37 AM