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
修复后程序逻辑说明
- 从命令行获取输入BMP路径,打开并读取全部内容到缓冲区
- 跳过BMP文件头,将所有像素数据改为纯白(0xFF,0xFF,0xFF)
- 创建新BMP文件,将修改后的缓冲区内容写入
- 正常退出程序
内容的提问来源于stack exchange,提问作者Dajewhpogrbgvt
相关产品推荐
相关产品推荐

