簡體   English   中英

使用 NASM 進行 Windows x64 匯編編程中未解析的外部符號 printf

[英]Unresolved external symbol printf in Windows x64 Assembly Programming with NASM

我最近一直在嘗試學習匯編,並偶然發現了這篇文章 作者使用NASM和微軟鏈接器搭建匯編環境。 我按照相同的步驟安裝了 NASM。 然后我開始編譯 hello world 應用程序。 編譯成功,但是在鏈接階段出現錯誤。 錯誤如下:

hello_world.obj : error LNK2001: unresolved external symbol printf
hello_world_basic.exe : fatal error LNK1120: 1 unresolved external

這是微軟鏈接器(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

在閱讀了 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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM