winapi - 在汇编程序中链接到 Kernel32.lib

标签 winapi assembly nasm

我今天开始学习汇编,并在 linux 上运行了很多测试,效果非常好!我搬到了我的电脑上,开始尝试在这里写一些东西。我在尝试调用外部函数(再次在 Linux 上运行良好)时遇到问题,我会收到 LINK 2001 Unresolved External 错误,告诉我在使用 nasm 编译后未定义 WriteConsoleA:

nasm -f win32 test.asm -o test.obj

和 cl.exe:

cl test.obj /link libcmt.lib kernel32.lib

我收到这些错误:

test.obj : error LNK2001: unresolved external symbol ExitProcess
test.obj : error LNK2001: unresolved external symbol GetStdHandle
test.obj : error LNK2001: unresolved external symbol WriteConsoleA
test.exe : fatal error LNK1120: 3 unresolved externals

程序集:

extern ExitProcess, GetStdHandle, WriteConsoleA
NULL equ 0
STD_OUTPUT_HANDLE equ -11
section .data
   msg db "Hello world!",0xa
msgLen equ $-msg
section .bss
    dummy resd 1
section .text
    global _main
_main:
    push STD_OUTPUT_HANDLE
    call GetStdHandle
    push NULL
    push dummy
    push msgLen
    push msg
    push eax
    call WriteConsoleA
    push NULL
    call ExitProcess

几乎完全复制自 here . 任何帮助深表感谢!谢谢!

最佳答案

首先,cl 不是链接器而是编译器。为什么不像我在您链接到的帖子中显示的那样使用 GoLink?它更容易使用。您可以使用 ld 作为链接器,但您的 externs 会稍微改变。

Windows API 函数使用函数名装饰 - 一个下划线 + FunctionName + @sizeof 参数,这是一个链接器的东西。

因此,ExitProcess 实际上导出为 _ExitProcess@4,因为它需要 1 个 DWORD 参数。 WriteConsoleA 采用 DWORD 大小的 5 个参数,因此它将是 _WriteConsole@20

将您的代码更改为:

extern _ExitProcess@4, _GetStdHandle@4, _WriteConsoleA@20

%define ExitProcess _ExitProcess@4
%define GetStdHandle _GetStdHandle@4
%define WriteConsoleA _WriteConsoleA@20

NULL equ 0
STD_OUTPUT_HANDLE equ -11
section .data
   msg db "Hello world!",0xa   
msgLen equ $-msg

section .bss
    dummy resd 1

section .text
    global _main
_main:
    push STD_OUTPUT_HANDLE
    call GetStdHandle

    push NULL
    push dummy
    push msgLen
    push msg
    push eax
    call WriteConsoleA

    push NULL
    call ExitProcess

要与 ld 链接,告诉它 lib 目录在哪里,一个不错的选择是: -L "C:\Program Files\Microsoft SDKs\Windows\v6.0\Lib"

然后只需在库中使用 -l 标志 -l kernel32

我的 makefile 使用 NASM 和 ld 作为您的示例代码:

APP= Sample

all: $(APP) clean

$(APP): $(APP).obj
    "C:\MinGW\bin\ld" $(APP).obj -o $(APP).exe -L "C:\Program Files\Microsoft SDKs\Windows\v6.0\Lib" -l kernel32

$(APP).obj: $(APP).asm
    nasm -f win32 $(APP).asm -o $(APP).obj

clean:
    rm $(APP).obj

如果您要像在另一篇文章中那样使用 GoLink,您可以只使用文档中显示的 API 函数名称。

关于winapi - 在汇编程序中链接到 Kernel32.lib,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20063224/

相关文章:

c - 如何过滤 wchar_t 数组?

c - 使用 GCC 内联汇编的 PC 相关调用

assembly - 0和双字0有什么区别?

macos - 非法指令 : 4 (Mac 64-bit, NASM)

c# - 我们什么时候需要将 ProcessStartInfo.UseShellExecute 设置为 True?

c++ - 是否有 WinZip 的环境变量或等效变量?

assembly - BIOS 连续两次从不同端口读取同一寄存器

ios - 如何将 Xcode 4.2 的 iOS 反汇编从 Thumb 切换到 ARM?

arrays - 将值插入数组并显示,nasm

c++ - 使用 WinDbg 的变量值