x64 Windows下NASM编写无C库依赖Hello World遇阻求助
可行的x64 Windows NASM无C库依赖Hello World实现方案
方案1:弹窗版(MessageBoxA)
以下代码直接调用Windows API,无任何C库依赖,可通过NASM编译+GoLink/MSVC Link链接:
; hello.asm bits 64 default rel ; 声明导入的API符号(通过导入表引用) extern __imp_MessageBoxA extern __imp_ExitProcess section .data title db 'Hello', 0 msg db 'Hello World!', 0 section .text ; 程序入口(x64 Windows默认入口名不是main,需显式指定) global Start Start: ; MessageBoxA(hWnd=NULL, lpText, lpCaption, uType=MB_OK) xor rcx, rcx ; 第1个参数:窗口句柄设为NULL lea rdx, [msg] ; 第2个参数:消息文本(RIP相对寻址) lea r8, [title] ; 第3个参数:弹窗标题 mov r9d, 0x00000000 ; 第4个参数:弹窗类型为MB_OK call [__imp_MessageBoxA] ; 间接调用导入的API ; ExitProcess(uExitCode=0) xor rcx, rcx ; 退出码设为0 call [__imp_ExitProcess]
编译链接命令
- 编译:
nasm -f win64 hello.asm -o hello.obj - GoLink链接:
golink /entry Start hello.obj user32.dll kernel32.dll - MSVC Link链接:
link hello.obj /subsystem:windows /entry:Start kernel32.lib user32.lib
方案2:控制台输出版(WriteConsoleA)
适合不需要弹窗的场景,仅依赖kernel32.dll:
; console_hello.asm bits 64 default rel extern __imp_GetStdHandle extern __imp_WriteConsoleA extern __imp_ExitProcess section .data msg db 'Hello World!', 0x0a, 0x0d ; 包含换行回车 msg_len equ $ - msg ; 计算消息长度 section .text global Start Start: ; 获取标准输出句柄(STD_OUTPUT_HANDLE = -11) mov rcx, -11 call [__imp_GetStdHandle] mov rbx, rax ; 保存句柄到RBX ; WriteConsoleA(hConsole, msg, len, NULL, NULL) mov rcx, rbx ; 第1个参数:控制台句柄 lea rdx, [msg] ; 第2个参数:输出文本 mov r8d, msg_len ; 第3个参数:文本长度 xor r9, r9 ; 第4个参数:接收实际输出长度的指针(设为NULL) push r9 ; 第5个参数:保留参数(x64调用约定中,前4个参数用寄存器,剩余压栈) call [__imp_WriteConsoleA] add rsp, 8 ; 清理栈空间 ; 退出程序 xor rcx, rcx call [__imp_ExitProcess]
编译链接命令
- 编译:
nasm -f win64 console_hello.asm -o console_hello.obj - GoLink链接:
golink /console /entry Start console_hello.obj kernel32.dll - GCC链接:
gcc console_hello.obj -o console_hello.exe -nostdlib -lkernel32 -e Start
你遇到的问题解决办法
1. 32位转64位无输出、语法错误不敏感
- 调用约定不兼容:x64 Windows使用fastcall调用约定,前4个参数必须用RCX/RDX/R8/R9传递,剩余参数压栈,和32位的stdcall/cdecl完全不同,直接修改寄存器会导致API调用参数错误,无输出。
- 目标格式错误:NASM编译时必须指定
-f win64,否则默认生成ELF64格式文件,Windows链接器无法正确处理,且NASM对ELF格式的语法校验逻辑更宽松,导致“对语法错误不敏感”。
2. MessageBoxA未定义错误
- 缺少依赖库:链接时必须显式指定
user32.dll(GoLink)或user32.lib(MSVC/GCC),否则链接器找不到MessageBoxA的导出符号。 - 符号名错误:x64下Windows API符号不需要加下划线,32位是
_MessageBoxA,64位直接是MessageBoxA,且必须通过导入表的__imp_MessageBoxA间接调用,不能直接call MessageBoxA。
3. 重定位截断错误
- 寻址方式错误:x64 Windows程序默认是地址无关代码(PIE),必须使用RIP相对寻址(
lea rdx, [msg]),不能用32位绝对寻址(mov rdx, msg),否则会因地址范围超出32位限制触发重定位错误。 - API调用方式错误:直接
call MessageBoxA会生成32位绝对地址引用,必须改为call [__imp_MessageBoxA]通过导入表间接调用,避免截断问题。
内容的提问来源于stack exchange,提问作者Codingwal
相关产品推荐
相关产品推荐

