最近一直在努力学习汇编,偶然发现了这个post。作者使用 NASM 和 Microsoft 链接器来设置汇编工作环境。我按照相同的步骤安装了 NASM。然后我开始编译 hello world 应用程序。编译成功,但是在链接阶段报错。报错如下:
hello_world.obj : error LNK2001: unresolved external symbol printf
hello_world_basic.exe : fatal error LNK1120: 1 unresolved external
以上是
Microsoft Linker
(link.exe)的输出。我按照帖子中的描述从 Developer Command Prompt 运行链接命令,因为 hello world 是一个 64 位应用程序,所以我正确设置了 LIB 环境变量(即使帖子中没有提到)。
这里是用作“Hello World”汇编程序的示例程序。
hello_world.asm:
bits 64
default rel
segment .data
msg db "Hello world!", 0xd, 0xa, 0
segment .text
global main
extern ExitProcess
extern printf
main:
push rbp
mov rbp, rsp
sub rsp, 32
lea rcx, [msg]
call printf
xor rax, rax
call ExitProcess
要重现问题,请分别执行命令。
1) 在 windows 命令提示符下编译程序。
nasm -f win64 -o hello_world.obj hello_world.asm
2)设置LIB环境变量。
set LIB=LIB=C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.27.29110\ATLMFC\lib\x86;C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.27.29110\lib\x64;C:\Program Files (x86)\Windows Kits\NETFXSDK\4.8\lib\um\x86;C:\Program Files (x86)\Windows Kits\10\lib\10.0.19041.0\ucrt\x64;C:\Program Files (x86)\Windows Kits\10\lib\10.0.19041.0\um\x64
3)并链接到可执行文件。
link hello_world.obj /subsystem:console /entry:main /out:hello_world_basic.exe "KERNEL32.LIB"
在阅读this discussion中Darran Rowe的回答后设法解决了这个问题。他还解释了为什么需要做这些事情。
这里是解决方案:
运行
x64 Native Tools Command Prompt for VS 20XX
中的链接命令,您可以从 Visual Studio 20XX 下的“开始”菜单启动(教程中建议的Developer Command Prompt for VS 20XX
不起作用)。
使用这个作为链接命令:
link hello_world.obj /subsystem:console /out:hello_world_basic.exe kernel32.lib legacy_stdio_definitions.lib msvcrt.lib
这里的变化是:
/entry:main
已被删除kernel32.lib legacy_stdio_definitions.lib msvcrt.lib
已添加根据链接Microsoft 已将一些标准的 C 内容移至另一个库@Jester 已共享。
所有 printf 和 scanf 函数的定义已内联移动到
、 和其他 CRT 标头中。对于在本地声明这些函数而不包括适当的 CRT 标头的任何程序,此重大更改会导致链接器错误(LNK2019,未解析的外部符号)。如果可能,您应该更新代码以包含 CRT 标头(即添加 #include ) 和内联函数,但如果您不想修改代码以包含这些头文件,另一种解决方案是向链接器输入添加一个额外的库,即 legacy_stdio_definitions.lib。
您需要链接库
legacy_stdio_definitions.lib
以实现printf
并且还需要初始化CRT。因此,将问题中的源码改成如下:
bits 64
default rel
segment .data
msg db "Hello world!", 0xd, 0xa, 0
segment .text
global main
extern ExitProcess
extern _CRT_INIT
extern printf
main:
push rbp
mov rbp, rsp
sub rsp, 32
call _CRT_INIT
lea rcx, [msg]
call printf
xor rax, rax
call ExitProcess
最后,按如下方式运行链接器。
link hello_world.obj /subsystem:console /entry:main /out:hello_world_basic.exe kernel32.lib legacy_stdio_definitions.lib msvcrt.lib
在上面的答案之一中它应该是(所以删除'LIB =')
set LIB=C:\Program Files (x86)\Microsoft Visual Studio�9\Community\VC\Tools\MSVC .27.29110\ATLMFC\lib\x86;C:\Program Files (x86)\Microsoft Visual Studio�9\ Community\VC\Tools\MSVC .27.29110\lib\x64;C:\Program Files (x86)\Windows Kits\NETFXSDK .8\lib\um\x86;C:\Program Files (x86)\Windows Kits \ lib .0.19041.0\ucrt\x64;C:\Program Files (x86)\Windows Kits \lib .0.19041.0\um\x64