使用fasm编写64位Windows Hello World:宏代码无输出问题排查
Win64 FASM 宏版本HelloWorld无输出问题排查
你遇到的问题核心大概率是栈对齐破坏、字符串寻址错误或参数传递顺序不符Win64约定,结合你提到的rsp和message地址差异,具体分析如下:
1. 栈对齐问题(RSP操作差异)
Win64调用约定强制要求:调用API前栈必须保持16字节对齐,且需要预留32字节的shadow space(用于被调用方保存RCX/RDX/R8/R9寄存器)。
- 无宏版本你可能手动做了正确的栈调整(比如
sub rsp, 32),确保了对齐; - 但
win64ax.inc的invoke宏已经自动处理了shadow space和栈对齐,如果你额外手动修改了RSP(比如重复sub rsp, 8或sub rsp, 32),会直接破坏16字节对齐,导致API调用失败(MessageBox不会执行)。
排查方式:对比反汇编中调用MessageBox前的RSP值,宏版本若比无宏版本多了额外的栈偏移,删掉手动的RSP调整代码。
2. 字符串寻址错误(Message地址差异)
Win64 PE文件运行时采用动态基址,访问数据必须用RIP相对寻址(而非32位绝对地址)。
- 无宏版本你可能用了
lea rcx, [rel message]这种正确的RIP相对寻址; - 宏版本若生成了
mov rcx, message(绝对地址),运行时该地址会指向无效内存,MessageBox因接收错误的字符串参数(空或无效指针)而不显示。
排查方式:反汇编看宏版本传递字符串的指令,若不是lea rcx, [rip+xxxx],检查win64ax.inc的addr宏是否正确配置,或手动在字符串前加rel前缀(比如lea rcx, [rel msg_text])。
3. 参数传递顺序不符约定
Win64调用约定规定前4个参数依次放入RCX、RDX、R8、R9,对应MessageBoxA的参数顺序是:MessageBoxA(hWnd, lpText, lpCaption, uType)
- 若
invoke宏错误地颠倒了参数顺序(比如把字符串放到RCX位置,当成窗口句柄),MessageBox会因参数无效而不触发弹窗。
排查方式:对比无宏版本和宏版本的寄存器赋值,确认RCX(窗口句柄,通常为NULL)、RDX(消息文本)、R8(标题)、R9(弹窗类型)的内容是否对应。
正确的宏版本示例代码
format PE64 GUI 4.0 entry start include 'win64ax.inc' section '.text' code readable executable start: invoke MessageBoxA, NULL, msg_text, msg_title, MB_OK invoke ExitProcess, 0 section '.data' data readable writeable msg_title db 'Hello', 0 msg_text db 'Hello World!', 0 section '.idata' import data readable writeable library kernel32, 'kernel32.dll', user32, 'user32.dll' import kernel32, ExitProcess, 'ExitProcess' import user32, MessageBoxA, 'MessageBoxA'
- 注意:如果是控制台输出(比如用WriteConsole),需把
format PE64 GUI 4.0改成format PE64 CONSOLE,否则控制台窗口会一闪而过或无输出。
内容的提问来源于stack exchange,提问作者Thomas S.
相关产品推荐
相关产品推荐

