windows - 使用 NASM 进行 Windows x64 汇编编程中未解析的外部符号 printf
问题描述
我最近一直在尝试学习汇编,并遇到了这篇文章。作者使用 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) 的输出。我按照帖子中的描述从开发人员命令提示符运行链接命令,并且因为 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
在 windows 命令提示符下编译程序。
nasm -f win64 -o hello_world.obj hello_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:\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
并链接到一个可执行文件。
link hello_world.obj /subsystem:console /entry:main /out:hello_world_basic.exe "KERNEL32.LIB"
问题是什么?有什么我错过的吗?
解决方案
根据链接,Microsoft 已将一些标准 C 内容移至@Jester 共享的另一个库中。
所有 printf 和 scanf 函数的定义都已内联移动到 <stdio.h>、<conio.h> 和其他 CRT 头文件中。对于在本地声明这些函数但未包含适当 CRT 标头的任何程序,此重大更改会导致链接器错误(LNK2019,未解析的外部符号)。如果可能,您应该更新代码以包含 CRT 标头(即添加#include <stdio.h>) 和内联函数,但如果您不想修改代码以包含这些头文件,另一种解决方案是在链接器输入中添加一个附加库 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
推荐阅读
- c++ - 在 C++ 继承中,父创建者可以不在子创建者的开头启动吗?
- javascript - 返回相反字母的函数
- r - R:将缺少分隔符的不均匀长度字符串拆分为两个列:单独的字符和数字
- android - 使用 CASE 的 SQLITE 条件排序
- pyspark - 如何在 pyspark 数据帧的每个分区上执行 pivot() 和 write.parquet?
- ios - 如何从父视图读取子视图的 State 属性并在子视图中的属性更改时更新父视图 - SwiftUI
- xml - 仅在 FileMaker 18 中从/到当前记录导出和导入日期
- angular - 我有每个项目都有 mat-spinner-button 的项目列表 我需要在项目上显示加载微调器 onClick 怎么做?
- sql-server - SQL Server 和空分区扫描
- webpack - 无法在 Vue 中加载 Emscripten 编译的 C++