汇编实现加减运算并输出:为何仅打印加法结果而非减法?
问题原因与解决方案
核心原因:违反Windows x86-64 ABI的栈调用规范
Windows x86-64平台要求调用外部函数(如printf)时必须满足两个硬性条件:- 调用前栈必须保持16字节对齐;
- 必须为被调用函数分配32字节的影子空间(Shadow Space),供函数临时使用,无论参数是否通过前四个寄存器传递。
你的
display_result函数完全没有处理这两点:- 进入
display_result时,call指令压入了8字节返回地址,栈处于8字节不对齐状态; - 调用
printf前未分配影子空间,导致printf执行时直接覆盖栈中的关键数据(比如返回地址)。
执行流程异常分析
第一次调用display_result时,栈状态相对干净,printf侥幸执行完成,ret指令正确回到main的减法代码段;但此时栈已被printf破坏。第二次调用display_result后,printf进一步破坏栈中的返回地址,导致ret指令无法回到main的后续流程,而是跳转到错误地址(比如直接触发程序终止),因此减法运算的结果要么没机会执行printf,要么输出后程序立即崩溃,无法看到输出。修复后的代码
修改display_result函数补充栈对齐和影子空间处理,同时调整代码结构避免返回地址异常:section .data num1 dq 5 ; 第一个数字(64位整数) num2 dq 2 ; 第二个数字(64位整数) mathResult db 'Mat result is %d', 0ah, 0 section .text global main ; 定义主函数(入口点) extern printf ; 链接MSVCRT中的printf extern ExitProcess ; 链接Kernel32中的ExitProcess main: sub rsp, 40 ; 对齐栈+分配影子空间(Windows ABI要求) ; 加法运算 mov rax, [num1] add rax, [num2] call display_result ; 减法运算 mov rax, [num1] sub rax, [num2] call display_result jmp exit_program ; 显式跳转到退出逻辑,避免返回地址异常 display_result: sub rsp, 40 ; 8字节对齐栈 + 32字节影子空间 mov rcx, mathResult ; 第一个参数:格式字符串 mov rdx, rax ; 第二个参数:运算结果 call printf add rsp, 40 ; 恢复栈 ret exit_program: xor ecx, ecx ; 设置退出码为0(ECX = 0) call ExitProcess ; 调用ExitProcess终止程序关键修改点:
- 在
display_result中调用printf前,通过sub rsp, 40完成栈对齐并分配影子空间,调用后用add rsp, 40恢复栈; - 在
main的两次display_result调用后,添加jmp exit_program显式跳转到退出逻辑,避免因返回地址异常导致的流程错误。
- 在
内容的提问来源于stack exchange,提问作者Josef
相关产品推荐
相关产品推荐

