问题!
我已经开始学习汇编语言,在编译程序时遇到了一些困难.
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
我已经成功地使用以下命令将我的程序集文件编译为目标文件。
ml64 /c main.asm
当我尝试使用以下命令编译结果main.obj
时,出现了问题。
link main.obj /subsystem:console /entry:main /out:main.exe
printf符号丢失。所以我做了一些研究,发现我需要链接kernel32.lib
,legacy_stdio_definitions.lib
和msvcrt.lib
才能让这个工作。所以我也链接了这些文件,但随后得到了以下错误。
LINK : fatal error LNK1104: cannot open file 'legacy_stdio_wide_specifiers.lib'
所以我也包含了这个文件,并运行了以下命令。
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"
现在我得到了以下错误,我目前的理论是,我需要链接更多的文件,但不能找出哪些。
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
在这一点上,我放弃了link.exe
,并使用gcc
来编译我的代码,它成功编译!
gcc main.obj -o main.exe
我的问题
- 如何使用
link.exe
链接目标文件。
1.为了找出解决方案,我遇到了以下编译器和链接器,其中一些我有点熟悉,其中一些对我来说是新发现。
ml64
link
gcc
ld
cl
其中一些是微软的编译器和链接器,一些是gnu编译器和链接器。这些编译器和链接器之间有什么区别?我应该在什么时候使用哪些?(如果需要,我使用Windows AMD机器)
1.我在这里提供的汇编代码是我从一本书中复制的,但做了一些修改。在那本书中,作者链接了一个汇编编译的.obj
文件和一个C
编译的.obj
文件,并调用了assembly
中定义的C
中的函数来在控制台中编写Hello, World!
。我在这里做了一些修改,使其成为一个独立的assembly
程序,但仍然不理解该程序,例如,sub
和add
指令的用途是什么。因此,对该计划的简要说明将不胜感激。
1.我注意到在link
中有一个entry
标志。我现在的假设是,它指定了程序/指令开始的位置。因此,如果我将汇编代码中的所有main
关键字替换为start
,并使用/entry:start
作为其中一个标志,程序是否会编译并按预期工作?(假设我首先设法使用link
编译了程序)
1条答案
按热度按时间js4nwp541#
printf
/wprintf
-这是CRT的一部分-为了使用它-需要做一些额外的步骤。这里可以有3个解决方案:1.完全不使用
printf
/wprintf
和CRT。只使用win32 API使用WriteConsoleW
。ASM代码可以是编译它:
并构建:
注意这里只使用了2个库-- kernel32.Lib和ucrt.lib(对于
_getch
)。最终的exe大小接近2.5Kb调用ExitProcess
是强制性的-否则您的exe根本不会终止或在30秒后终止。exe入口点可以具有任何名称。2.
如果我们想使用CRT -它必须被初始化。在这种情况下,exe入口点必须是
[w]mainCRTStartup
,或者代码必须具有proc[w]main
。它将从[w]mainCRTStartup
调用asm码
注意,这里我们不能调用
ExitProcess
-我们返回到CRT代码,它自己调用它。我们现在需要设置的链接和库列表:
源代码变得越来越简单,与第一个变体相比,但二进制exe的大小不超过9 Kb(与第一个变体相比为2.5Kb)
3.部分使用CRT(最复杂的变体)。使用
wprintf
等CRT函数,但可自行初始化CRT这里发生了什么变化?首先,我们再次将入口点设置为self code:
我们再次需要直接调用
ExitProcess
。库列表变小了我们可以删除
vcruntime.lib
和msvcrt.lib
-它们在这里未使用需要为链接器添加选项
问题-此选项的用途以及对
_initterm
、.CRT$XIA
、.CRT$XIZ
等的调用?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(通常此文件位于 *
\Community\VC\Tools\MSVC\<version>\crt\src\vcruntime\initializers.cpp
*)fragment fom it:当链接器查看
.CRT*
部分时,它总是生成警告:当我们像往常一样使用CRT时-事实上包含了initializers.cpp(通过ob/lib),并且
#pragma comment(linker, "/merge:.CRT=.rdata")
删除了.CRT
部分。如果我们不使用CRT -需要自己做。不仅合并节,而且调用所有函数指针-通过调用_initterm
如果使用
/map
选项,则可以查看符号__PLEASE_LINK_WITH_legacy_stdio_wide_specifiers.lib
(是的,就是这个名字)。它来自legacy_stdio_wide_specifiers.lib
,位于.CRT$XIC
截面。所以这是函数指针,需要调用它。如果你感兴趣的是这个符号是如何生成的,以及哪个代码将被调用,请查找\Community\VC\Tools\MSVC\<version>\crt\src\linkopts\legacy_stdio_wide_specifiers.cpp
它片段:
3种情况下的exe最终大小将接近3.5Kb