MASM611编译TINY模型汇编程序遇A2118错误及运行无响应问题咨询
MASM611编译TINY模型汇编程序遇A2118错误及运行无响应问题咨询
我来帮你逐个分析和解决这两个问题:
一、编译时出现的A2118错误
当你用ml.exe /AT filename.asm编译时触发A2118: cannot have segment address references with TINY model错误,原因很直接:
- TINY模型要求程序的代码、数据、栈段合并成一个64KB的段,最终生成
.COM格式程序。这种模型下,程序启动时CS=DS=ES=SS,所有段寄存器默认指向同一个段,完全不需要手动设置DS。 - 你的代码里写了
mov ax, @data和mov ds, ax,@data是MASM用来引用独立数据段地址的符号,但TINY模型不存在独立数据段,这种段地址引用属于非法操作,所以编译器报错。
解决办法:直接删掉这两行设置DS的代码,TINY模型下系统会自动帮你把DS指向正确的段。
二、程序编译成功但运行无响应(无输出)
你的程序编译后没反应,核心是两个关键逻辑错误导致的:
1. 文件查找结果的判断逻辑完全错误
INT 21h的4Eh(查找第一个文件)功能调用,不是通过AL的值判断成败,而是通过CF标志位:
- 查找成功时,CF会被清零;
- 查找失败(比如目录为空、路径不存在)时,CF会被置位。
你原代码用cmp al, 0来判断,这完全不符合DOS中断的规范,导致即使找不到文件,也不会进入输出逻辑,直接跳转到程序退出,所以看不到任何内容。
正确的判断方式是调用int 21h后,用jc exit_search(如果CF置位,说明查找失败,直接跳转到退出)。
2. DTA中日期和时间的解析完全混乱
INT 21h的4Eh调用后,DTA的结构里:
- 偏移
20h是日期字段(不是年份),格式为:高9位是相对于1980的年份,中间4位是月份,低5位是日期; - 偏移
22h是时间字段(不是月份),格式为:高5位是小时,中间6位是分钟,低5位是秒(乘以2)。
你原代码不仅把这两个字段搞反了,还直接把整个字拆成字节输出,就算找到文件,输出的也是乱码,但首先是判断错误导致根本没进入输出环节。
3. 额外的小坑
路径用C:\*.*时,要确保DOSBox里的C盘存在对应目录,换成当前目录".\*.*"可能更稳妥,避免因路径不存在导致查找失败。
修正后的代码示例
.model tiny .stack 100h .data DTA db 128 dup(0) path db ".\*.*", 0 ; 改用当前目录,兼容性更好 creation_time db "File created on: ", 0 .code main proc ; TINY模型下无需设置DS,CS=DS=SS已由系统自动设置 mov ah, 1Ah ; 设置磁盘传输区域(DTA) mov dx, offset DTA int 21h mov dx, offset path mov ah, 4Eh ; 查找第一个文件 int 21h jc exit_search ; CF置位说明查找失败,直接退出 search_loop: ; 输出提示字符串 mov dx, offset creation_time mov ah, 09h ; 字符串输出功能 int 21h ; 解析日期(DTA+20h) mov cx, word ptr [DTA+20h] ; 提取年份:高9位是相对于1980的数值,加1980得到实际年份 mov ax, cx shr ax, 9 add ax, 1980 ; 输出年份(简单的十进制转ASCII) call print_decimal mov dl, '-' ; 输出分隔符 mov ah, 02h int 21h ; 提取月份:中间4位 mov al, cl shr al, 4 call print_single_digit mov dl, '-' int 21h ; 提取日期:低5位 mov al, cl and al, 0Fh call print_single_digit ; 输出时间(DTA+22h) mov dl, ' ' int 21h mov cx, word ptr [DTA+22h] ; 提取小时:高5位 mov al, ch shr al, 3 call print_single_digit mov dl, ':' int 21h ; 提取分钟:中间6位 mov al, ch and al, 07h shl al, 3 or al, cl shr 5 call print_single_digit mov dl, ':' int 21h ; 提取秒:低5位乘以2 mov al, cl and al, 1Fh shl al, 1 call print_single_digit ; 输出换行 mov dl, 0Dh int 21h mov dl, 0Ah int 21h ; 查找下一个文件 mov ah, 4Fh int 21h jnc search_loop ; CF未置位说明找到下一个文件,继续循环 exit_search: mov ah, 4Ch ; 程序退出 int 21h ; 辅助子程序:输出AX中的十进制数(简化版,适用于1980-2099范围) print_decimal proc push bx push cx mov cx, 10 xor bx, bx div_loop: xor dx, dx div cx push dx inc bx test ax, ax jnz div_loop print_digits: pop dx add dl, 30h mov ah, 02h int 21h dec bx jnz print_digits pop cx pop bx ret print_decimal endp ; 辅助子程序:输出AL中的单个十进制数(0-59) print_single_digit proc push ax mov ah, 0 mov cl, 10 div cl add ah, 30h mov dl, ah mov ah, 02h int 21h mov dl, al add dl, 30h int 21h pop ax ret print_single_digit endp main endp end main
修正说明
- 删掉了设置DS的代码,彻底解决TINY模型的A2118编译错误;
- 修正了文件查找结果的判断逻辑,严格遵循DOS中断的CF标志位判断规则;
- 正确解析DTA中的日期和时间字段,并通过辅助子程序将数值转换为ASCII字符输出;
- 改用当前目录路径,避免因C盘路径不存在导致的查找失败;
- 添加了辅助子程序处理十进制数转ASCII输出,修复原代码中直接输出字节的错误。
备注:内容来源于stack exchange,提问作者Артем Лебідь
相关产品推荐
相关产品推荐

