使用NASM进行Windows x64汇编编程时未解析的外部符号printf
我最近一直在学习组装,遇到了这个问题。作者使用NASM和MicrosoftLinker来设置汇编环境。我按照同样的步骤安装了NASM。然后我开始编译hello world应用程序。编译成功,但我在链接阶段出错。错误如下:使用NASM进行Windows x64汇编编程时未解析的外部符号printf,windows,assembly,x86-64,nasm,linker-errors,Windows,Assembly,X86 64,Nasm,Linker Errors,我最近一直在学习组装,遇到了这个问题。作者使用NASM和MicrosoftLinker来设置汇编环境。我按照同样的步骤安装了NASM。然后我开始编译hello world应用程序。编译成功,但我在链接阶段出错。错误如下: hello_world.obj : error LNK2001: unresolved external symbol printf hello_world_basic.exe : fatal error LNK1120: 1 unresolved external 这是mi
hello_world.obj : error LNK2001: unresolved external symbol printf
hello_world_basic.exe : fatal error LNK1120: 1 unresolved external
这是microsoft链接器(link.exe)的输出。我从开发者命令提示符运行link命令,如本文所述,因为helloworld是一个64位的应用程序,所以我正确地设置了LIB环境变量(尽管本文中没有提到)
你好
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
在windows命令提示符下编译程序
nasm-f win64-o hello\u world.obj hello\u world.asm
设置LIB环境变量
set LIB=LIB=C:\Program Files(x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.27.29110\ATLMFC\LIB\x86;C:\ProgramFiles(x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.27.29110\lib\x64;C:\ProgramFiles(x86)\Windows Kits\NETFXSDK\4.8\lib\um\x86;C:\ProgramFiles(x86)\Windows Kits\10\lib\10.0.19041.0\ucrt\x64;C:\ProgramFiles(x86)\Windows Kits\10\lib\10.0.19041.0\um\x64
并链接到可执行文件
link hello\u world.obj/subsystem:console/entry:main/out:hello\u world\u basic.exe“KERNEL32.LIB”
有什么问题?有什么我遗漏的吗?根据@Jester共享的链接
所有printf和scanf函数的定义都已内联移动到、和其他CRT标题中。对于在本地声明这些函数而不包含相应CRT头的任何程序,此中断性更改将导致链接器错误(LNK2019,未解析的外部符号)。如果可能,应更新代码以包含CRT头(即添加#包含)和内联函数,但如果您不想修改代码以包含这些头文件,另一种解决方案是在链接器输入中添加一个附加库legacy_stdio_definitions.lib
因此,为了实现printf
,您需要链接legacy\u stdio\u definitions.lib
,还需要初始化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
在年读了Darran Rowe的答案后设法解决了这个问题。他还进一步解释了为什么需要做这些事情 以下是解决方案: 在VS 20XX的
x64本机工具命令提示符中运行link命令,您可以从Visual Studio 20XX下的“开始”菜单启动该命令(Developer命令提示符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\u stdio\u definitions.lib msvcrt.lib
,即legacy\u stdio\u definitions.lib
。确保你正确地链接了它,你可能还需要预先准备一个前导underscore@Jester我在printf中添加了前缀u,但没有解决问题。我还将命令行参数更改为link hello\u world.obj/subsystem:console/entry:main/out:hello\u world\u basic.exe“KERNEL32.LIB”“UCRT.LIB”“legacy\u stdio\u definitions.LIB”
@Jester谢谢。我解决了这个问题。IIRC,64位Windows没有前置C符号名,只有32位Windows才这样做。