您在使用 alink 时遇到的主要问题是它没有任何 64 位支持,这就是为什么您必须使用它nasm -fwin32
来生成 32 位目标代码的原因。第二个问题是您没有指定入口点。令人沮丧,不是吗?我自己在不同的链接器上浪费了很多时间。
如果你想用 nasm 做 win64 汇编,我建议使用golink。它采用轻便、快速、严肃的方法进行链接。如果您想在代码中使用 DLL 中的函数,则不需要任何库文件——GoLink 可以仅使用 DLL 文件本身完成所有链接。它甚至会将它们从系统路径中拉出,因此您无需将任何内容放在与源代码相同的文件夹中。
您遇到的下一个主要问题是您的示例代码不适合 Windows。这是您可以开始使用的一个,当您运行它时不会崩溃:
; example64.s
; nasm -fwin64 example64.s
; golink /console example64.obj kernel32.dll msvcrt.dll
bits 64
default rel
extern GetStdHandle
extern WriteFile
extern ExitProcess
extern printf
section .data
message db 'Hello, World!',10,0
msglen equ $-message
written dq 1
section .text
global Start ; GoLink will use Start as the default entry point
Start:
; Use the C library to print our message
mov rcx, message
call printf
; Now try using the Windows API
mov rcx, -11
call GetStdHandle
; Use WriteFile to print our message again.
; Notice the calling convention for 64-bit Windows uses
; rcx, rdx, r8, and r9 for the first 4 non-floating point arguments
; and then the rest are pushed onto the stack.
mov rcx, rax ; HANDLE hFile
mov rdx, message ; LPCVOID lpBuffer
mov r8, msglen ; DWORD nNumberOfBytesToWrite
mov r9, written ; LPDWORD lpNumberOfBytesWritten
push qword 0 ; LPOVERLAPPED lpOverlapped
call WriteFile
mov rcx, 0
call ExitProcess
假设它保存为 example64.s,您可以像这样组装和链接它:
nasm -fwin64 example64.s
golink /console example64.obj kernel32.dll msvcrt.dll
请注意,我们包含 kernel32.dll 的原因是用于 Windows API 调用(WriteFile、ExitProcess、GetStdHandle)。同样,msvcrt.dll 用于标准 C 库函数(即 printf、malloc 等)。如果您想真正了解 Win64 程序集,您可能希望继续使用 Windows API,而忽略 msvcrt.dll。您可以在 MSDN 上找到所有 Windows API 函数和数据结构的文档。
最后,值得注意的是,他们在 MSDN 上提供的许多函数原型和结构都是针对 32 位 Windows API 的,因此每当您看到 DWORD 时,您可能会想要使用 QWORD 代替。
无论如何,我希望这能让你朝着你想去的方向开始。祝你好运!