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

NASM技术问题:BMP图像十六进制信息打印异常排查

问题:BMP文件十六进制打印仅输出BM_,无法完整显示内容

我编写了一段NASM代码,目标是实现类似Hexdump的功能,打印终端传入的BMP图像参数的十六进制信息。但运行程序时,只得到BM_的输出,看不到完整的图像十六进制信息。我怀疑问题出在openAndReadBMPFile函数里,或者调用该函数后、调用printStr函数前的代码段中。

section .data

    LF equ 10 
    NULL equ 0 
    TRUE equ 1
    FALSE equ 0
    EXIT_SUCCESS equ 0 
    STDIN equ 0 
    STDOUT equ 1 
    STDERR equ 2 
    SYS_read equ 0 
    SYS_write equ 1 
    SYS_open equ 2 
    SYS_close equ 3 
    SYS_fork equ 57 
    SYS_exit equ 60 
    SYS_creat equ 85 
    SYS_time equ 201 
    O_CREAT equ 0x40
    O_TRUNC equ 0x200
    O_APPEND equ 0x400
    O_RDONLY equ 000000q 
    O_WRONLY equ 000001q 
    O_RDWR equ 000002q 
    S_IRUSR equ 00400q
    S_IWUSR equ 00200q
    S_IXUSR equ 00100q

    BUFF_SIZE equ 255 
    newLine db LF, NULL 

    bmpFileDesc         dq  0
    sgFileDesc         dq  0
    MAX_IMG_SIZE        equ 1048576

    errMsgOpenBmp       db "Erro ao abrir o BMP", LF, NULL
    errImgRead          db "Erro ao ler o BMP", LF, NULL


section .bss

    readImgBuffer: resb MAX_IMG_SIZE 


section .text


printStr:
    push rbp
    mov rbp, rsp
    push rbx
    mov rbx, rdi
    mov rdx, 0   
    
strCountLoop:
    cmp byte [rbx], NULL
    je strCountDone
    inc rdx
    inc rbx
    jmp strCountLoop   
    
strCountDone:
    cmp rdx, 0
    je prtDone
    mov rax, SYS_write
    mov rsi, rdi
    mov rdi, STDOUT 
    syscall     
    
prtDone:
    pop rbx
    pop rbp
    ret        
printStrLn:
    call printStr
    mov rdi, newLine
    call printStr
    ret


errorOnOpenBmp:
    mov rdi, errMsgOpenBmp
    call printStr
    call terminate
    
errorOnRead:
    mov rdi, errMsgRead
    call printStr
    call terminate


openAndReadBMPFile: 

    push rsi 
    mov rax, SYS_open 
    mov rsi, O_RDONLY 
    syscall 
    cmp rax, 0
    jl errorOnOpenBmp
    mov [bmpFileDesc], rax 
    mov rax, SYS_read

    mov rdi, [bmpFileDesc]
    pop rsi 
    mov rsi, readImgBuffer
    mov rdx, MAX_IMG_SIZE

    syscall
    cmp rax, 0
    jl errorOnRead
    push rax 
    mov rax, SYS_close
    mov rdi, qword [bmpFileDesc]
    syscall
    pop rax
    ret



global _start 
_start: 

mov rdi, [rsp + 16]
call openAndReadBMPFile

mov rsi, readImgBuffer
mov byte [rsi+rax], NULL
mov rdi, readImgBuffer
call printStr

terminate:
    mov rax, SYS_exit
    mov rdi, EXIT_SUCCESS
    syscall

问题根源

  1. printStr函数的局限性:该函数按C风格字符串处理,遇到NULL(0x00)就停止计数和输出。而BMP文件头中BM后紧接着就有0x00字节(文件大小字段的低16位常包含0值),导致函数读到第一个0x00就终止,只输出BM及后续一个非0字节,也就是你看到的BM_。
  2. 多余的字符串终止操作:读取文件后执行mov byte [rsi+rax], NULL完全没必要,还会破坏文件内容(若文件刚好读满缓冲区),且BMP文件本身包含大量0x00字节,根本不能当作字符串处理。

修复方案

1. 替换为直接输出二进制内容的函数

不需要按字符串计数,直接用SYS_write输出读取到的实际字节数(rax返回值即为读取字节数):

printBinary:
    push rbp
    mov rbp, rsp
    mov rax, SYS_write
    mov rdi, STDOUT
    ; rsi 指向缓冲区,rdx 为要输出的字节数
    syscall
    pop rbp
    ret

2. 修改主函数输出逻辑

去掉添加NULL终止符的代码,直接调用新的输出函数:

_start: 
mov rdi, [rsp + 16]
call openAndReadBMPFile

; 直接输出读取到的二进制内容
mov rsi, readImgBuffer
mov rdx, rax  ; rax 存储了读取的字节数
call printBinary

terminate:
    mov rax, SYS_exit
    mov rdi, EXIT_SUCCESS
    syscall

3. (可选)实现真正的Hexdump格式

若要像hexdump工具那样输出十六进制+ASCII预览,需编写字节转十六进制的转换函数,循环处理每个字节:

  • 编写byteToHex函数,将单个字节转换为两位十六进制字符
  • 每处理16字节换行,同时输出对应的ASCII字符(不可见字符用.代替)

额外优化

openAndReadBMPFile中SYS_open调用缺少权限参数(虽O_RDONLY场景下不强制,但显式传入更规范),在SYS_open前添加:

mov rdx, 0  ; O_RDONLY模式下权限参数传0即可

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 07:01:02