You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

异常原因

  1. 64位内存写入越界:%%printInt中的mov [rcx], rbx是64位写入操作(rbx为64位寄存器),但digit仅分配了2字节(resw 1),一次性写入8字节会覆盖后续内存区域,破坏数据上下文。
  2. 内存空间不足:digit仅2字节,无法容纳多位数(如240需要3位数字+换行共4字节),后续storeLoop的写入会持续越界,残留数据干扰下一次打印。
  3. 未保存调用者寄存器:宏直接修改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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 07:13:09