Windows x64调用规范问题:汇编程序执行流程异常求助
x64汇编调用规范问题修复:WriteConsoleA返回异常解决
你的代码在x64 Windows调用约定的栈处理、参数传递上存在多处致命错误,导致程序执行流程被破坏。以下是问题分析和修正方案:
核心错误点
- 返回地址被非法覆盖:
ShowMessageConsole开头的POP指令完全错误。CALL ShowMessageConsole执行后,栈顶是返回地址(8字节),你用POP R10把返回地址弹到了R10,后续RET指令找不到正确的返回地址,必然导致程序崩溃。 - 未分配影子空间:根据x64 ABI,调用任何Win32 API前,调用者必须在栈上分配32字节的影子空间,供被调用者保存RCX/RDX/R8/R9寄存器。你的代码完全跳过了这一步。
- 栈未按要求对齐:x64要求调用函数前,RSP必须是16字节对齐(
CALL指令会压入8字节返回地址,调用后RSP自动对齐到16字节边界)。你在main中连续push四个值后直接call,此时RSP的对齐状态不符合规范。 - 参数传递错误:
WriteConsoleA的第四个参数是指向DWORD的指针(用于接收实际写入的字符数),你直接传入message_size的数值而非地址;第五个参数需要压栈,但你没有在正确的位置放置它。
修正后的代码
GetStdHandle PROTO ExitProcess PROTO WriteConsoleA PROTO .data message DB "Hello World",0 bytes_written DWORD ? ; 存储实际写入的字符数 .code ShowMessageConsole PROC ; 调用者已完成参数传递和影子空间分配,直接调用API CALL WriteConsoleA ; 清理栈上的第五个参数(8字节) ADD RSP, 8 RET ShowMessageConsole ENDP main PROC ; 获取标准输出句柄 MOV RCX, -11 ; STD_OUTPUT_HANDLE常量 CALL GetStdHandle ; 分配32字节影子空间 + 预留第五个参数的位置(共40字节) ; 确保调用ShowMessageConsole前RSP是16字节对齐 SUB RSP, 32 + 8 ; 设置WriteConsoleA的参数 MOV RCX, RAX ; 1. 控制台句柄 LEA RDX, message ; 2. 消息缓冲区地址 MOV R8, SIZEOF message - 1 ; 3. 要写入的字符数(去掉末尾的0) LEA R9, bytes_written ; 4. 接收实际写入数的指针 MOV QWORD PTR [RSP + 32], 0 ; 5. 保留参数(NULL),放在影子空间之后 CALL ShowMessageConsole ; 恢复栈指针到调用前的状态 ADD RSP, 32 + 8 ; 正常退出程序 MOV RCX, 0 CALL ExitProcess main ENDP END
x64调用规范关键要点
- 影子空间:调用者必须在栈上分配32字节连续空间,位于栈参数之前。无论被调用者是否使用,这部分空间都必须分配。
- 栈对齐:调用函数前,RSP必须是16字节对齐。
CALL指令压入8字节返回地址后,RSP会自动对齐到16字节边界。 - 参数传递:前4个参数依次存入RCX/RDX/R8/R9;第5个及以后的参数从右到左压入栈中。
- 栈清理:调用者负责清理栈上的所有参数(包括超过4个的栈参数和影子空间),通常通过
ADD RSP, 字节数恢复栈指针。
内容的提问来源于stack exchange,提问作者Homayoon
相关产品推荐
相关产品推荐

