x86-64汇编打印数组元素异常:输出值不符如何修复?
x86-64汇编打印数组元素异常:输出240、48、52而非预期值
原始代码
section .data numbers db 240, 40, 80, 90, 30, 40 section .bss digit resw 1 %macro printNumber 1 mov eax, %1 %%printInt: mov rcx, digit ;set rcx to digit memory address mov rbx, 10 ; moving a newline into rbx mov [rcx], rbx ; setting digit to rbx inc rcx ; increment rcx position by one byte %%storeLoop: xor rdx, rdx ; zero out rdx mov rbx, 10 div rbx ; rax / rbx (10) ; rdx holds the remainder of the divison add dl, 48 ; add 48 to rdx to make in ascii character mov [rcx], dl ; get the character part of rdx inc rcx ; increment digit position again cmp rax, 0 jnz %%storeLoop ; continue looping until rax is 0 %%printLoop: push rcx ;perform sys write mov rax, 1 mov rdi, 1 mov rsi, rcx mov rdx, 1 syscall pop rcx dec rcx cmp rcx, digit ; first byte of digit (10) jge %%printLoop %endmacro section .text global _start _start: mov esi,numbers ;movzx r8d, byte [esi] ;printNumber r8d ; -> mov eax, r8d ;movzx r8d, byte[esi+1] ;printNumber r8d ;movzx r8d, byte[esi+2] ;printNumber r8d
异常原因
- 64位内存写入越界:
%%printInt中的mov [rcx], rbx是64位写入操作(rbx为64位寄存器),但digit仅分配了2字节(resw 1),一次性写入8字节会覆盖后续内存区域,破坏数据上下文。 - 内存空间不足:
digit仅2字节,无法容纳多位数(如240需要3位数字+换行共4字节),后续storeLoop的写入会持续越界,残留数据干扰下一次打印。 - 未保存调用者寄存器:宏直接修改
rax、rbx、rcx、rdx等调用者保存寄存器,可能破坏调用者的程序逻辑。
修复方案及代码
section .data numbers db 240, 40, 80, 90, 30, 40 num_count equ $ - numbers ; 自动计算数组元素个数 section .bss digit resb 20 ; 分配20字节空间,足够容纳64位整数的所有数字+换行 %macro printNumber 1 ; 保存调用者保存的寄存器,避免破坏上下文 push rax push rbx push rcx push rdx mov eax, %1 %%printInt: mov rcx, digit mov byte [rcx], 10 ; 仅写入1字节换行符,避免64位越界 inc rcx %%storeLoop: xor rdx, rdx mov rbx, 10 div rbx add dl, 48 ; 转换为ASCII字符 mov [rcx], dl inc rcx cmp rax, 0 jnz %%storeLoop %%printLoop: push rcx ; 系统调用打印单个字符 mov rax, 1 mov rdi, 1 mov rsi, rcx mov rdx, 1 syscall pop rcx dec rcx cmp rcx, digit jge %%printLoop ; 恢复寄存器 pop rdx pop rcx pop rbx pop rax %endmacro section .text global _start _start: mov rsi, numbers mov rcx, num_count ; 循环计数器:数组元素个数 print_all_elements: movzx eax, byte [rsi] ; 读取字节并零扩展到eax printNumber eax inc rsi ; 移动到下一个元素 dec rcx jnz print_all_elements ; 循环打印所有元素 ; 正常退出程序 mov rax, 60 mov rdi, 0 syscall
修复说明
- 内存分配调整:
digit resb 20提供足够空间,避免越界写入。 - 写入宽度修正:
mov byte [rcx], 10改为1字节写入,彻底解决64位写入越界问题。 - 寄存器保护:宏开头/结尾添加
push/pop,保存并恢复调用者寄存器,避免上下文破坏。 - 自动循环打印:通过
num_count计算数组长度,实现自动遍历打印所有元素,无需手动逐个调用。 - 添加退出逻辑:程序结束时调用
exit系统调用,避免执行崩溃。
内容的提问来源于stack exchange,提问作者user25004318
相关产品推荐
相关产品推荐

