如何在MASM中使用INT 21h,48h分配的内存读取DOS文件内容?
问题分析
你的代码存在两个核心问题导致文件读取失败:
- 文件指针未重置:使用
INT 21h, 42h(SEEK_END)获取文件大小后,文件指针停留在文件末尾,此时调用INT 21h, 3Fh会读取到0字节内容。 - 缓冲区地址未正确关联:
INT 21h, 48h返回的是动态分配内存的段地址,但你未将该段地址绑定到DS寄存器,也未设置DX为缓冲区起始偏移(分配的内存段偏移从0开始),导致INT 21h, 3Fh无法定位到正确的缓冲区。
修复后的代码
.MODEL SMALL .STACK 100h READ equ 0 SEEK_SET equ 0 SEEK_END equ 2 .DATA file_name db "test.txt",0 file_handle dw ? file_size dw ? file_segment dw ? original_ds dw ? ; 保存原数据段地址,用于后续恢复 .CODE main PROC mov ax, @DATA mov ds, ax ; 打开文件并获取句柄 mov ah, 3Dh mov al, READ lea dx, file_name int 21h mov [file_handle], ax mov bx, ax ; 获取文件大小:将指针移至文件末尾,读取当前指针位置 mov ah, 42h mov al, SEEK_END xor dx, dx xor cx, cx ; 42h需要CX:DX作为偏移高/低16位,需全部清零 int 21h mov [file_size], ax ; 重置文件指针到开头,否则从末尾读取无内容 mov ah, 42h mov al, SEEK_SET xor dx, dx xor cx, cx int 21h ; 计算需分配的内存段落数(1段落=16字节) mov ax, [file_size] add ax, 15 mov cl, 4 shr ax, cl ; 动态分配内存 mov bx, ax mov ah, 48h int 21h ; 可选:检查CF标志判断分配是否失败,AX会返回最大可用段落数 mov [file_segment], ax ; 读取文件内容到分配的内存 mov ah, 3Fh mov bx, [file_handle] mov cx, [file_size] ; 保存当前DS,切换到分配的内存段 mov [original_ds], ds mov ds, [file_segment] xor dx, dx ; 分配的内存起始偏移为0 int 21h ; 恢复原数据段,避免后续操作出错 mov ds, [original_ds] ; 可选:添加显示文件内容的代码,例如调用INT 21h, 09h或直接输出字符 ; 关闭文件(良好编程习惯,避免资源泄漏) mov ah, 3Eh mov bx, [file_handle] int 21h ; 释放动态分配的内存(可选,DOS退出时会自动回收,但建议手动释放) mov ah, 49h mov es, [file_segment] int 21h ; 终止程序 mov ah, 4Ch int 21h main ENDP END main
关键修复点说明
- 重置文件指针:获取文件大小后,必须调用
INT 21h, 42h并设置AL=SEEK_SET(0),将指针移回文件开头,否则读取操作会从末尾开始,返回0字节。 - 切换DS寄存器:
INT 21h, 3Fh要求缓冲区地址为DS:DX,因此先保存原DS的值,再将DS设置为INT 21h, 48h返回的段地址,同时将DX设为0(分配的内存段起始偏移为0)。读取完成后恢复原DS,避免后续操作访问错误的内存段。 - 资源清理:添加了文件关闭和内存释放的代码,虽然DOS程序退出时系统会自动回收资源,但这是规范的编程习惯;也可在
INT 21h, 48h后检查CF标志,判断内存分配是否成功。
内容的提问来源于stack exchange,提问作者Gene Adam Oker
相关产品推荐
相关产品推荐

