从结构上大家可以看到参数字符串的起始地址不是0080H,位于0080H处的一个字节保存了一个8位的数据,这个数据反映了参数字符串的长度。实际的参数字符串从0082H开始,以回车符结束。偏移81H处有一个空格,在处理时通常将其忽略。下面给出了一个演示程序,这个是另一个版本的LIST程序,它可以显示任意目录下的文本文件,只需给出路径名:
code segment
assume cs:code,ds:code
org 100h
main proc far
jmp start
msg db 'Press any key to continue...',0dh,0ah,24h
line db ?
start:
mov si,80h ;SI寄存器指向PSP偏移80H处
lodsb ;取得命令行参数的字符数
xor ah,ah
add si,ax ;令SI寄存器指向命令行参数的末尾
mov byte ptr [si],0 ;用"0"取取代回车符,构成ASCIIZ串
mov dx,82h ;DX寄存器指向构造好的ASCIIZ串
mov ax,3d00h ;按"读"方式打开文件
int 21h
jc exit ;若出错,转EXIT结束
mov bx,ax ;文件句柄送入BX寄存器
mov ah,3fh ;准备读入数据
mov cx,65535 ;读入64K字节
mov dx,offset buffer ;DX寄存器指向内存中的缓冲区
int 21h ;读文件
jc exit ;若出错,转EXIT结束
mov si,dx ;SI寄存器指向缓冲区首
mov di,ax ;已读入的字节数送入DI寄存器
disp_loop:
cmp di,0 ;已经处理完所有的数据吗?
jz exit ;是,转EXIT结束
dec di ;未处理完所有数据,DI寄存器减1
lodsb ;取得一个字节数据
mov ah,0eh ;在屏幕上显示这个字节
int 10h
cmp al,0ah ;一行字符都已显示了吗?
jnz disp_loop ;未显示一整行,转DISP_LOOP继续
inc byte ptr line ;已显示了一整行,行号加1
cmp line,23 ;已显示了一整屏了吗?
jnz disp_loop ;未显示满整个屏幕,转DISP_LOOP继续
mov line,0 ;行计数器清0,准备显示下一屏
mov ah,9 ;输出"PRESS ANY KEY"提示信息
mov dx,offset msg
int 21h
mov ah,0 ;等待键盘输入
int 16h
jmp disp_loop ;转DISP_LOOP继续显示下一屏
exit:
mov ah,4ch ;结束进程
int 21h
main endp
buffer db ? ;缓冲区首
code ends
end main
这个程序的使用方法和TYPE命令一致,它只能处理64K以下的文件,这主要是为了编程简单。
问题讨论至此可以告一段落了,事实上没有涉及到的知识还有很多,其中不乏有一些很重要的内容我们还没有研究。笔者认为"掌握知识不如掌握方法"。通过这一段的学习大家对此已有所体会,我们讨论了半本书,但直到现在也没有把全部的指令都说到,可是凭我们已经掌握的一些指令就能编制出完整的程序。由此可见学习汇编语言的关键不在于背下全部的指令,而在于将指令、算法、DOS/BIOS功能调用和硬件知识有机的结合起来。基于这样一种观点,所以笔者决定不再更深入地讨论有关文件的内容,剩下的东西留给大家以此检验大家的能力。