1. 重定向 以下a.asm,用含't'及回车13的txt,仿command.com,依masm命令行的arg符号值N,(如masm /Darg=0 a;),实现5个DOS打开专用文件(STD_)的6种io重定向: N=0:是STDIN句柄,先bin方式读1符,再从txt输't'到char N=1:是STDOUT句柄,输出char的'1'到txt N=2:是STDERR句柄,输出char的'2'到txt N=30,31: 3是STDAUX句柄,N=30,从txt输't'到char;N=31,输出char的'3'到txt N=41: 4是STDPRN句柄,输出char的'4'到txt asm调用如下功能: N=0时,44,读/写设备info,敲键符值入100h,其ascii/scan对,入106h,扩展键时,首对,入104h,次值,入101h. 如1,得(31,31,2),ctl_c,得(3,3,2e),F1,得(0,0,3bh),(3bh,0,3bh) 3d,依读写方式,打开txt,保存句柄到si 45,保存STD_句柄的复制值到di 46,将来访问(cx)句柄,变为访问(bx)=(si)句柄,开始重定向 3f/40,用STD_输入/出,字符数1,偏置char 46,将来访问(cx)句柄,变为访问(bx)=(di)句柄,结束重定向 3e,关闭txt DEBUG行完a.com,对输入,见103h的char,变't',对输出,type txt,见1~4. ACT=2 IFDEF arg IF arg GT 2 IF arg EQ 30 ACT=30 ENDIF IF arg EQ 31 ACT=31 ENDIF IF arg EQ 41 ACT=41 ENDIF STD_=arg/10 ELSE IF arg GE 0 ACT=1 STD_=arg IF arg EQ 0 ACT=0 ENDIF ENDIF ENDIF ENDIF IF ACT EQ 2 无效 %OUT /Darg=0|1|2|30|31|41 .ERR ENDIF just macro local j mov di,es:[26] 敲键,i9写低asc,高scan到[1Ch尾引字++],i16读[1Ah首引字++]到3f功能的ax sub di,2 cmp di,1ch 未重划键区,现在回头 ja j mov di,3ch 刚才入尾 j: mov ax,es:[di] endm c segment assume cs:c,ds:c org 100h @: jmp @1 char db '0'+STD_ txt db 'txt',0 @1: mov ah,3dh open mov al,ACT and 1 lea dx,txt int 21h mov si,ax han mov bx,ACT stdin test bx,63 >41 jnz @3 mov ax,4400h I/O,从/到fil\nul定向,dx=42h\80c4,否则80d3 int 21h mov ax,4401h or dl,32 bin xor dh,dh push dx int 21h mov ax,64 bios数据区seg,1E~3D是键区 mov es,ax mov ah,3fh 不等回车读 mov cx,1 1符 lea dx,@ 入256 int 21h test byte ptr cs:[256],255 测扩展 jnz @2 just mov word ptr txt,ax mov ah,3fh 取真 inc dx int 21h @2: just mov word ptr txt[2],ax mov ax,4401h 复原 pop dx and dx,not 32 int 21h @3: mov ah,45h duplica mov bx,STD_ int 21h mov di,ax han mov ah,46h force han mov bx,si mov cx,STD_ int 21h mov ah,3fh+ACT r/w=3f/40 mov bx,STD_ mov cx,1 lea dx,char int 21h mov ah,46h mov bx,di mov cx,STD_ int 21h mov ah,3eh close mov bx,si int 21h ret c ends end @ 2. 管道 反汇编DOS_3.31_more,得[100,1e9]是代码区,[1ea,219]是数据区,初值为18/50的1ea/leb,记录屏幕配置行/列数,初值1/1的1ec/1ed,记录已处理行/列数. 流程: (2.1) 100处,用功能30,取DOS主/次版本号al/ah,若非3/1f,就显1fc处的"MORE: Incorrect DOS version",用110处的int 20,退出 (2.2) 置1ea=19,用int 10,ah=0f,得屏幕列数到1eb,如50 (2.3) 用功能45,复制stdin(bx=0)句柄到bp,如5,用功能3e,关闭stdin句柄 (2.4) 用功能45,复制stderr(bx=2)句柄(也可复制被@1的si句柄),必得刚关闭的句柄0, 为看完满屏而读键盘一符时,从stderr或si读,而不移管道stdin指针. (2.5) 139处,用功能3f,打开bp句柄,字节数cx=1000,目的地21a,读stdin 用|接入管道时,more不创建新进程. 未接入时,将读键盘行,如读"135",此串及回车0d,换行0a,被存目的地,被存长度5返到ax,键入符数多于cx时,前面cx个字符被存目的地.对^Z单行,ax返回0. 若ax=0,就用14a处的int 20退出,否则 (2.6) 150处,读目的地每个字符到al 读到^Z,则转14a退出 读到0d,置列数1ed=1,转1ac 读到0a,行数1ec加1,转1ac 读到回退符08,当1ed=1,转1ac,否则列数减1后,转1ac 读到制表符09,则1ed置为下个制表位置,转1ac 读到响铃符07,则不占输出列,转1ac 读到其它符,1ed加1,比较屏幕配置列数1eb,不大于则转1ac,否则 1ec加1,再置1ed=1 (2.7) 1ac处, 用功能2,显出al到stdout,以再接管道 若1ec小于屏幕配置行数1ea,则转1e1处,否则用功能09,显出1f0处的"-- More --",用功能0c,且al=08,清键盘输入后,内调功能08,无回显,从stderr读键盘一符 输出2空行,再置1ed=1,1ec=1 (2.8) 1e1处, cx减1,结果为0,转139,否则转150 成文: BLKSZ=1000h c segment assume cs:c;ds:c,es:c,ss:c org 100h @: jmp init cfg_r db 19h cfg_c db 50h cur_r db 1 cur_c db 1 buf db BLKSZ dup (0) msg db '-more-$' cr db 13,10,36 init: xor bx,bx mov ah,45h int 21h mov bp,ax mov ah,3eh int 21h mov bx,2 mov ah,45h int 21h read: lea dx,buf mov cx,BLKSZ mov bx,bp mov ah,3fh int 21h or ax,ax jnz read1 quit: int 20h read1: mov cx,ax mov si,dx nxtch: lodsb cmp al,1ah jz quit cmp al,13 jnz ?newlin mov cur_c,1 jmp show ?newlin: cmp al,10 jnz ?back inc cur_r jmp show ?back: cmp al,8 jnz ?tab cmp cur_c,1 jz show dec cur_c jmp show ?tab: cmp al,9 jnz ?bell mov ah,cur_c add ah,7 and ah,0f8h inc ah mov cur_c,ah jmp show ?bell: cmp al,7 jz show inc cur_c mov ah,cur_c cmp ah,cfg_c jbe show inc cur_r mov cur_c,1 show: mov dl,al mov ah,2 int 21h mov ah,cur_r cmp ah,cfg_r jb ?endblk lea dx,msg mov ah,9 int 21h mov ax,0c08h int 21h lea dx,cr mov ah,9 1 cr int 21h mov cur_c,1 mov cur_r,1 ?endblk: dec cx jz read@ jmp nxtch read@: jmp read c ends end @ |