从结构上大家可以看到参数字符串的起始地址不是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功能调用和硬件知识有机的结合起来。基于这样一种观点,所以笔者决定不再更深入地讨论有关文件的内容,剩下的东西留给大家以此检验大家的能力。