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

NASM程序复制BMP并转纯白时触发打开错误的排查求助

BMP转纯白副本程序的打开错误修复

问题说明

我编写的汇编程序目标是接收一张BMP图片作为命令行参数,生成其纯白副本,但运行时始终触发errMsgOpenBmp错误(提示文本:Erro ao abrir o BMP)。怀疑问题出在readImgBuffer缓冲区的使用方式以及writeImageFile函数的实现上。

原始代码

section .data

    NULL                equ 0
    LF                  equ 10
    STDOUT              equ 1
    SYS_read            equ 0 
    SYS_open            equ 2 
    O_RDONLY            equ 000000q 
    SYS_close           equ 3 
    EXIT_SUCCESS        equ 0
    SYS_creat           equ 85
    SYS_exit            equ 60
    S_IRUSR             equ 00400q
    S_IWUSR             equ 00200q
    MAX_IMG_SIZE        equ 1048576
    SYS_write           equ 1
    bmpFileDesc         dq  0
    newImage            db  'fname.bmp',0x00
    newLine             db LF,NULL
    errMsgOpenTxt       db "Erro ao abrir o TXT", LF, NULL
    errMsgOpenBmp       db "Erro ao abrir o BMP", LF, NULL
    errMsgRead          db "Erro ao ler o BMP", LF, NULL
    errMsgWrite         db "Error write", LF, NULL

section .bss

    readImgBuffer: resb MAX_IMG_SIZE
    newBmpFileDesc: resq 1

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 printStrLn
    call terminate
    
errorOnRead:
    mov rdi, errMsgRead
    call printStrLn
    call terminate

errorOnWrite:
    mov rdi, errMsgWrite
    call printStr
    call terminate

terminate:
    mov rax, SYS_exit
    mov rdi, EXIT_SUCCESS
    syscall

readImageFile:
    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, qword [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
   
changeColorToWhite:
    _for: 
        cmp ebx, MAX_IMG_SIZE  
        jb _ciclo 
        jmp _next          
    _ciclo:
        mov byte [ebx + 0], 0xFF 
        mov byte [ebx + 1], 0xFF 
        mov byte [ebx + 2], 0xFF  
        add ebx, 4
        jmp _for
    _next:
        ret 
          
writeImageFile:
    push rsi
    push rdx
    mov rax, SYS_creat
    mov rdi, [newImage]
    mov rsi, S_IRUSR | S_IWUSR
    syscall
    cmp rax,0
    jl errorOnOpenBmp
    mov [bmpFileDesc], rax
    mov rax, SYS_write
    mov rdi, qword [bmpFileDesc]
    pop rdx 
    pop rsi
    syscall
    cmp rax, 0
    jl errorOnWrite
    mov rax, SYS_close
    mov rdi, qword [bmpFileDesc]
    syscall 
    ret     

global _start 
_start: 

    mov rdi, [rsp + 16]
    call readImageFile
    
    mov ebx, readImgBuffer
    
    call changeColorToWhite
    
    mov rdi, readImgBuffer
    
    call writeImageFile  
    
    pop rax
    call terminate

原函数说明

  • readImageFile:打开BMP文件并将内容存入缓冲区
  • writeImageFile:创建新图片并将缓冲区内容写入新BMP文件

错误分析与修复

1. readImageFile参数丢失导致打开失败

readImageFile函数调用SYS_open时,未保留传入的文件名参数(rdi),导致系统调用使用了错误的文件路径,触发打开错误。

修复后的readImageFile:

readImageFile:
    push rdi    ; 保存传入的文件名参数
    push rsi    
    mov rax, SYS_open
    ; rdi已持有文件名,无需重新设置
    mov rsi, O_RDONLY
    syscall
    cmp rax, -1  ; 系统调用失败返回-1,而非任意小于0的值
    jl errorOnOpenBmp 
    mov [bmpFileDesc], rax
    mov rax, SYS_read
    mov rdi, qword [bmpFileDesc]
    pop rsi 
    mov rsi, readImgBuffer
    mov rdx, MAX_IMG_SIZE
    syscall
    cmp rax, -1
    jl errorOnRead
    push rax 
    mov rax, SYS_close
    mov rdi, qword [bmpFileDesc]
    syscall 
    pop rax
    pop rdi     ; 恢复寄存器,维持栈平衡
    ret

2. writeImageFile参数传递错误

原代码调用writeImageFile时未传递缓冲区长度,且函数内部栈操作混乱,导致SYS_write使用无效的rsi和rdx值。

修复后的writeImageFile(需接收文件名、缓冲区地址、长度三个参数):

writeImageFile:
    ; 参数约定:rdi=输出文件名, rsi=缓冲区地址, rdx=写入长度
    push rsi
    push rdx
    push rdi
    mov rax, SYS_creat
    ; rdi已持有输出文件名
    mov rsi, S_IRUSR | S_IWUSR
    syscall
    cmp rax, -1
    jl errorOnOpenBmp
    mov [bmpFileDesc], rax
    mov rax, SYS_write
    mov rdi, qword [bmpFileDesc]
    pop rdi      ; 恢复寄存器,维持栈平衡
    pop rdx      ; 取出写入长度
    pop rsi      ; 取出缓冲区地址
    syscall
    cmp rax, -1
    jl errorOnWrite
    mov rax, SYS_close
    mov rdi, qword [bmpFileDesc]
    syscall 
    ret

3. changeColorToWhite破坏BMP文件头

原代码直接从缓冲区起始位置修改颜色,会覆盖BMP的文件头和信息头(前54字节),导致生成的文件格式损坏。需跳过这部分数据,仅修改像素区域。

修复后的changeColorToWhite:

changeColorToWhite:
    ; 参数约定:rbx=像素数据起始地址, r12=文件总长度
    _for: 
        cmp rbx, readImgBuffer + r12  ; 判断是否到文件末尾
        jnb _next          
    _ciclo:
        mov byte [rbx], 0xFF       ; 蓝色通道
        mov byte [rbx + 1], 0xFF   ; 绿色通道
        mov byte [rbx + 2], 0xFF   ; 红色通道
        add rbx, 4                  ; 适配32位BMP的像素步长(若为24位需改为3)
        jmp _for
    _next:
        ret 

4. _start栈平衡错误与参数传递修正

原_start中调用writeImageFile后执行pop rax,无对应的push操作会破坏栈平衡;同时未保存readImageFile返回的文件长度,导致写入时无法确定有效数据长度。

修复后的_start:

global _start 
_start: 
    mov rdi, [rsp + 16]  ; 取出第一个命令行参数(BMP路径)
    call readImageFile
    mov r12, rax         ; 保存读取到的文件总长度

    mov rbx, readImgBuffer + 54  ; 跳过BMP头(前54字节),指向像素数据
    call changeColorToWhite

    mov rdi, newImage    ; 输出文件名
    mov rsi, readImgBuffer  ; 缓冲区地址
    mov rdx, r12         ; 写入长度
    call writeImageFile  

    call terminate

修复后程序逻辑说明

  1. 从命令行获取输入BMP路径,打开并读取全部内容到缓冲区
  2. 跳过BMP文件头,将所有像素数据改为纯白(0xFF,0xFF,0xFF)
  3. 创建新BMP文件,将修改后的缓冲区内容写入
  4. 正常退出程序

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 10:54:52