x64汇编跳转指令异常:循环运行时长超出预期求助
Win64汇编循环异常:输出多余空值的问题排查与修复
问题根源分析
- 非易失性寄存器未保存:Win64调用约定中,
RBX属于非易失性寄存器,调用C标准库函数(如printf)前必须手动保存,否则函数会修改RBX的值,导致循环计数器错乱。你的代码直接用RBX作为循环计数器,调用printf后RBX被破坏,循环逻辑彻底失控。 - 字符串缺少终止符:
err字符串末尾未添加ASCII空字符(0),printf会持续读取内存直到遇到空字符,可能引发乱码或意外行为。 - 未遵守Win64调用约定的
RAX要求:调用printf这类可变参数函数时,需将RAX设为浮点参数的数量(此处无浮点参数,需置RAX=0),否则会导致寄存器或栈状态异常。 - 循环逻辑冗余混乱:循环内重复判断
rbx与r11的关系,跳转逻辑重复,进一步加剧了循环失控的问题。
修复后的代码
bits 64 default rel section .data fmt db "%s", 0xd, 0xa, 0 err db "Correct usage: echo <string>", 0 ; 补充字符串终止符 section .text extern printf extern ExitProcess global main main: ; 建立栈帧与阴影空间 push rbp mov rbp, rsp sub rsp, 32 ; 保存命令行参数 mov r11, rcx ; argc mov r12, rdx ; argv ; 检查参数数量是否合规 cmp r11, 2 jl .wrong_num_of_args_error ; 保存非易失性寄存器RBX(避免被printf修改) push rbx mov rbx, 1 ; 从argv[1]开始遍历(argv[0]为程序名) .loop: cmp rbx, r11 je .loop_end ; 准备printf参数并调用 mov rdx, [r12 + rbx * 8] mov rcx, fmt xor rax, rax ; 浮点参数数量为0,符合Win64约定 call printf inc rbx jmp .loop .loop_end: pop rbx ; 恢复RBX寄存器 .end: xor rax, rax call ExitProcess .wrong_num_of_args_error: ; 输出错误提示 mov rcx, err xor rax, rax call printf xor rax, rax call ExitProcess
关键修复点说明
- 保护非易失性寄存器:使用
RBX前执行push rbx保存其值,循环结束后pop rbx恢复,避免printf破坏计数器。 - 补全字符串终止符:给
err字符串末尾添加, 0,确保printf能正确识别字符串边界。 - 符合调用约定:每次调用
printf前清零RAX,满足Win64对可变参数函数的寄存器要求。 - 简化循环逻辑:移除重复的条件判断,统一用
jmp .loop实现循环,逻辑更清晰可控。
内容的提问来源于stack exchange,提问作者Angad Warhadpande
相关产品推荐
相关产品推荐

