使用NASM进行Windows x64汇编编程时未解析的外部符号printf

使用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

我最近一直在学习组装,遇到了这个问题。作者使用NASM和MicrosoftLinker来设置汇编环境。我按照同样的步骤安装了NASM。然后我开始编译hello world应用程序。编译成功,但我在链接阶段出错。错误如下:

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才这样做。