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
问题根源
printStr函数的局限性:该函数按C风格字符串处理,遇到NULL(0x00)就停止计数和输出。而BMP文件头中BM后紧接着就有0x00字节(文件大小字段的低16位常包含0值),导致函数读到第一个0x00就终止,只输出BM及后续一个非0字节,也就是你看到的BM_。- 多余的字符串终止操作:读取文件后执行
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
相关产品推荐
相关产品推荐

