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

求助:修复x86架构NASM汇编程序的十六进制数输出问题

x86汇编实现32位十六进制数打印问题排查

需求:编写x86架构的NASM汇编程序,通过write系统调用在标准输出打印32位十六进制数,效果等价于C语言的printf("%x\n",123456)。自己编写的代码无法正常运行,附上代码求助,本人是汇编新手,缺乏调试思路。

原代码:

section .data
    message db '0x',0
    number dq 123456

section .text
    global _start

_start:
    ; Print "0x"
    mov eax, 4
    mov ebx, 1
    mov ecx, message
    mov edx, 2
    int 0x80

    ; Print number in hex
    mov eax, number
    push eax
    call print_hex
    add esp, 4

    ; Exit
    mov eax, 1
    xor ebx, ebx
    int 0x80

; Function to print number in hex
print_hex:
    push ebx
    push edx
    mov ebx, 16
    mov edx, 0
    mov ecx, 0

print_hex_loop:
    xor edx, edx
    div ebx
    add edx, '0'
    cmp edx, '9'
    jg print_hex_digit
    push edx
    inc ecx
    test eax, eax
    jne print_hex_loop

print_hex_done:
    mov eax, 4
    mov ebx, 1
    mov edx, ecx
    int 0x80

print_hex_pop_loop:
    pop edx
    mov [esp], edx
    inc esp
    dec ecx
    jne print_hex_pop_loop
    pop edx
    pop ebx
    ret

print_hex_digit:
    add edx, 'A' - '9' - 1
    jmp print_hex_done

代码中的关键错误

  1. 变量取值错误:number定义为dq(8字节),但mov eax, number取的是变量的内存地址而非数值,正确写法应为mov eax, [number]。另外因为需求是32位数,number用dd(4字节)更合适。
  2. 字母转换流程错误:当数字大于9需要转换为字母时,print_hex_digit直接跳转到print_hex_done,导致后续循环中断,转换后的字符没有入栈计数,直接进入输出逻辑,完全跳过了剩余数字的处理。
  3. 输出逻辑错误:print_hex_done中的write调用未设置ecx指向有效输出缓冲区(当前ecx是字符计数器),后续的print_hex_pop_loop直接操作esp修改栈内容,不仅破坏栈结构,还没有把字符正确传递给write系统调用。

修正后的代码

section .data
    prefix db '0x'
    hex_chars db '0123456789abcdef'  ; 小写十六进制字符集,要大写换ABCDEF
    newline db 0xa
    number dd 123456  ; 32位变量

section .bss
    hex_buf resb 8  ; 32位十六进制最多8位字符

section .text
    global _start

_start:
    ; 打印前缀"0x"
    mov eax, 4
    mov ebx, 1
    mov ecx, prefix
    mov edx, 2
    int 0x80

    ; 打印十六进制数
    mov eax, [number]
    call print_hex

    ; 打印换行
    mov eax, 4
    mov ebx, 1
    mov ecx, newline
    mov edx, 1
    int 0x80

    ; 退出程序
    mov eax, 1
    xor ebx, ebx
    int 0x80

; 功能:打印eax中的32位十六进制数
print_hex:
    push ebx
    push ecx
    push edx
    push esi

    mov esi, hex_buf + 7  ; 从缓冲区末尾开始填充(十六进制高位在左,低位在右)
    mov ecx, 8            ; 32位固定8位十六进制字符

print_hex_loop:
    xor edx, edx
    mov ebx, 16
    div ebx               ; eax = eax/16,edx = 余数
    mov bl, [hex_chars + edx]  ; 取对应字符
    mov [esi], bl
    dec esi
    dec ecx
    jnz print_hex_loop

    ; 输出缓冲区内容
    mov eax, 4
    mov ebx, 1
    mov ecx, hex_buf
    mov edx, 8
    int 0x80

    pop esi
    pop edx
    pop ecx
    pop ebx
    ret

修正说明

  • 使用固定大小的缓冲区存储十六进制字符,从高位到低位填充,避免栈操作的混乱
  • 直接通过字符集数组索引获取十六进制字符,逻辑更简洁不易出错
  • 保留了换行输出,和printf("%x\n", ...)的行为一致
  • 严格维护栈平衡,避免寄存器污染

内容的提问来源于stack exchange,提问作者suchypisarz

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 07:35:19