閱讀188 返回首頁    go 阿裏雲 go 技術社區[雲棲]


[轉貼]改好DEBUG七處缺點的comexe實現報告

 

 

首先聲明,本文所指DEBUG,係DOS 6.22,win 98及2k三者DEBUG.EXE.

(1) DEBUG命令T及P的2處缺點

跟蹤命令T,建立在8086標誌寄存器第8位(自陷位)置1後,處理器執行完一條
被跟蹤指令,就進單步中斷1的基礎上(進入時,被調試進程棧頂3個字,被無辜破壞).
DEBUG預先接管中斷1,在那裏,對被跟蹤指令的執行完現場,先保存,後顯示.

於是,DEBUG用以下5步,讓欲跟蹤的指令,在自陷位持有1的處理器環境下,間接執行:

(1.1) or    標誌寄存器,100h
(1.2) push    標誌寄存器
(1.3) push    欲跟蹤的指令CS
(1.4) push    欲跟蹤的指令IP
(1.5) iret

欲跟蹤的指令是int 21h等中斷指令時,遇到1個問題:

處理器執行此int指令時,先壓標誌寄存器F(自陷位已被DEBUG置為1)入棧,
然後清標誌寄存器的自陷位及中斷位,接著壓int下條指令y的CS,IP入棧,
最後,查找位於0:0的中斷矢量表,執行此中斷號對應的中斷入口指令x
(21h中斷的入口IP,CS,在0:84h,0:86h字).而此時的自陷位剛被清為0,
於是,就不能跟蹤x這條指令.

再次進入中斷1的時刻,隻能是此int例程通過iret指令返回到用戶態時,
處理器從棧中彈出y的ip,cs及標誌寄存器F,間接執行完y的那個時刻.

命令T能跟進int例程內部,靠以下模擬int進入過程的5步:

(1.6) 壓標誌寄存器F入用戶態堆棧.
(1.7) 壓y的CS,IP入用戶態堆棧.
(1.8) 清標誌寄存器F的中斷位.
(1.9) 改欲跟蹤的指令為x.
(1.10) 用(1.1)開始的5步,間接執行x.注意,在依此彈出x的IP,CS後,彈出的標誌
       寄存器F,其中斷位已被(1.8)清除,從而與int指令實際執行後的環境相同,
       x在中斷位關閉的氛圍中執行.

置斷點命令G,建立在一執行機器碼為0cch的INT 3指令,就進斷點中斷3的
基礎上.DEBUG預先接管中斷3,然後用0cch替換斷點首字節,運行被調試進程,如果
運行路徑遇到此斷點,就會進中斷3.在那裏,命令G對被調試進程進入int 3之前的
現場,先保存,後顯示,再恢複斷點首字節.

繼續命令P,能執行int指令而不跟進去,靠的是對int的下條指令y置斷點.
這樣,就把整個int例程視為1條指令,使int的下條指令y,停於中斷3.

命令T及P有2處缺點:

(1.11) 它們的步數從1到ffff,對想無限次運行,直至被調試進程自身終止的用戶,
       這是缺點1.

(1.12) 遇int或call指令,T進入而P不進入,對想跟蹤自編的proc,而不想跟蹤
       int例程的用戶,要不斷用T與P,手工解決進入問題,T與P自動運行多步
       的功能,隻得棄用,這是缺點2.

(2) DEBUG對INTO執行命令P的1處缺點

F第11位(溢出位)為1時,執行機器碼為0ceh的INTO,將進入int 4.例如,

mov al,7fh
inc al        ;al變為80h,置1溢出位
into

,不想進入中斷4內部,執行P命令時,DEBUG卻與命令T相同,進了內部,這是缺點3.

(3) DEBUG不認首字被5a4d標識,後綴改為他名的exe文件的1處缺點

exe文件,以頭兩個字節為4d(M),5a(Z)做標識,不管後綴名.本文所用的4b01裝入功能,
就按此規則,解決exe文件的重定位.

但DEBUG卻依後綴名解決重定位,這是缺點4.

剛進DEBUG的bx:cx值,體現裝入文件長度,對exe文件,此值,少去exe頭占用的200h.

(4) DEBUG與用戶交互時的3處缺點

(4.1) 用戶想輸出DEBUG的運行結果到foo.1時,隻能發:DEBUG foo.com>foo.1
但運行提示及用戶的鍵盤echo,也被重定向,不可見,這是缺點5.

(4.2) 改標誌寄存器的標誌位時,需知各標誌的兩字母簡名,如溢出位為1/0,
簡名為OV/NV,對不知簡名,而想改標誌的用戶,這是缺點6.

(4.3) 被調試進程用功能4ch/31h,使al帶errorlevel值5a,正常/駐留終止時,
DEBUG顯出Program terminated normally信息,但不反映errorlevel及終止類型
字節,用戶這時隻得手工匯編mov ah,4d,int 21,從al,ah取兩值,這是缺點7.

(5) comexe改好這七處缺點的做法:

(5.1) 仿命令T及P運行時,comexe將用'val[0001~fffe,ffff]',詢問步數,
回答ffff時,comexe將無限次運行,直至被調試進程自身終止,這改好缺點1.

(5.2) 遇操作碼為0cdh的int,或0cch,或0ceh且F溢出位為1,comexe將用
'proceed,n(ever enter int):',問是否進入中斷內部,答p,本次不進入,
答n,從此不進入,答其他,將進入;call指令,comexe都進入,這改好缺點2,3.

(5.3) comexe調用4b01功能,裝入被調試進程,依返回的sp初值,決定是否exe文件,
這改好缺點4.

(5.4) comexe先保存輸出句柄1到oldstd1,對提示及用戶的鍵盤echo,
讓stderr代替句柄1,從而可見;對運行結果,讓oldstd1代替句柄1,輸出
能到屏幕或文件,這改好缺點5.

(5.5) comexe能讀,寫任意段:位移上的字,被調試進程AX,BX,CX,DX,SP,BP,SI,DI,
DS,ES,SS,CS,IP,F這14個字,從低存到高,AX的段:位移,被AX(seg:off=0526:0190)
指明,F有效位C等,被F(????ODITSZ?A?P?C)指明,這改好缺點6.

(5.6) comexe仿DEBUG,能捕獲被調試進程5類終止,並改好缺點7:

裝入映象後,comexe使被調試進程psp偏移0ah處的終止IP及CS,指向comexe的i22,
被調試進程用int 20h,或int 21h的功能0,或功能4ch正常終止,或用int 27h,
int 21h的功能31h駐留終止,DOS都將終止IP及CS寫入中斷22h,然後執行int 22h,
於是,comexe在i22,可感知這些終止,並用4d功能,取終止信息,顯出
exit_type/errlev=00/5a.

(7) comexe仿DEBUG,能捕獲被調試進程CTRL-BREAK,CTRL-C中斷的做法:

按ctl-break/ctl-c鍵時,鍵盤電路中斷CPU,鍵盤中斷服務程序,會將40:71字節
第7位,置為1/0,並在屏幕光標處,顯示^C,最後,調用中斷23h.

comexe讓中斷23h指向i23,被調試進程被ctl中斷,而進入i23時,sp指向鍵盤中斷
服務程序調用中斷23h那條指令後麵的ip,加6後,指向被調試程序中,能檢ctl
中斷的int指令後麵的ip,如int後麵的cmp:

mov ah,1    ;讀鍵盤
int 21h
cmp al,'q'

comexe對這兩鍵,分顯為^b/^c.而DEBUG,不分顯.

(8) comexe仿DEBUG能求指令操作碼的助記符的做法:

占1到6個字節的8086的指令,分3部分:操作碼字節[尋址方式字節][位移或數據字節].

第2部分的出現被第1部分決定.第3部分的出現被第1,2部分決定.

8086有6種操作數尋址方式:

(8.1) 寄存器對寄存器,如mov cx,bx,把bx的內容送入cx.

(8.2) 立即數尋址,如mov cx,10,把10送入cx(10值,隨.RADIX變,寫.RADIX 4,cx為4)

(8.3) 直接存儲器尋址,如mov cx,wd1,把寫為wd1 dw 0的wd1字內容,送入cx.

(8.4) 寄存器(bx,bp,si,di)間接尋址,如mov cx,[bx],把bx的內容,作為有效地址EA,
將EA處的字,送入cx.

(8.5) 寄存器+位移disp的間接尋址,如mov cx,[bx]+1234h,把bx的內容加上1234h,
作為EA,將EA處的字,送入cx.

(8.6) 基址寄存器(bx,bp)+變址寄存器(si,di)+位移的間接尋址,如mov cx,
[bx]+[si]+13h,把bx的內容,si的內容,13h,三者相加,作為EA,將EA處的字,送入cx.

有時,操作碼字節的第0位w,用1/0,指明字/字節操作.

有時,操作碼字節的第1位vds,在移位指令中,用1/0,指明cl次/1次移動;在含運算
結果的指令中,用1/0,指明結果存於reg域/有效地址EA;在含立即數加減的指令
中,用1指明加減字時(w為1),尋址方式字節的下個字節,將依符號位,展成1個運算字.

尋址方式字節,從高到低,含mod域(2位),reg域(3位),r/m域(3位).

mod域解釋disp的形成:

mod為0,則disp為0,即無位移低字節及位移高字節.(r/m域為6時,EA僅被位移低字節,
及位移高字節構成)

mod為1,則disp為位移低字節,及此字節的符號擴展字節,無位移高字節.

mod為2,則disp為位移低字節,及位移高字節.

mod為3,則r/m域是寄存器域.

reg域依w的1/0,索引ax,cx,dx,bx,sp,bp,si,di及al,cl,dl,bl,ah,ch,dh,bh

r/m域解釋16位有效地址(EA)的組成:
r/m=0,EA=[BX]+[SI]+disp
r/m=1,EA=[BX]+[DI]+disp
r/m=2,EA=[BP]+[SI]+disp
r/m=3,EA=[BP]+[DI]+disp
r/m=4,EA=[SI]+disp
r/m=5,EA=[DI]+disp
r/m=6,EA=[BP]+disp(mod域為0時,EA僅被位移低字節,及位移高字節構成)
r/m=7,EA=[BX]+disp

(8.7) 舉10個例子,解釋反匯編思想:

(8.7.1) 字節操作,運算結果存於EA:
機器碼00c1,反出add cl,al,mod為3,reg為0,索引到al,結果存於1值r/m索引到的cl

(8.7.2) 字操作,運算結果存於reg:
機器碼03ad3412,反出add bp,[di]+1234h,mod為2,reg為5,索引到bp,r/m為5,
EA就是[DI]+disp,先低後高存儲的disp為1234h

(8.7.3) mod為0,使位移為0:
機器碼f630(div的reg,恒為6),反出div byte ptr [bx]+[si]+0,這時,r/m為0,
EA就是[BX]+[SI]+disp

(8.7.4) mod為0,r/m為6,使EA僅被16位disp構成:
機器碼f6363412,反出div byte ptr [1234h]

(8.7.5) mod為1,使disp為位移低字節,及此字節的符號擴展字節:
機器碼8042fd80,反出add byte ptr [bx]+[di]-3,80h,這時,disp為fd的16位符號
擴展字fffd,即-3,r/m為1,EA就是[BX]+[DI]+disp,加數為80h

(8.7.6) mod為2,使disp為位移高字節,及位移低字節:
機器碼c78257136824,反出mov word ptr 1357h[bp+si],2468h,這時,mov的reg規定
為0,r/m為2,EA就是[BP]+[SI]+disp

(8.7.7) vds為1,w為1:
機器碼83c3fc,反出add bx,-4,這時,add的reg規定為0,r/m為3,索引到bx,fc符號
擴展成運算字fffc,即-4

(8.7.8) vds為0,w為1:
機器碼81c3fcff,反出add bx,-4,未用符號擴展優點,字-4存為fcff

(8.7.9) 偏移108h處,相等則跳到10fh的指令:
機器碼7405,反出jz 10f,74不分域,下一條指令地址10ah,加上補碼形式的位移
字節5,就是目的地址10fh.若想轉101h,位移字節為f7,對應-9.

(8.7.10) 指定段前綴:
機器碼26a03412,反出mov al,es:[1234h],段前綴26,2e,36,3e,對應es,cs,ss,ds.

隱含段前綴時的尋址方法:

[ip],[sp],[bx],[bp],[si],用cs,ss,ds,ss,ds

[di]不含串時,用ds,如mov [di],al,否則用es,如stosb

基址+變址的段前綴,依基址.

DEBUG靠4個表:mnemo,mnemo_idx,x4857_idx,x4857,求指令操作碼的助記符.

(8.8) mnemo是指令助記符表,各助記符被空格隔開,如"CLD CLI".

(8.9) mnemo_idx被操作碼索引,對應的字值為助記符對mnemo的偏移,例如,cli的
機器碼是fa,mnemo_idx的第fa個字,值為48h,此為CLI串對mnemo的偏移.mnemo_idx
的字值為0ffffh時,要用操作碼索引x4857_idx:

(8.9.1) x4857_idx的對應字節值不為0ffh時,是對x4857的偏移off,這時,要用尋址
方式字節的reg域,索引x4857的始於字節偏移off的8個字,這組字中被索引的字值,
為助記符對mnemo的偏移.

例如,dec ah,機器碼是fecc,mnemo_idx的第fe個字,值為0ffffh,找x4857_idx的
第fe個字節,值為30h,再用尋址方式字節cc的reg值1,索引x4857的偏移30h字節
開始的8個字,找這組字中的第1個字,值為6ch,此為"DEC"對mnemo的偏移.

(9) comexe的跨段檢查功能

DEBUG.EXE等,常用retf等指令,同時改IP,CS,comexe的t,遇CS改值,
用0033 gap seg,n(o check):,指明老CS的偏移33處的指令執行後,
使CS改值,並問還查跨段否,答n表示不查.

DEBUG依4表求助記符,是靠comexe,調試2k的DEBUG.EXE,對t,答ffff,對proceed,
答n,過了33,103,1aa,104跨段,遇顯出'-'的28fc,讀u等命令的478,顯助記符
的292c,然後用DEBUG調試此EXE,得mnemo始於40ba,mnemo_idx始於3cba,
化簡後,得x4857_idx,32個在4857的字,減40ba,得x4857.

想從文件輸入的用戶,對進中斷及跨段,可寫兩個n,不管誰先到,再預寫其他
命令,可使comexe自動運行,如用pctools寫不含LF的29字節二進製文件foo.0:

0100  64 65 62 75 67 2E 65 78-65 0D 66 2E 65 78 65 0D   debug.exe.f.exe.
0110  74 66 66 66 66 0D 6E 6E-75 0D 71 0D 71            tffff.nnu.q.q

其中,f.exe是debug.exe的參數,由

code    segment
        assume  es:code,cs:code,ss:code,ds:code
@        proc    far
        push    ds
        xor        ax,ax
        push    ax
        ret
@        endp
code    ends
        end        @

生成.執行comexe<foo.0,相當於執行了debug.exe f.exe的命令u,q

(10) comexe.asm全文:

RADIX    =    16            ;可接收各進製
RADIX1    =    400h+RADIX    ;4是移次
WANTSZ    =    4            ;不含CR的輸入長

setstd1    macro std1
        mov ah,46h        ;使bx起cx作用
        mov    bx,std1
        mov cx,1        ;stdout
        int 21h
        endm

makebrk    macro
        mov al,es:[bx]                ;保存首字節
        mov brkval,al
        mov byte ptr es:[bx],0cch    ;換入0cch

        mov brkoff,bx
        mov brkseg,es
        endm

alasc    macro      
        mov        ah,al

        and        al,15    ;低nibble
        xlat

        xchg    ah,al

        rept    4
        shr        al,1    ;高nibble
        endm

        xlat

        stosw
        endm

axasc    macro
        xchg ah,al            ;處理ah
        
        push ax
        alasc
        pop ax

        xchg ah,al            ;處理al
        alasc
        endm

newline    macro
        mov ah,9
        lea dx,CRLF
        int 21h
        endm

code    segment
        assume es:code,cs:code,ss:code,ds:code

        org 100h
@:        jmp @1

w16        dw 0            ;參數塊起始,0繼承父env
        dw 128+15+1        ;實長打頭的參數串偏移
paraseg    dw 5 dup(0)        ;參數串段值及4字fcb
initsp    dw 0
initss    dw 0
initip    dw 0
initcs    dw 6 dup(0)

.w0        db    13,10
w0_w14    db '0000 0000 0000 0000 0000 0000 0000 0000 '
        db '0000 0000 0000 0000 0000 0000 0000 '
w15        dw 2 dup(0)
$_32    db "$gap seg,n(o check):$"    ;跨段標記

bufsz    db    WANTSZ+1        ;鍵盤緩衝區
charcnt    db    0
charbuf    db    WANTSZ+1    dup(0)        

cax     dw 0
cbx     dw ?                ;被調試文件長的高,低字.對exe文件,少200h
ccx     dw ?
cdx     dw 0
csp     dw ?
cbp     dw 0
csi     dw 0
cdi     dw 0

cds     dw ?
ces     dw ?
css     dw ?
ccs     dw ?
cip     dw ?

cf        dw    3202h            ;仿debug,初置標誌寄存器.對應0:0
oldstd1    dw    0,1,1            ;伴隨comexe的stdout

b0_b1    label    word
byte0    db    0
byte1    db    0
intsz    dw    0,3,3            ;欲進的中斷指令的字節數

.ax        db 13,10,'AX='
axdiasc    db '0000 BX=0000 CX=0000 DX=0000 '
        db 'SP=0000 BP=0000 SI=0000 DI=0000|'

codeasc    dw 0                    ;操作符asc

vecasc    label    word            ;中斷號asc
        db    0,0,13,10,'DS='

dsipasc    db '0000 ES=0000 SS=0000 CS=0000 IP=0000 '
oc        db 23    dup(32),'|'    ;8個標誌簡名    
mne8086    db 7 dup(0)            ;8086指令助記符
CRLF    db 13,10,36

F01        db 'NVOVUPDNDIEIPLNGNZZRNAACPOPENCCY'

i?        label    word        ;區別中斷1,3,22h,23h
        db    'co'

off23    label    word
        db    'm,'

seg23    label    word
        db    'ex'

steps1    label    word
        db    'e:'

chkgap    db    36                ;查跨段?

steps    dw    0a0dh            ;步數

brkval    db    'a'                ;斷點首字節
brkoff    label    word
        db    'rg'            ;斷點off
brkseg    label    word    
        db    '(len<85):$'    ;斷點seg

?cmd    db    13,10,'AX(seg:off='    ;主菜單
caxseg    db    4    dup(0),58                
caxoff    db    4    dup(0)
        db    ') F(????ODITSZ?A?P?C) d(ump word),edit,go,trace:$'

?steps    db 13,10,'steps[0001~fffe,ffff]$'
?seg    db 13,10,'seg[????]$'
?off    db 13,10,'off[????]$'
?val    db 13,10,'val[????]$'

?enter    db 13,10,'proceed,n(ever enter int):$'

hextbl    db '0123456789abcdef'
Fvalid    dw    0ed5h    ;over,direction,interrupt(,trap)
                    ;sign,zero,auxiliary,parity,carry

ctl        db    13,10,94
c_brk    db    0,13,10,36

exitmsg    db    13,10,'exit_type/errlev='
type4    db    0,0,47
errlev    db    0,0,13,10,36

;指令助記符表(debug的40bah)
mnemo    db "DB DW ; ORG ADD "    ;0
        db "ADC SUB SBB XOR "    
        db "OR AND AAA AAD A"
        db "AM AAS CALL CBW "
        db "CLC CLD CLI CMC "
        db "CMPSB CMPSW CMP "
        db "CWD DAA DAS DEC "
        db "DIV ESC FXCH FFR"
        db "EE FCOMPP FCOMP "    ;80h
        db "FCOM FICOMP FICO"
        db "M FNOP FCHS FABS"
        db " FTST FXAM FLDL2"
        db "T FLDL2E FLDLG2 "
        db "FLDLN2 FLDPI FLD"
        db "1 FLDZ F2XM1 FYL"
        db "2XP1 FYL2X FPTAN"
        db " FPATAN FXTRACT "    ;100h
        db "FDECSTP FINCSTP "
        db "FPREM FSQRT FRND"
        db "INT FSCALE FINIT"
        db " FDISI FENI FCLE"
        db "X FBLD FBSTP FLD"
        db "CW FSTCW FSTSW F"
        db "STENV FLDENV FSA"
        db "VE FRSTOR FADDP "    ;180h
        db "FADD FIADD FSUBR"
        db "P FSUBR FSUBP FS"
        db "UB FISUBR FISUB "
        db "FMULP FMUL FIMUL"
        db " FDIVRP FDIVR FD"
        db "IVP FDIV FIDIVR "
        db "FIDIV FWAIT FILD"
        db " FLD FSTP FST FI"    ;200h
        db "STP FIST HLT IDI"
        db "V IMUL INC INTO "
        db "INT IN IRET JNBE"
        db " JAE JA JCXZ JNB"
        db " JBE JB JNC JC J"
        db "NAE JNA JZ JE JG"
        db "E JG JNLE JNL JL"
        db "E JL JNGE JNG JM"    ;280h
        db "P JNZ JNE JPE JP"
        db "O JNP JNS JNO JO"
        db " JS JP LAHF LDS "
        db "LEA LES LOCK LOD"
        db "SB LODSW LOOPNZ "
        db "LOOPZ LOOPNE LOO"
        db "PE LOOP MOVSB MO"
        db "VSW MOV MUL NEG "    ;300h
        db "NOP NOT OUT POPF"
        db " POP PUSHF PUSH "
        db "RCL RCR REPZ REP"
        db "NZ REPE REPNE RE"
        db "P RETF RET ROL R"
        db "OR SAHF SAR SCAS"
        db "B SCASW SHL SHR "
        db "STC STD STI STOS"    ;380h
        db "B STOSW TEST WAI"
        db "T XCHG XLAT ES: "
        db "CS: SS: DS: ??? "    ;3b0h

;x4857_idx被操作碼索引,偶數值,是助記符對x4857的偏移

x4857_idx    db 128 dup(1)                            ;0~7fh
            db 4 dup(10h),76 dup(1)                    ;80h~0cfh
            db 4 dup(0),4 dup(1),8 dup(0ffh)        ;0d0h~0dfh
            db 22 dup(1),20h,20h,6 dup(1),30h,30h    ;0e0h~0ffh

;x4857被尋址方式字節reg域索引,項值為助記符對mnemo的偏移

        ;被256bh或255dh找出,是ROL,ROR,RCL,RCR,SHL,SHR,???,SAR偏移
x4857    dw 035bh,035fh,0330h,0334h,0378h,037ch,03bch,0368h

        ;被211fh或218ch找出,是ADD,OR,ADC,SBB,AND,SUB,XOR,CMP偏移
        dw 0ch,20h,10h,18h,23h,14h,1ch,5ch

        ;被2585h找出,是TEST,???,NOT,NEG,MUL,IMUL,DIV,IDIV偏移
        dw 398h,3bch,314h,30ch,308h,222h,70h,21dh

        ;被2594h找出,是INC,DEC,CALL,CALL,JMP,JMP,PUSH,???偏移
        dw 227h,6ch,37h,37h,28eh,28eh,32bh,3bch

comment * (debug的3cbah)
000  C6 40 AF 21 C6 40 AF 21-C6 40 04 22 C6 40 04 22    ;00-03
010  C6 40 2F 21 C6 40 2F 21-E5 43 CC 21 DB 43 CC 21    ;04-07
020  DA 40 AF 21 DA 40 AF 21-DA 40 04 22 DA 40 04 22    ;08-0b
030  DA 40 2F 21 DA 40 2F 21-E5 43 CC 21 BA 40 6B 21    ;0c-0f
040  CA 40 AF 21 CA 40 AF 21-CA 40 04 22 CA 40 04 22    ;10-13
050  CA 40 2F 21 CA 40 2F 21-E5 43 CC 21 DB 43 CC 21    ;14-17
060  D2 40 AF 21 D2 40 AF 21-D2 40 04 22 D2 40 04 22    ;18-1b
070  D2 40 2F 21 D2 40 2F 21-E5 43 CC 21 DB 43 CC 21    ;1c-1f
080  DD 40 AF 21 DD 40 AF 21-DD 40 04 22 DD 40 04 22    ;20-23
090  DD 40 2F 21 DD 40 2F 21-66 44 6C 20 1E 41 7D 22    ;24-27
0A0  CE 40 AF 21 CE 40 AF 21-CE 40 04 22 CE 40 04 22    ;28-2b
0B0  CE 40 2F 21 CE 40 2F 21-6A 44 68 20 22 41 7D 22    ;2c-2f
0C0  D6 40 AF 21 D6 40 AF 21-D6 40 04 22 D6 40 04 22    ;30-33
0D0  D6 40 2F 21 D6 40 2F 21-6E 44 64 20 E1 40 7D 22    ;34-37
0E0  16 41 AF 21 16 41 AF 21-16 41 04 22 16 41 04 22    ;38-3b
0F0  16 41 2F 21 16 41 2F 21-72 44 60 20 ED 40 7D 22    ;3c-3f
100  E1 42 D9 21 E1 42 D9 21-E1 42 D9 21 E1 42 D9 21    ;40-43
110  E1 42 D9 21 E1 42 D9 21-E1 42 D9 21 E1 42 D9 21    ;44-47
120  26 41 D9 21 26 41 D9 21-26 41 D9 21 26 41 D9 21    ;48-4b
130  26 41 D9 21 26 41 D9 21-26 41 D9 21 26 41 D9 21    ;4c-4f
140  E5 43 D9 21 E5 43 D9 21-E5 43 D9 21 E5 43 D9 21    ;50-53
150  E5 43 D9 21 E5 43 D9 21-E5 43 D9 21 E5 43 D9 21    ;54-57
160  DB 43 D9 21 DB 43 D9 21-DB 43 D9 21 DB 43 D9 21    ;58-5b
170  DB 43 D9 21 DB 43 D9 21-DB 43 D9 21 DB 43 D9 21    ;5c-5f
180  BA 40 6B 21 BA 40 6B 21-BA 40 6B 21 BA 40 6B 21    ;60-63
190  BA 40 6B 21 BA 40 6B 21-BA 40 6B 21 BA 40 6B 21    ;64-67
1A0  BA 40 6B 21 BA 40 6B 21-BA 40 6B 21 BA 40 6B 21    ;68-6b
1B0  BA 40 6B 21 BA 40 6B 21-BA 40 6B 21 BA 40 6B 21    ;6c-6f
1C0  68 43 98 22 64 43 98 22-0F 43 98 22 07 43 98 22    ;70-73
1D0  22 43 98 22 4C 43 98 22-0B 43 98 22 FF 42 98 22    ;74-77
1E0  6B 43 98 22 60 43 98 22-54 43 98 22 58 43 98 22    ;78-7b
1F0  3C 43 98 22 28 43 98 22-38 43 98 22 2C 43 98 22    ;7c-7f
200  00 00 1F 21 00 00 1F 21-00 00 1F 21 00 00 8C 21    ;80-83
210  52 44 04 22 52 44 04 22-5C 44 04 22 5C 44 04 22    ;84-87
220  BE 43 AF 21 BE 43 AF 21-BE 43 04 22 BE 43 04 22    ;88-8b
230  BE 43 DD 21 7A 43 FF 21-BE 43 ED 21 DB 43 FA 21    ;8c-8f
240  CA 43 7D 22 5C 44 BB 22-5C 44 BB 22 5C 44 BB 22    ;90-93
250  5C 44 BB 22 5C 44 BB 22-5C 44 BB 22 5C 44 BB 22    ;94-97
260  F6 40 7D 22 1A 41 7D 22-F1 40 43 21 57 44 7D 22    ;98-9b
270  DF 43 7D 22 D6 43 7D 22-1D 44 7D 22 71 43 7D 22    ;9c-9f
280  BE 43 C8 22 BE 43 C8 22-BE 43 DC 22 BE 43 DC 22    ;a0-a3
290  B2 43 7D 22 B8 43 7D 22-0A 41 7D 22 10 41 7D 22    ;a4-a7
2A0  52 44 2F 21 52 44 2F 21-46 44 7D 22 4C 44 7D 22    ;a8-ab
2B0  87 43 7D 22 8D 43 7D 22-26 44 7D 22 2C 44 7D 22    ;ac-af
2C0  BE 43 E7 22 BE 43 E7 22-BE 43 E7 22 BE 43 E7 22    ;b0-b3
2D0  BE 43 E7 22 BE 43 E7 22-BE 43 E7 22 BE 43 E7 22    ;b4-b7
2E0  BE 43 EE 22 BE 43 EE 22-BE 43 EE 22 BE 43 EE 22    ;b8-bb
2F0  BE 43 EE 22 BE 43 EE 22-BE 43 EE 22 BE 43 EE 22    ;bc-bf
300  BA 40 6B 21 BA 40 6B 21-11 44 5C 21 11 44 7D 22    ;c0-c3
310  7E 43 FF 21 76 43 FF 21-BE 43 2A 21 BE 43 2A 21    ;c4-c7
320  BA 40 6B 21 BA 40 6B 21-0C 44 5C 21 0C 44 7D 22    ;c8-cb
330  EA 42 F8 22 EA 42 3E 21-E5 42 7D 22 F1 42 7D 22    ;cc-cf
340  00 00 6B 25 00 00 6B 25-00 00 5D 25 00 00 5D 25    ;d0-d3
350  E9 40 84 21 E5 40 84 21-BA 40 6B 21 61 44 7D 22    ;d4-d7
360  00 00 B4 23 00 00 4E 23-00 00 B4 23 00 00 26 23    ;d8-db
370  00 00 B4 23 00 00 07 23-00 00 B4 23 00 00 FD 22    ;dc-df
380  93 43 98 22 9A 43 98 22-AD 43 98 22 02 43 98 22    ;e0-e3
390  EE 42 03 25 EE 42 FE 24-D2 43 20 25 D2 43 25 25    ;e4-e7
3A0  F1 40 AB 22 48 43 AB 22-48 43 43 21 48 43 98 22    ;e8-eb
3B0  EE 42 F6 24 EE 42 F1 24-D2 43 0E 25 D2 43 13 25    ;ec-ef
3C0  82 43 70 20 BA 40 6B 21-F7 43 70 20 F2 43 70 20    ;f0-f3
3D0  D3 42 7D 22 06 41 7D 22-00 00 85 25 00 00 85 25    ;f4-f7
3E0  FA 40 7D 22 3A 44 7D 22-02 41 7D 22 42 44 7D 22    ;f8-fb
3F0  FE 40 7D 22 3E 44 7D 22-00 00 94 25 00 00 94 25    ;fc-ff
*

;mnemo_idx被操作碼索引,非ffff項值,為助記符對mnemo的偏移,否則查x4857_idx
mnemo_idx    dw 6 dup(0ch),32bh,321h                    ;0
            dw 6 dup(20h),32bh,0

            dw 6 dup(10h),32bh,321h
            dw 6 dup(18h),32bh,321h

            dw 6 dup(23h),3ach,64h
            dw 6 dup(14h),3b0h,68h

            dw 6 dup(1ch),3b4h,27h
            dw 6 dup(5ch),3b8h,33h

            dw 8 dup(227h)                            ;40h
            dw 8 dup(6ch)

            dw 8 dup(32bh)
            dw 8 dup(321h)

            dw 8 dup(0)
            dw 8 dup(0)

            dw 2aeh,2aah,255h,24dh,268h,292h,251h,245h
            dw 2b1h,2a6h,29ah,29eh,282h,26eh,27eh,272h

            dw 4 dup(0ffffh),398h,398h,3a2h,3a2h    ;80h
            dw 5 dup(304h),2c0h,304h,321h

            dw 310h,7 dup(3a2h)
            dw 3ch,60h,37h,39dh,325h,31ch,363h,2b7h

            dw 4 dup(304h),2f8h,2feh,50h,56h
            dw 398h,398h,38ch,392h,2cdh,2d3h,36ch,372h

            dw 8 dup(304h)
            dw 8 dup(304h)

            dw 0,0,357h,357h,2c4h,2bch,304h,304h    ;c0h
            dw 0,0,352h,352h,230h,230h,22bh,237h

            dw 4 dup(0ffffh),2fh,2bh,0,3a7h
            dw 8 dup(0ffffh)

            dw 2d9h,2e0h,2f3h,248h,234h,234h,318h,318h
            dw 37h,3 dup(28eh),234h,234h,318h,318h

            dw 2c8h,0,33dh,338h,219h,4ch,0ffffh,0ffffh
            dw 40h,380h,48h,388h,44h,384h,0ffffh,0ffffh

INnib    proc            ;輸WANTSZ個nibble到charbuf

INnib0:    mov    ah,9        ;提示
        int    21h        

        push dx

        inc    ah            ;0a是緩衝輸入
        lea    dx,bufsz
        int    21h

        pop dx

        cmp    charcnt,WANTSZ
        jnz    INnib0

        xor    bx,bx        ;bx收nibble
        lea    si,charbuf

INnib1:    test    charcnt,0ffh
        jz        INnib2

        lodsb

        mov    cx,RADIX
        lea di,hextbl
        repne scasb
        jnz INnib0

        inc    cx            ;轉'[0-9a-f]'為0~15
        sub    cx,RADIX1
        neg    cx

        xchg ch,cl
        shl    bx,cl

        or bl,ch

        dec    charcnt
        jmp short INnib1

INnib2:    ret
INnib    endp

regasc    proc
regasc1:lodsw

        axasc

        dec dh
        jz regasc2

        mov al,dl
        cbw

        add di,ax        ;跳到AX=1234 BX=5678的5
        jmp regasc1

regasc2:ret
regasc    endp

i1:        mov cs:i?,1*4
        jmp    sv

i3:        mov cs:i?,3*4
        jmp    sv

i22:    cmp    cs:i?,22h*4
        jnz i22_1
        jmp myend            ;被調試進程psp,已被comexe用4ch終止

i22_1:    mov cs:i?,22h*4
        jmp sv

i23:    mov cs:i?,23h*4
        add sp,3*2    ;sp指向鍵盤中斷服務程序調用中斷23h那條指令後麵的ip,
                    ;加6後,指向被調試程序中,能檢ctl中斷的int指令後麵的ip

sv:        mov cs:cax,ax        ;保存reg
        mov cs:cbx,bx
        mov cs:ccx,cx
        mov cs:cdx,dx
        mov cs:cbp,bp
        mov cs:csi,si
        mov cs:cdi,di
        mov cs:cds,ds
        mov cs:ces,es
        mov cs:css,ss

        pop bx                ;進i1,i3,i22,i23前的ip,cs,F到bx,es,cf
        pop es
        pop cs:cf

        mov cs:csp,sp        ;保存真實的csp

        cmp cs:i?,3*4        ;中斷3的ip要減1
        jnz sv1

        dec    bx

sv1:    mov ax,cs:i?
        and ax,12
        
        cmp ax,12            ;中斷3,23h,恢複斷點
        jnz sv_ccs

        mov ax,cs:brkseg
        mov ds,ax

        mov di,cs:brkoff

        mov al,cs:brkval
        mov ds:[di],al

sv_ccs:    mov ax,es

        cmp cs:ccs,ax
        jz sv_cip

        mov cs:ccs,ax        ;ccs僅此時修改

        cmp cs:i?,1*4        ;僅處理命令t跨段
        jnz sv_cip

        cmp cs:chkgap,36    ;查跨段?
        jnz sv_cip

        mov ax,cs:cip        ;保存引起跨段的cip
        mov cs:w15,ax

        mov cs:$_32,32        ;置跨段標記為空格

sv_cip:    mov cs:cip,bx

        xor ax,ax
        mov ds,ax

        mov dx,cs:off23            ;指回老中斷23h
        mov ds:[23h*4],dx        

        mov dx,cs:seg23
        mov ds:[23h*4+2],dx

        mov di,cs:i?

        mov dx,cs:cf[di]        ;指回老中斷1或3
        mov ds:[di],dx        

        mov dx,cs:cf[di+2]
        mov ds:[di+2],dx

        mov cl,ds:[40h*10h+71h]    ;取ctl-break位

        test cl,80h
        jz sv_cip1

        mov ds:[40h*10h+71h],al    ;清ctl-break位

sv_cip1:not    ax                ;ax為ffff

        cmp cs:steps,ax        ;steps為ffff
        jz myenv

        test cs:steps,ax    ;steps為0
        jz myenv
        
        dec cs:steps

myenv:    mov bp,cs            ;指向comexe

        mov ss,bp
        mov sp,256

        sti                    ;盡早開中斷

        mov ds,bp
        cld                    ;方向,從低到高

        cmp i?,22h*4
        jb myenv1

        mov    steps,0            ;22h,23h中斷,都清步數
        je myenv1
        
        shl cl,1            ;23h,左移cl
        cmc                    ;變反c

        mov ax,962h            ;al為b    
        adc    al,0

        mov c_brk,al

        lea dx,ctl
        int 21h

myenv1:    jmp main

scene   proc            ;顯示現場

        xor bh,bh        ;用於byte0尋址
        mov bl,byte0

        mov si,bx        
                
        mov si,mnemo_idx[bx+si]    ;mnemo_idx是字表,取助記符偏移到si

        cmp si,0ffffh
        jnz scene1

        mov si,3bch                ;浮點指令,反出???

        mov al,x4857_idx[bx]    ;x4857_idx是字節表
        cmp al,255
        jz scene1

        mov bl,byte1        ;尋址方式字節,含mod(2),reg(3),r/m(3)
        and bl,38h        
        shr bl,1
        shr bl,1    

        add bl,al

        mov si,x4857[bx]    ;x4857是字表

scene1:    add si,offset mnemo    ;助記符偏移加上mnemo表頭位置

        mov ax,2020h        
        mov vecasc,ax        ;填空格

        mov    cx,7            ;助記符最長7
        mov di,si

        repnz scasb            ;助記符斷於空格

        push cx
        sub cx,7
        neg cx

        lea di,mne8086        ;傳助記符
        rep movsb

        pop cx
        rep stosb            ;傳空格

        lea    bx,hextbl

        mov al,byte0
        lea di,codeasc        ;操作碼
        alasc

        cmp intsz,2            ;遇int 21h等?
        jnz scene2

        mov al,byte1
        lea di,vecasc        ;中斷號
        alasc

scene2:    mov dx,804h            ;dh是ax到di項數,dl是AX=1234 BX=5678的4,5隔

        lea si,cax            ;si取出預顯數值
        lea di,axdiasc        ;di存放si顯出字符
        call regasc

        mov dh,5            ;ds_ip項數
        lea di,dsipasc
        call regasc

        mov bx,800h            ;從溢出位向右,逐位測試
        lea si,F01
        lea    di,oc

chkbit1:test Fvalid,bx        ;此位有效?
        jz chkbit4

        test cf,bx        
        jz chkbit2

        add si,2            ;此位為1
        lodsw                

        jmp chkbit3

chkbit2:lodsw                ;此位為0
        add si,2

chkbit3:stosw                ;傳2字母
        inc di                ;跳空格
                    
chkbit4:shr bx,1
        jnc chkbit1

        mov    ah,9
        lea dx,.ax
        int 21h                ;顯示現場

        ret
scene   endp

@1:        mov sp,256    ;設26字節comexe堆棧在低區,以釋放尾後內存
        
        lea bx,tail ;comexe內存映像尾
        add bx,15

        rept 4
        shr bx,1    ;字節轉節
        endm

        mov ah,4ah    ;comexe內存始於es節,長bx節
        int 21h        ;釋放comexe尾後的內存

        mov ah,45h    ;複製bx文件句柄到ax
        mov bx,1    ;stdout
        int 21h

        mov oldstd1,ax

        setstd1 2    ;stderr

        mov ah,9
        lea dx,i?;輸入com,exe的8.3名
        int 21h

        mov si,128
        mov byte ptr [si],13;限長:8文件名+點+3擴展名+回車
        mov byte ptr [si+15],(128-26)-15-2
        
        mov ah,10            ;stdin緩衝輸入,存到dx指向
        mov dx,si
        int 21h
        
        xor bh,bh                                    
        mov bl,[si+1]        ;實長
        mov [bx+128+2],bh    ;4b01h要求0結尾

        mov ah,9            ;輸入被調試進程實參,字節數<85
        lea dx,steps        
        int 21h

        mov ah,10
        mov dx,128+15
        int 21h        

        setstd1 oldstd1    

        mov bp,cs            ;bp恒指comexe

        mov paraseg,bp         ;參數串段值

        mov ax,4b01h        ;裝入,而不啟動
        lea bx,w16            ;es:bx指參數塊
        mov dx,128+2        ;ds:dx指程序名
        int 21h
        
        jnc loaded

myend:    mov ah,4ch
        int 21h                ;comexe返到父dos

loaded:    lea    bx,hextbl

        mov    ax,cs            ;cax段
        lea di,caxseg
        axasc

        lea ax,cax            ;cax位移
        lea di,caxoff
        axasc

        mov    ax,3d00h        ;打開,讀
        mov dx,128+2
        int 21h

        mov bx,ax            ;句柄送bx

        mov ax,4202h        ;移指針到文件尾+cx:dx
        xor dx,dx        

        mov es,dx            ;清40:71處ctl-break位
        mov es:[40h*10h+71h],dl

        mov    steps,dx        ;清步數

        xor cx,cx
        int 21h

        mov ccx,ax            ;取指針dx:ax到cbx:ccx
        mov cbx,dx

        mov ah,3eh            ;關閉
        int 21h        

        mov ah,62h            ;取被調試進程psp到bx
        int 21h

        mov cds,bx            ;令cds,ces指向psp
        mov ces,bx

        mov es,bx

        mov es:[10],offset i22 
        mov es:[12],cs        ;置被調試進程psp終止矢量

        add initsp,2        ;4b01h做後,[sp]為0ffff,未裝首字是'ZM'的exe
                            ;文件時,sp為fffc,且[sp+2]為0,使com文件的
                            ;ret指令,返到psp偏移0的int 20h.故初始sp加2
                            
        mov bx,initsp
        mov csp,bx
        
        cmp bx,0fffeh
        jz loaded1

        sub ccx,200h        ;調整exe文件長度
        sbb cbx,0

loaded1:mov bx,initss
        mov css,bx

        mov bx,initcs
        mov ccs,bx

        mov es,bx

        mov bx,initip
        mov cip,bx

main:    mov cx,es:[bx]        ;取es:[bx]操作碼,尋址方式到byte0,byte1
        mov b0_b1,cx
        mov es,bp

        cmp    i?,22h*4
        jne    main0

        lea    bx,hextbl

        mov    ah,4dh            ;取終止信息
        int    21h

        mov dl,ah

        lea di,errlev
        alasc

        mov al,dl
        lea di,type4
        alasc

        mov    ah,9
        lea dx,exitmsg
        int    21h

main0:    mov intsz,2

        cmp cl,0cdh            ;欲進int 21h等
        jz show

        mov intsz,0

        cmp cl,0cch            ;欲進int 3
        jz main1

        cmp cl,0ceh            ;欲進into
        jnz main2

        test cf,800h        ;查溢出位
        jz main2

main1:    and cl,3            ;cc,ce轉為int 3,4
        add cl,6
        shr cl,1

        mov byte1,cl    
        inc intsz

main2:    cmp steps,0ffffh
        jnz show

        cmp $_32,32            ;無盡跟蹤時,查跨段
        jz show

        jmp set1            ;不費顯時

show:    call scene            ;顯示現場

        cmp $_32,32            ;查跨段
        jnz show2

        setstd1 2            ;使輸出可見

        lea bx,hextbl        ;用於alasc
        mov ax,w15            ;顯示跨段處cip
        lea di,w15
        mov dx,di
        axasc

        mov ah,9
        int 21h

        mov $_32,36            ;複原

        mov ah,1            ;等待按鍵
        int 21h

        cmp al,'n'            ;n,從此不查跨段
        jne    show1

        inc chkgap            ;已輸n

show1:    setstd1 oldstd1

show2:    test steps,0ffffh
        jz talk

        jmp trace            ;繼續跟蹤

talk:    setstd1 2

talk1:    mov ah,9
        lea dx,?cmd
        int 21h

        mov ah,1            ;stdin輸入[degt]
        int 21h

        cmp al,'t'
        jne go

t0:        lea dx,?steps        ;輸入步數    
        call INnib            
        or bx,bx            ;非0
        jz t0            

        mov steps,bx

        newline
        setstd1 oldstd1        

        jmp trace

go:     cmp al,'g'
        jnz dump

        lea dx,?seg
        call INnib

        push bx

        lea dx,?off
        call INnib    

        pop es

        makebrk
        newline
        setstd1 oldstd1

        jmp set3

dump:    cmp    al,'d'
        jnz edit

        lea dx,?seg
        call INnib

        push bx

        lea dx,?off
        call INnib    

        pop ds

        mov    cx,16
        mov si,bx
        lea di,w16
        rep movsw        ;取16字

        mov ds,bp

        lea bx,hextbl    ;用於alasc
        mov dx,1001h    ;dh是項數,dl是1234 5678的4,5隔
        lea si,w16
        lea di,w0_w14
        call regasc

        mov ah,9
        lea dx,.w0
        int 21h

        jmp talk1

edit:    cmp al,'e'
        jnz kill

        lea dx,?seg
        call INnib        

        push bx

        lea dx,?off
        call INnib    

        push bx

        lea dx,?val
        call INnib    

        pop di
        pop    es

        mov es:[di],bx    ;換值
        mov es,bp

        jmp talk1

kill:   mov i?,22h*4    ;令被調試進程返到父comexe
        mov ah,4ch            
        int 21h

trace:    test intsz,0ffffh
        jnz faceint
        jmp set1

faceint:cmp ?enter,13
        jnz proceed

        setstd1 2        ;未輸過'n'

        mov ah,9
        lea dx,?enter
        int 21h

        mov ah,1        ;輸入[pn]
        int 21h

        mov w0_w14,al        ;暫存

        newline
        setstd1 oldstd1

        cmp w0_w14,'p'
        jz proceed            ;p,本次不進int

        cmp w0_w14,'n'        ;n,從此不進int
        jnz enter

        inc ?enter            ;已輸n

proceed:mov es,ccs
        mov bx,cip

        add bx,intsz    
        makebrk

set3:    mov di,3*4
        lea dx,i3
        jmp set

enter:    mov ax,intsz
        add ax,cip            ;令ax指向預取指令

        cli
        mov ss,css            ;取被調試進程堆棧
        mov sp,csp
        sti

        push cf                ;模擬進入int的壓棧
        push ccs
        push ax            

        mov csp,sp            ;調整csp

        xor bx,bx
        mov es,bx

        mov bl,byte1        ;因進int 1或3,不能用int功能
        shl bx,1            ;故從0:0取中斷口到es:bx
        shl bx,1

        les bx,es:[bx]

        and cf,not 0200h    ;模擬進入int的關中斷

        mov i?,1*4
        jmp sv_ccs            ;設置ccs:cip

set1:    or cf,100h            ;置自陷位

        mov di,1*4
        lea dx,i1

set:    xor ax,ax
        mov es,ax

        mov ax,es:[di]        ;保存變的老中斷1或3
        mov    cf[di],ax

        mov ax,es:[di+2]
        mov    cf[di+2],ax

        mov es:[di],dx
        mov es:[di+2],cs    ;令中斷1或3,指向i1或i3

        mov ax,es:[23h*4]    ;保存變的老中斷23h
        mov    off23,ax

        mov ax,es:[23h*4+2]
        mov    seg23,ax

        mov es:[23h*4],offset i23
        mov es:[23h*4+2],cs    ;令中斷23h,指向i23

        mov ax,cax        ;恢複被調試進程環境
        mov bx,cbx 
        mov cx,ccx
        mov dx,cdx

        mov bp,cbp
        mov si,csi
        mov di,cdi

        cli                ;防中斷
        mov sp,csp
        mov ss,css
        sti

        mov es,ces
        mov ds,cds

        push cs:cf
        push cs:ccs
        push cs:cip

        iret            ;啟動被調試進程

tail=$
code    ends
        end @

(11) 用comexe.com,重定向I/O,調試2k的debug.exe f.exe用例

comexe <foo.0 >foo.1 2>foo.2

foo.1中,接收u及反出首條指令的兩個片斷是:

AX=0a82 BX=0671 CX=0000 DX=4a36 SP=4a01 BP=0000 SI=0085 DI=0000|cd21
DS=0682 ES=0682 SS=0682 CS=0682 IP=0478 NV UP EI PL ZR NA PE NC|INT    
u

...

AX=4000 BX=0001 CX=0013 DX=2638 SP=49c1 BP=0013 SI=4d6b DI=2638|cd21
DS=0682 ES=0682 SS=0682 CS=0682 IP=292c NV UP EI PL NZ NA PE NC|INT    
1E            PUSH    

foo.2內容是:

com,exe:debug.exe

arg(len<85):f.exe

AX(seg:off=0526:0190) F(????ODITSZ?A?P?C) d(ump word),edit,go,trace:t
steps[0001~fffe,ffff]ffff

0033 gap seg,n(o check):n
proceed,n(ever enter int):n

AX(seg:off=0526:0190) F(????ODITSZ?A?P?C) d(ump word),edit,go,trace:q

輸出到屏幕及foo.1的運行結果,未必一致,如:

mov ah,2    ;輸出dl
mov dl,'0'
int 21h

DEBUG及comexe下,返回的al,對屏幕是30h,對foo.1是1.

(12) 對popf指令的1個注釋

用popf指令,可使自陷位置1,若popf後麵,仍有能使自陷位置1的若幹popf指令,處理器
將在這些popf執行期間,不響應硬件時鍾中斷8.如做:

code    segment
        assume    cs:code,ds:code

        org        100h

start:    jmp        start1

old8    label   dword
old8ip  dw      0
old8cs  dw      0

timer:    sti
        int     21h        ;輸出'0'

        pushf            ;多壓1個字.老中斷8,用彈出3個字的iret結束
        call    old8    ;調用老中斷8,以防死機

        iret

start1:    cli

        mov     ax,3508h    ;取老中斷8
        int        21h

        mov        old8ip,bx
        mov        old8cs,es

        mov        ah,25h        ;令中斷8指向timer
        lea        dx,timer
        int        21h

        mov        ah,2        ;輸出dl
        mov        dl,'0'

        sti

loop1:  pushf                ;取標誌寄存器
        pop        bx

chg:    or        bx,100h        ;自陷位置1
;        or        bx,200h        ;中斷位置1
    
                            ;進入int時,這兩位都被8086清除,可比較

        rept    400            ;入棧400次
        push    bx
        endm

        rept    400            ;彈棧400次
        popf
        endm

        jmp        loop1        ;每次時鍾中斷,都顯'0'

code    ends
        end    start

若隻改chg處的or bx,100h為or bx,200h,對比速度執行,改前的com慢.

作者: 北京信息工程學院 軟件工程研究中心 馬文曉
寫於: 2002.10.22
郵編: 100101
電話: 66188615,64884879
E-MAIL: mawenxiao@biti.edu.cn

最後更新:2017-04-02 00:06:22

  上一篇:go 我用c#寫的串口通訊
  下一篇:go 給串口發送16進製字符串命令和包括16進製命令轉換為字節數組