assembly 在Windows x64中使用NASM进行汇编编程时无法解析外部符号printf

up9lanfz  于 2022-11-13  发布在  Windows
关注(0)|答案(2)|浏览(336)

我最近一直在学习汇编,看到了这个帖子,作者用NASM和微软linker搭建了汇编工作环境,我按照同样的步骤安装了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)的输出。我按照帖子中的描述从开发人员命令提示符运行链接命令,因为hello world是一个64位应用程序,所以我正确地设置了LIB环境变量(尽管帖子中没有提到)。
下面是用作**“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"
i86rm4rw

i86rm4rw1#

在阅读了this discussion中Darran Rowe的答案后,设法解决了这个问题。他还解释了更多为什么需要做这些事情。
以下是解决方案:
x64 Native Tools Command Prompt for VS 20XX中运行link命令,您可以从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
z9zf31ra

z9zf31ra2#

显示链接Microsoft has moved some standard C stuff into another library@Jester已共享。
所有printf和scanf函式的定义都已经内嵌到<stdio.h>、<conio.h>和其他CRT信头中。这项重大变更会导致在本机宣告这些函式但未包含适当CRT信头的任何程式发生连接器错误(LNK 2019,无法解析的外部符号)。如果可能,您应该更新程式码,以包含CRT信头(也就是加入#include<stdio.h>)和内嵌函式。但是如果您不想修改代码以包含这些头文件,另一种解决方案是向链接器输入中添加一个额外的库legacy_stdio_definitions. lib。
printf的实现需要链接库legacy_stdio_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

相关问题