The issue!
I have started learning assembly language and am facing some difficulty compiling my program.
option casemap:none
.data
fmtStr byte 'Hello, world!', 10, 0
.code
externdef printf:proc
main proc
sub rsp, 56
lea rcx, fmtStr
call printf
add rsp, 56
ret
main endp
end
I have successfully compiled my assembly file to object file using the following command.
ml64 /c main.asm
The problem arises when I try to compile the resulting main.obj using the following command.
link main.obj /subsystem:console /entry:main /out:main.exe
The printf symbol was missing. So
I did some research and found that I need to link kernel32.lib, legacy_stdio_definitions.lib and msvcrt.lib to get this to work. So I linked those files as well but then got the following error.
LINK : fatal error LNK1104: cannot open file 'legacy_stdio_wide_specifiers.lib'
So I included that file as well and ran the following command.
link main.obj /subsystem:console /entry:main /out:main.exe "C:\Program Files (x86)\Windows Kits\10\Lib\10.0.19041.0\um\x64\kernel32.Lib" "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.29.30133\lib\x64\legacy_stdio_definitions.lib" "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.29.30133\lib\x64\legacy_stdio_wide_specifiers.lib" "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.29.30133\lib\x64\msvcrt.lib"
Now I am getting the following errors and my current theory is that I need to link more files but can't figure out which ones.
Microsoft (R) Incremental Linker Version 14.29.30148.0
Copyright (C) Microsoft Corporation. All rights reserved.
legacy_stdio_definitions.lib(legacy_stdio_definitions.obj) : error LNK2019: unresolved external symbol __acrt_iob_func referenced in function _vwprintf_l
legacy_stdio_definitions.lib(legacy_stdio_definitions.obj) : error LNK2019: unresolved external symbol __stdio_common_vfwprintf referenced in function _vfwprintf_l
legacy_stdio_definitions.lib(legacy_stdio_definitions.obj) : error LNK2019: unresolved external symbol __stdio_common_vfwprintf_s referenced in function _vfwprintf_s_l
legacy_stdio_definitions.lib(legacy_stdio_definitions.obj) : error LNK2019: unresolved external symbol __stdio_common_vfwprintf_p referenced in function _vfwprintf_p_l
legacy_stdio_definitions.lib(legacy_stdio_definitions.obj) : error LNK2019: unresolved external symbol __stdio_common_vfwscanf referenced in function _vfwscanf_l
legacy_stdio_definitions.lib(legacy_stdio_definitions.obj) : error LNK2019: unresolved external symbol __stdio_common_vswprintf referenced in function _vsnwprintf_l
legacy_stdio_definitions.lib(legacy_stdio_definitions.obj) : error LNK2019: unresolved external symbol __stdio_common_vswprintf_s referenced in function _vswprintf_s_l
legacy_stdio_definitions.lib(legacy_stdio_definitions.obj) : error LNK2019: unresolved external symbol __stdio_common_vsnwprintf_s referenced in function _vsnwprintf_s_l
legacy_stdio_definitions.lib(legacy_stdio_definitions.obj) : error LNK2019: unresolved external symbol __stdio_common_vswprintf_p referenced in function _vswprintf_p_l
legacy_stdio_definitions.lib(legacy_stdio_definitions.obj) : error LNK2019: unresolved external symbol __stdio_common_vswscanf referenced in function _vswscanf_l
legacy_stdio_definitions.lib(legacy_stdio_definitions.obj) : error LNK2019: unresolved external symbol __stdio_common_vfprintf referenced in function _vfprintf_l
legacy_stdio_definitions.lib(legacy_stdio_definitions.obj) : error LNK2019: unresolved external symbol __stdio_common_vfprintf_s referenced in function _vfprintf_s_l
legacy_stdio_definitions.lib(legacy_stdio_definitions.obj) : error LNK2019: unresolved external symbol __stdio_common_vfprintf_p referenced in function _vfprintf_p_l
legacy_stdio_definitions.lib(legacy_stdio_definitions.obj) : error LNK2019: unresolved external symbol __stdio_common_vfscanf referenced in function _vfscanf_l
legacy_stdio_definitions.lib(legacy_stdio_definitions.obj) : error LNK2019: unresolved external symbol __stdio_common_vsprintf referenced in function _vsnprintf_l
legacy_stdio_definitions.lib(legacy_stdio_definitions.obj) : error LNK2019: unresolved external symbol __stdio_common_vsprintf_s referenced in function _vsprintf_s_l
legacy_stdio_definitions.lib(legacy_stdio_definitions.obj) : error LNK2019: unresolved external symbol __stdio_common_vsnprintf_s referenced in function _vsnprintf_s_l
legacy_stdio_definitions.lib(legacy_stdio_definitions.obj) : error LNK2019: unresolved external symbol __stdio_common_vsprintf_p referenced in function _vsprintf_p_l
legacy_stdio_definitions.lib(legacy_stdio_definitions.obj) : error LNK2019: unresolved external symbol __stdio_common_vsscanf referenced in function _vsscanf_l
main.exe : fatal error LNK1120: 19 unresolved externals
At this point I ditched link.exe and use gcc to compile my code and it successfully compiled!
gcc main.obj -o main.exe
My questions
What can I do to link my object files using
link.exe.Trying to figure out a solution I came across the following compilers and linkers, some of them I was a little familiar with, and some of them were a new discovery to me.
ml64linkgccldcl
Some of them are microsoft compilers and linkers some are gnu compilers and linkers. What are the differences between these compilers and linkers and when should I use which ones? (I use a windows amd machine if that's needed)
The assembly code that I have provided here is the one that I copied from a book with some changes. In that book the author was linking an assembly compiled
.objfile and aCcompiled.objand was calling the function inCdefined inassemblyto writeHello, World!in the console. I made some changes here to make this a standaloneassemblyprogram but still don't understand the program properly, e.g., what is the use ofsubandaddinstructions. So a brief explanation of the program will be appreciated.I noticed that there is an
entryflag available to us inlink. My assumption for now is that is specifies where the program/instructions begin. So, if I replaced all themainkeywords in the assembly code with let's saystartand used/entry:startas one of the flags, will the program compile and work as intended? (assuming that I managed to compile the program usinglinkin the first place)
the
printf/wprintf- this is part of CRT - and for use it - need do some additional steps. here can be 3 solutions:1. not use
printf/wprintfand CRT at all. use only win32 api. useWriteConsoleW. the asm code can becompile it:
and build:
note that here used only 2 lib - kernel32.Lib and ucrt.lib (for
_getch). final exe size is near 2.5Kb callExitProcessis mandatory - otherwise your exe not terminate at all or terminate say after 30 seconds. the exe entry point can have anyname.2.
if we want use CRT - it must be initialized. the exe entry point must be
[w]mainCRTStartupin this case and or code must have proc[w]main. it will be called from[w]mainCRTStartupasm code
note that here we must not call
ExitProcess- we return to CRT code, which by self call it. for link we need now setand list of libs:
source code became less and more simply compare first variant, but binary exe not take 9Kb+ in size (compare 2.5Kb infirst variant)
3. partialy use CRT (most complex variant). use CRT functions like
wprintfbut initialize CRT by selfwhat here is changed ? at first we again set entry point to self code:
we again need direct call
ExitProcess. the list of libs became smallerwe can remove
vcruntime.libandmsvcrt.lib- they unused hereand need add option for linker
question - for what this option and for what call to
_initterm,.CRT$XIA,.CRT$XIZ, etc ?When Microsoft C/C++ compiler sees a global initializer, it generates a dynamic initializer and place function pointers to it in special sections. names of this section you can view in initializers.cpp (usually this file is located in
\Community\VC\Tools\MSVC\<version>\crt\src\vcruntime\initializers.cpp) fragment fom it:when linker view
.CRT*section it always generate warning:when we use CRT as usual - the initializers.cpp by fact is included (via ob/lib) and
#pragma comment(linker, "/merge:.CRT=.rdata")remove.CRTsection. if we not use CRT - need by self do this. not only merge sections, but call all function pointers - by call_inittermif we use
/mapoption we can view symbol__PLEASE_LINK_WITH_legacy_stdio_wide_specifiers.lib(yes, exactly with such name). it come fromlegacy_stdio_wide_specifiers.liband located in.CRT$XICsection. so this is function pointer and need call it. if interesting how this symbol is generated and which code will be called - look for\Community\VC\Tools\MSVC\<version>\crt\src\linkopts\legacy_stdio_wide_specifiers.cppit fragment:
final size of exe in 3 case will be near 3.5Kb