もう2年になりますでしょうか,「晴れのちおおさわぎ!」(PC-98,カクテル・ソフト)のIPLからの立ち上げ後,起動するADVSHELL.COMの解析を試みておりましたが,ようやく自分としてはこれ以上時間をかけても新たな発見が見込まれないであろうというところまでの作業をすませましたので,とりあえず発表してしまいます。
SYMDEB.EXEでADVSHELL.COMのトレース実行を試みましたが,NP21では,-Tのトレースモードに入ったところで作動停止。T98-Nextでは,トレース実行ができないようで,いきなりプログラムの実行を完了してプログラムに基づくエラー表示。。無償使用できるようになった最新版Anex86では,実機より少し先でやはり作動停止。
そんなわけで,プログラムの流れは完全には検証できていません。
解析結果のフローチャートは以下のとおり。
コメント付きソースは6万字を超えたので,4回くらいに分けないとアップできません・・・。たった2,048バイトのプログラムなのに。私のコメントが過剰なのか?
次の行から,下はコメント付きソースの第1弾。先は長いよ。
なお,SOUCERによる逆アセンブルリストをベースにしています。
seg_a segment byte public
assume cs:seg_a, ds:seg_a
org 100h
ADVSHELL proc far
3B66:0100 start:
3B66:0100 E9 00FD jmp real_start ; (0200)
3B66:0103 00FD[00] db 253 dup (0)
;##########################################################################
;
; External Entry Point
;
;##########################################################################
;レジスタ群初期化
3B66:0200 real_start: ; xref 3B66:0100
3B66:0200 FA cli ; Disable interrupts 外部割込禁止
3B66:0201 8C C8 mov ax,cs ; AX=CS
3B66:0203 8E D8 mov ds,ax ; DS=AX
3B66:0205 8E D0 mov ss,ax ; SS=AX CS=DS=SS
3B66:0207 BC 0200 mov sp,200h ; SP=0200H
3B66:020A FB sti ; Enable interrupts 割込フラグをセット
; 次の命令の最後で、外部割込を可能に。
3B66:020B E8 055C call sub_14 ; (076A)
;##########################################################################
; SUBROUTINE
;
; Called from: 3B66:020B
;##########################################################################
3B66:076A sub_14 proc near
3B66:076A E8 FEB1 call sub_7 ; (061E)
;##########################################################################
; SUBROUTINE
;
; 割込禁止等処理ルーチン~065CH,COPYキー,STOPキー,Ctrl-Cキーの無効化
; 致命的ディスクエラーに対する独自処理?,0514H:0512Hにファンクションコールにシステムコールアドレス確保?
; (MS-DOSシステムコールハンドブック,河西朝雄著,ナツメ社発行,'91/11/11,P.~)
; (MS-DOS エンサイクロペディア Volume2 リファレンス編,マイクロソフトプレス編,株式会社アスキー発行P.~)
; Called from: 3B66:076A
;##########################################################################
3B66:061E sub_7 proc near
3B66:061E FA cli ; Disable interrupts 外部割込禁止
3B66:061F ,BA 031D mov dx,offset int_06h_entry ; DX=031DH
3B66:0622 52 push dx ; DX退避
3B66:0623 B8 2505 mov ax,2505h ; 割込ベクタの設定,割込タイプ番号 05H COPYキー
3B66:0626 CD 21 int 21h ; DOS Services ah=function 25h
; set intrpt vector al to ds:dx
; DS:DX(031DH)=割り込み処理ルーチンのアドレス
; DS:031DH IRET 割込からのリターン命令
; COPYキー割込に何もせずリターン。以下,同様。
3B66:0628 5A pop dx ; DX復帰。DX=031DH
3B66:0629 52 push dx ; DX退避
3B66:062A B8 2506 mov ax,2506h ; 割込ベクタの設定,割込タイプ番号 06H STOPキー
3B66:062D CD 21 int 21h ; DOS Services ah=function 25h
; set intrpt vector al to ds:dx
; DS:DX(031DH)=割り込み処理ルーチンのアドレス
; DS:031DH IRET 割込からのリターン命令
; STOPキー割込に何もせずリターン。
3B66:062F 5A pop dx ; DX復帰。DX=031DH
3B66:0630 B8 2523 mov ax,2523h ; 割込ベクタの設定,割込タイプ番号 23H Ctrl-Cキー
3B66:0633 CD 21 int 21h ; DOS Services ah=function 25h
; set intrpt vector al to ds:dx
; DS:DX(031DH)=割り込み処理ルーチンのアドレス
; DS:031DH IRET 割込からのリターン命令
; Ctrl-Cキー割込に何もせずリターン。
3B66:0635 ,BA 02B6 mov dx,offset int_24h_entry ; DX=02B6H
3B66:0638 B8 2524 mov ax,2524h ; 割込ベクタの設定,割込タイプ番号 24H 致命的ディスクエラー発生
3B66:063B CD 21 int 21h ; DOS Services ah=function 25h
; set intrpt vector al to ds:dx
; DS:DX(02B6H)=割り込み処理ルーチンのアドレス
3B66:063D B8 3521 mov ax,3521h ; 割込ベクタの取得 割込番号 21H システムコール
3B66:0640 CD 21 int 21h ; DOS Services ah=function 35h
; get intrpt vector al in es:bx
; ES:BX=割込ルーチンのアドレス
3B66:0642 89 1E 0512 mov word ptr data_81,bx ; DS:0512Hのアドレスのメモリに割込ハンドルのオフセットアドレスを代入,DS:0512H=BX
3B66:0646 8C 06 0514 mov word ptr data_81+2,es ; DS:0514Hのアドレスのメモリに割込ハンドルのセグメントアドレスを代入,DS:0514H=ES
; 割込ハンドルES:BX=[0514H]:[0512H]
3B66:064A BA 032E mov dx,32Eh ; DX=032EH
3B66:064D ,BB 0084 mov bx,data_2e ; BX=0084H
BB data16 MOV BX,data16 word move data to BX
3B66:0650 2B C0 sub ax,ax ; AX=0000H
3B66:0652 8E C0 mov es,ax ; ES=0000H
3B66:0654 26: 89 17 mov es:[bx],dx ; ES:[0084H]=032EH, 0086:0084は本来のシステムコールアドレス,システムコールの無効化?
3B66:0657 26: 8C 5F 02 mov es:[bx+2],ds ; ES:[0086H]=DS, [0086H]:[0084H]=DS:032EH, 032EHは,PUSHF
3B66:065B FB sti ; Enable interrupts 割込フラグセット,次の命令の最後で割込を可能に
3B66:065C C3 retn
sub_7 endp
;キーバッファ設定
3B66:076D 2B C0 sub ax,ax ; AX=0000H
3B66:076F 8E C0 mov es,ax ; ES=0000H
3B66:0771 26: 80 0E 0500 20 or byte ptr es:[0500H],20h ; 98のワークエリアのセグメント0000H,オフセット0500Hの第5ビットを1にする
; キーバッファオーバーフロー時にビープを鳴らさない設定
; http://www.webtech.co.jp/company/doc/undocumented_mem/memsys.txt
;画面クリア
3B66:0777 ,BA 07A4 mov dx,offset data_96 ; (3B66:07A4='ESC[2J') 画面をクリアし,カーソルをホームに移動
3B66:077A B4 09 mov ah,9 ; 文字列の表示,DS:DX=07A4Hで始まる$までの文字列を画面に表示する
3B66:077C CD 21 int 21h ; DOS Services ah=function 09h
; display char string at ds:dx 1Bはエスケープキーの文字コード
3B66:077E E8 FEDD call sub_8 ; (065E)
;##########################################################################
; SUBROUTINE
; ストリング2000H本ノックルーチン
; Called from: 3B66:077E
;##########################################################################
3B66:065E sub_8 proc near
3B66:065E FC cld ; Clear direction 割込フラグをクリア,外部割込禁止
3B66:065F B8 A000 mov ax,0A000h ; AX=0A000H テキストVRAMセグメント
3B66:0662 8E C0 mov es,ax ; ES=0A000H
3B66:0664 2B FF sub di,di ; DI=0000H
3B66:0666 B8 0020 mov ax,20h ; AX=0020H
3B66:0669 B9 1000 mov cx,1000h ; CX=1000H
3B66:066C F3/ AB rep stosw ; Rep when cx >0 Store ax to es:[di] ES:[DI]から始まるメモリにAXレジスタの内容0020Hをストア
; CXレジスタの回数分1000H回繰り返して終了。0A000:0000HからAXレジスタの内容を1000H回分ストア
; TVRAMに1000H回0020H(2バイト)をストア,終了時DI=2000H
3B66:066E B8 00E1 mov ax,0E1h ; AX=00E1H
3B66:0671 B9 1000 mov cx,1000h ; CX=1000H,終了時DI=4000H
3B66:0674 F3/ AB rep stosw ; Rep when cx >0 Store ax to es:[di] 同上。ただし,ストアされる内容は00E1H
3B66:0676 C3 retn
sub_8 endp
;メーカー名,タイトル表示,プログラム読み込み中表示
3B66:0781 ,BA 07A9 mov dx,07A9H ; (3B66:07A9=' [mAdvShell for ')
3B66:0784 B4 09 mov ah,9 ; 文字列の表示,DS:DXで始まる$までの文字列を画面に表示する
3B66:0786 CD 21 int 21h ; DOS Services ah=function 09h
; display char string at ds:dx
3B66:0788 B4 12 mov ah,12h ; カーソルの表示停止(UNDOCUMENTED 9801/9821,P.65)
3B66:078A CD 18 int 18h ; ROM basic
3B66:078C B0 0F mov al,0Fh ;DISP ENABLE テキストとグラフィック両方の画面表示のON。
; http://www.webtech.co.jp/company/doc/undocumented_mem/io_disp.txt
3B66:078E E6 68 out 68h,al ; port 68h I/O Non-standard
3B66:0790 E8 FF8B call sub_12 ; (071E)
;##########################################################################
; SUBROUTINE
;
; Called from: 3B66:0790
;##########################################################################
;カレントドライブ確認ルーチン
3B66:071E sub_12 proc near
3B66:071E B4 19 mov ah,19h ;Current Disk カレントドライブ番号の取得
3B66:0720 CD 21 int 21h ; DOS Services ah=function 19h
; get default drive al (00H=A:,01H=B:)
3B66:0722 84 C0 test al,al ; ドライブ番号のANDを取る。
3B66:0724 74 1F jz loc_26 ; Jump if zero ドライブAならZF=1になり,0745Hへ
;***********************************************************************************************
;ここからエラー表示
;起動ドライブエラー
3B66:0726 BA 086A mov dx,86Ah ; ドライブAでない場合,DX=086AH
3B66:0729 E8 FAEC call sub_1 ; (0218)
;##########################################################################
; SUBROUTINE
;
; Called from: 3B66:0729 ;異常時文字列表示ルーチン
;##########################################################################
3B66:0218 sub_1 proc near
3B66:0218 loc_1: ; xref 3B66:0254
3B66:0218 E8 0069 call sub_3 ; (0284) エラー文字列表示ルーチンへ
;##########################################################################
; SUBROUTINE
;
; Called from: 3B66:0218 ;起動ドライブ違いエラールーチン
;##########################################################################
3B66:0284 sub_3 proc near
3B66:0284 B4 09 mov ah,9 ; DX=086AHで飛んできた。文字列 'ドライブA:から起動しなおしてください。'
3B66:0286 CD 21 int 21h ; DOS Services ah=function 09h 文字列の表示,DS:DXから$までの文字列を画面に表示
; display char string at ds:dx
3B66:0288 loc_10: ; xref 3B66:028A
3B66:0288 ,FA cli ; Disable interrupts 外部割込禁止
3B66:0289 F4 hlt ; Halt processor 割込がかかるまでCPUを停止させる
3B66:028A EB FC jmp short loc_10 ; (0288)
sub_3 endp
3B66:021B 90 nop
3B66:021C loc_2: ; xref 3B66:021C
3B66:021C EB FE jmp short loc_2 ; (021C) 無限ループ
sub_1 endp
;以上,エラー表示終了
;**********************************************************************************************
;カレントドライブAのときここへ
3B66:0745 loc_26: ; xref 3B66:0724
3B66:0745 E8 FF30 call sub_9 ; (0678) ドライブAからの起動確認後ここに来た。AL=00H確認ずみ。
;##########################################################################
; SUBROUTINE
;
; Called from: 3B66:0745
;##########################################################################
3B66:0678 sub_9 proc near
3B66:0678 E8 00D5 call sub_13 ; (0750)
;##########################################################################
; SUBROUTINE
;
; Called from: 3B66:0678, 074C ;ディスクリザルト,ディスクリセット+ディスク確認呼出ルーチン
;##########################################################################
3B66:0750 sub_13 proc near
3B66:0750 2B C0 sub ax,ax ; AX=0000H
3B66:0752 8E C0 mov es,ax ; ES=0000H
3B66:0754 BB 0564 mov bx,0564 ; BX=0564H
3B66:0757 B0 C0 mov al,0C0h ; AX=00C0H
3B66:0759 B9 0004 mov cx,4 ; CX=0004H カウンタを4回にセット
3B66:075C locloop_27: ; xref 3B66:0762
3B66:075C 26: 08 07 or es:[bx],al ; DISK RESULT
; 98のワークエリア0000H:0564Hの第6,7ビットを1にする。
; 第1FDDのInterrupt Codeの0と1をセット。
; http://www.webtech.co.jp/company/doc/undocumented_mem/memsys.txt
3B66:075F 83 C3 08 add bx,8 ; BX=056CH
3B66:0762 E2 F8 loop locloop_27 ; Loop if cx > 0
;(ループ内容)
;残り3回
3B66:075C 260807 OR ES:[BX],AL ; 98のワークエリア0000H:056CHの第6,7ビットを1にする。
; 第2FDDのInterrupt Codeの0と1をセット。
3B66:075F 83C308 ADD BX,0008H ; BX=0574H
3B66:0762 E2F8 LOOP 075CH ; CXの値を1減じて0でなければ065CHへ。CX=0002H。
;残り2回
3B66:075C 260807 OR ES:[BX],AL ; 98のワークエリア0000H:0574Hの第6,7ビットを1にする。
; 第3FDDのInterrupt Codeの0と1をセット。
3B66:075F 83C308 ADD BX,0008H ; BX=057CH
3B66:0762 E2F8 LOOP 075CH ; CXの値を1減じて0でなければ065CHへ。CX=0001H。
;残り1回
3B66:075C 260807 OR ES:[057C],AL ; 98のワークエリア0000H:057CHの第6,7ビットを1にする。
; 第4FDDのInterrupt Codeの0と1をセット。
3B66:075F 83C308 ADD BX,0008H ; BX=0584H
3B66:0762 E2F8 LOOP 075CH ; CXの値を1減じて0なので無視。CX=0000H。
3B66:0764 B4 0D mov ah,0Dh ; Disk Reset ディスクのリセット
3B66:0766 CD 21 int 21h ; DOS Services ah=function 0Dh 全ファイルバッファの内容をディスクに書き出し,
; flush disk buffers to disk ファイルバッファを空にする。(DOS6.2PRM P.61)
3B66:0768 C3 retn ; AX=0D0CH
sub_13 endp
3B66:067B 2A C0 sub al,al ;AX=0D00H
3B66:067D E8 006A call sub_11 ; (06EA)
;##########################################################################
; SUBROUTINE(ソーサーが作ってくれなかったサブルーチン)
;
; Called from: 3B66:067D ; ディスク確認ルーチン
;##########################################################################
;ドライブAディスク確認ルーチン~057D,AX=0D00H
3B66:06EA 1E PUSH DS
3B66:06EB 07 POP ES ; DS=ES
3B66:06EC 50 PUSH AX ; AX退避,AX=0D00H。
3B66:06ED 8AE0 MOV AH,AL ; AX=0000H。
3B66:06EF 054160 ADD AX,6041H ; AX=6041H。
3B66:06F2 88269F08 MOV [089FH],AH ; DS:[089FH]=60H 'A' ; [089FH]のメモリに全角Aの文字コードを入力した
3B66:06F6 A2FA08 MOV [08FAH],AL ; DS:[08FAH]=41H 'A' ; [08FAH]のメモリに半角Aの文字コードを入力した
3B66:06F9 58 POP AX ; AX=0D00H ; AX復帰。AX=0D00H
3B66:06FA BB0009 MOV BX,0900H ; BX=0900H
3B66:06FD 8BFB MOV DI,BX ; DI=0900H
3B66:06FF B90100 MOV CX,0001H ; CX=0001H
3B66:0702 BA0300 MOV DX,0003H : DX=0003H
3B66:0705 57 PUSH DI ; DI退避
3B66:0706 CD25 INT 25H ; Absolute disk read, drive al
; if disk under 32MB, dx=start
; cx=#sectors, ds:bx=buffer
; else cx=-1, ds:dx=parm block
; (MS-DOS エンサイクロペディア Volume2 リファレンス編,マイクロソフトプレス編,株式会社アスキー発行P.813~)
; (応用MS-DOS改訂新版,村瀬康治著,株式会社アスキー発行,'89/12/31,P189~)
; (MS-DOSシステムコールハンドブック,河西朝雄著,ナツメ社発行,'91/11/11,P.60~)
; ftp://ftp.abk.nu/pub/text/dos/msdos.txt
; 物理セクタ番号によるディスク読み出し
; AL=ドライブ番号(A:=00H,B:=01H,,,),AL=00HなのでA:
; BX=ディスク転送アドレスのオフセット,読み出すデータの先頭アドレス DS:BX=DS:0900H
; 読み出すセクタ数 CX=0001H 1セクタ
; 読み出しを開始する相対的(論理)セクタ番号 DX=003H 3セクタ
; ディレクトリ領域を正常に読めればCF=0
; セグメントレジスタ(CS,SS,DS,ES)以外の全てのレジスタ破壊。
; フラグはスタックに積まれる(PUSHF)ので,終了後はPOPFまたはADD SP,2。
; ディスク操作が正しく行われるとCF=0
; DS:0900Hに論理セクタ番号3(ディレクトリエントリ)のデータ'ハレノチオオサワギA)',00H*4以下がロードされた。
3B66:0708 58 POP AX ; フラグレジスタをAXに載せる
3B66:0709 5F POP DI ; DI=0900H
3B66:070A BAFFFF MOV DX,0FFFFH ; DX=0FFFFH
3B66:070D 720C JC 071BH ; Jump if carry Set,CF=1(正常に読めない)なら071BHへ。
3B66:070F BEF008 MOV SI,08F0H ; ADVSHELL.COMの[08F0H]には,
; 'ハレノチオオサワギA)',00H*4が書かれている。
;[SI]=CA DA C9 C1 B5 B5 BB DC B7 DE 41 29 00 00 00 00
3B66:0712 B90800 MOV CX,0008H ;
3B66:0715 FC CLD ;ディレクションフラグを0(増加)にリセット
3B66:0716 F3/ A7 repe cmpsw ; Rep zf=1+cx >0 Cmp [si] to es:[di] ; ZF=1で,かつCXが0でない間CXを1減じつつCMPSWを繰り返す。
; ES=DS:[DI]とDS:[SI] にある一致していないワードを探す。
; データブロックの比較
; DS:[SI]とES:[DI]で示されるメモリをワード値で比較し,
; SIとDIの値を2増加させる。8ワード分比較する。
; ES:[DI]には論理セクタ番号3(ディレクトリエントリ)
; 先頭データ'ハレノチオオサワギA)',00H*4が格納されているので一致する
3B66:0718 7501 JNE 071BH ; Jump if not zero, ZF=0(不一致)なら071BHへ
;**********************************************************************************************
;正常時処理
3B66:071A 42 INC DX ; DX=0000H,ZF=1
;エラー時は1行飛ばし 3B66:071B 8BC2 MOV AX,DX ; 正常時AX=0000H,ZF=1,エラー時AX=0FFFFH,ZF=0
3B66:071D C3 RET ;
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3B66:0680 85 C0 test ax,ax ; AX=0000HならZF=1,エラー時AX=0FFFFHなのでZF=0
3B66:0682 75 05 jnz 0689H ; Jump if not zero ZF=0ならRET直行
3B66:0684 B0 01 mov al,1 ; ZF=1(一致)なら,AL=01H。AX=0001H。
3B66:0686 E8 0061 call sub_11 ; (06EA) Bディスク確認ルーチンへ。
;ドライブBディスク確認ルーチン
以下,第2弾へ。
3B66:06EA 1E PUSH DS ;
3B66:06EB 07 POP ES ; DS=ES
3B66:06EC 50 PUSH AX ; AX退避,AX=0001H。
3B66:06ED 8AE0 MOV AH,AL ; AX=0101H
3B66:06EF 054160 ADD AX,6041H ; AX=6142H
3B66:06F2 88269F08 MOV [089FH],AH ; DS:[089FH]=61H 'B'
3B66:06F6 A2FA08 MOV [08FAH],AL ; DS:[08FAH]=42H 'B'
3B66:06F9 58 POP AX ; AX=0001H
3B66:06FA BB0009 MOV BX,0900H ; BX=0900H
3B66:06FD 8BFB MOV DI,BX ; DI=0900H, 読み出したデータの先頭アドレス
3B66:06FF B90100 MOV CX,0001H ; CX=0001H, 1セクタ読み出し
3B66:0702 BA0300 MOV DX,0003H : DX=0003H, 論理セクタ3(ディレクトリエントリ)のデータ
3B66:0705 57 PUSH DI ; DI退避
3B66:0706 CD25 INT 25H ; アブソリュートディスクリード
; AL=ドライブ番号(A:=00H,B:=01H,,,),AL=01HなのでB:
3B66:0708 58 POP AX ; フラグレジスタをAXに載せる
3B66:0709 5F POP DI ; DI=0900H
3B66:070A BAFFFF MOV DX,0FFFFH ; DX=0FFFFH
3B66:070D 720C JB 071BH ; CF=1(正常に読めない)なら071BHへ。
3B66:070F BEF008 MOV SI,08F0H ; DS:[08F0H]には,'ハレノチオオサワギB)',00H*4が書かれている。
; 06F6HでA→Bに書き換えずみ
; [SI]=CA DA C9 C1 B5 B5 BB DC B7 DE 42 29 00 00 00 00
3B66:0712 B90800 MOV CX,0008H ;
3B66:0715 FC CLD ; ディレクションフラグを0(増加)にリセットした。
3B66:0716 F3/ A7 repe cmpsw ; Rep zf=1+cx >0 Cmp [si] to es:[di]
; ZF=1で,かつCXが0でない間CXを1減じつつCMPSWを繰り返す。
; ES:[DI]とDS:[SI] にある一致していないワードを探す。
; データブロックの比較
; DS:[SI]とES:[DI]で示されるメモリをワード値で比較し,
; SIとDIの値を2増加させる。8ワード分比較する。
; ES:[DI]には論理セクタ番号3(ディレクトリエントリ)
; 先頭データ'ハレノチオオサワギB)',00H*4が格納されている。
3B66:0718 7501 JNE 071BH ; ZF=0(データ不一致)なら071BHへ。DX=0FFFFH
3B66:071A 42 INC DX ; DX=0000H
3B66:071B 8BC2 MOV AX,DX ; AX=0000H,ZF=1,0718Hから来たときは,AX=0FFFFH,ZF=0
3B66:071D C3 RET ; 0689Hへ復帰。
3B66:0689 loc_ret_22: ; xref 3B66:0682
3B66:0689 C3 retn
sub_9 endp
3B66:0748 85 C0 test ax,ax ; AX=0000Hなので,ZF=1
3B66:074A 75 E0 jnz 072CH ; Jump if not zero ,ZF=1なのでスルー
; エラー時は072CHへ
;**********************************************************************************************
エラー時表示ルーチン
3B66:072C loc_25: ; xref 3B66:074A
3B66:072C ,BA 0896 mov dx,0896h ;'ドライブA:のディスクを確認してください。$'
3B66:072F B4 09 mov ah,9 ; Bディスク確認エラーなら06F2Hで089FHをAからBに書き換えずみ
3B66:0731 CD 21 int 21h ; DOS Services ah=function 09h 文字列の表示
; display char string at ds:dx DXを先頭アドレスとする$までの文字列
3B66:0733 B4 11 mov ah,11h ; カーソルの表示開始(UND P.65)
3B66:0735 CD 18 int 18h ; ROM basic
3B66:0737 E8 FBE4 call sub_6 ; (031E)キー入力確認ルーチンへ
;キー入力確認ルーチン~0637H
3B66:031E B401 MOV AH,01H ;キーバッファ状態のセンス 出力 BH=00 キー入力データなし
3B66:0320 CD18 INT 18H ;(UNDOCUMENTED 9801/9821,P.41) BH=01 キー入力データあり
;AH=キーコード,AL=キーデータ
;キーバッファにキー入力データがなければすぐに終了する。
3B66:0322 53 PUSH BX ;BX=BH00H
3B66:0323 B400 MOV AH,00H ;キーデータの読み出し(1文字の入力待ち)
3B66:0325 CD18 INT 18H ;(UNDOCUMENTED 9801/9821,P.40) AH=キーコード,AL=キーデータ
;入力を待つので進まない。
3B66:0327 5B POP BX ;BX=BH00H
3B66:0328 84FF TEST BH,BH ;キー入力なしならZF=1,キー入力ありZF=0
3B66:032A 75F2 JNE 021EH ;キー入力あり(ZF=0)なら,021EHへ。無限ループ?
3B66:032C C3 RET ;
3B66:073A B4 12 mov ah,12h ; カーソルの表示停止
3B66:073C CD 18 int 18h ; ROM basic,(UNDOCUMENTED 9801/9821 小高輝真・河野健著 株式会社インプレス発行 '94/03/21,P.65)
3B66:073E ,BA 08C2 mov dx,08C2h ; (3B66:08C2='全角スペース21個',0DH,'$')
3B66:0741 B4 09 mov ah,9 ; '$'検出までの文字列の表示
3B66:0743 CD 21 int 21h ; DOS Services ah=function 09h
; display char string at ds:dx
エラー時表示ルーチン終了
;**********************************************************************************************
3B66:074C E8 0001 call sub_13 ; (0750)
以下,晴れのちおおさわぎ!(PC-98,カクテル・ソフト)ADVSHELL.COM解析(その2)に続く。
晴れのちおおさわぎ!(PC-98,カクテル・ソフト)ADVSHELL.COM解析(その3)はこちら。
<<著作権に関して>>
本記事に引用している全てのソフトの名称・画像の著作権・その他権利は、制作、販売されたソフトハウス、メーカー、または作者様に帰属します。本サイトでの上記著作物の取扱いは、著作権など各権利関係を侵害することが目的ではありません。問題などある場合は、メール(gekigangarあっとmail.goo.ne.jp)にてその旨お知らせください。
SYMDEB.EXEでADVSHELL.COMのトレース実行を試みましたが,NP21では,-Tのトレースモードに入ったところで作動停止。T98-Nextでは,トレース実行ができないようで,いきなりプログラムの実行を完了してプログラムに基づくエラー表示。。無償使用できるようになった最新版Anex86では,実機より少し先でやはり作動停止。
そんなわけで,プログラムの流れは完全には検証できていません。
解析結果のフローチャートは以下のとおり。
コメント付きソースは6万字を超えたので,4回くらいに分けないとアップできません・・・。たった2,048バイトのプログラムなのに。私のコメントが過剰なのか?
次の行から,下はコメント付きソースの第1弾。先は長いよ。
なお,SOUCERによる逆アセンブルリストをベースにしています。
seg_a segment byte public
assume cs:seg_a, ds:seg_a
org 100h
ADVSHELL proc far
3B66:0100 start:
3B66:0100 E9 00FD jmp real_start ; (0200)
3B66:0103 00FD[00] db 253 dup (0)
;##########################################################################
;
; External Entry Point
;
;##########################################################################
;レジスタ群初期化
3B66:0200 real_start: ; xref 3B66:0100
3B66:0200 FA cli ; Disable interrupts 外部割込禁止
3B66:0201 8C C8 mov ax,cs ; AX=CS
3B66:0203 8E D8 mov ds,ax ; DS=AX
3B66:0205 8E D0 mov ss,ax ; SS=AX CS=DS=SS
3B66:0207 BC 0200 mov sp,200h ; SP=0200H
3B66:020A FB sti ; Enable interrupts 割込フラグをセット
; 次の命令の最後で、外部割込を可能に。
3B66:020B E8 055C call sub_14 ; (076A)
;##########################################################################
; SUBROUTINE
;
; Called from: 3B66:020B
;##########################################################################
3B66:076A sub_14 proc near
3B66:076A E8 FEB1 call sub_7 ; (061E)
;##########################################################################
; SUBROUTINE
;
; 割込禁止等処理ルーチン~065CH,COPYキー,STOPキー,Ctrl-Cキーの無効化
; 致命的ディスクエラーに対する独自処理?,0514H:0512Hにファンクションコールにシステムコールアドレス確保?
; (MS-DOSシステムコールハンドブック,河西朝雄著,ナツメ社発行,'91/11/11,P.~)
; (MS-DOS エンサイクロペディア Volume2 リファレンス編,マイクロソフトプレス編,株式会社アスキー発行P.~)
; Called from: 3B66:076A
;##########################################################################
3B66:061E sub_7 proc near
3B66:061E FA cli ; Disable interrupts 外部割込禁止
3B66:061F ,BA 031D mov dx,offset int_06h_entry ; DX=031DH
3B66:0622 52 push dx ; DX退避
3B66:0623 B8 2505 mov ax,2505h ; 割込ベクタの設定,割込タイプ番号 05H COPYキー
3B66:0626 CD 21 int 21h ; DOS Services ah=function 25h
; set intrpt vector al to ds:dx
; DS:DX(031DH)=割り込み処理ルーチンのアドレス
; DS:031DH IRET 割込からのリターン命令
; COPYキー割込に何もせずリターン。以下,同様。
3B66:0628 5A pop dx ; DX復帰。DX=031DH
3B66:0629 52 push dx ; DX退避
3B66:062A B8 2506 mov ax,2506h ; 割込ベクタの設定,割込タイプ番号 06H STOPキー
3B66:062D CD 21 int 21h ; DOS Services ah=function 25h
; set intrpt vector al to ds:dx
; DS:DX(031DH)=割り込み処理ルーチンのアドレス
; DS:031DH IRET 割込からのリターン命令
; STOPキー割込に何もせずリターン。
3B66:062F 5A pop dx ; DX復帰。DX=031DH
3B66:0630 B8 2523 mov ax,2523h ; 割込ベクタの設定,割込タイプ番号 23H Ctrl-Cキー
3B66:0633 CD 21 int 21h ; DOS Services ah=function 25h
; set intrpt vector al to ds:dx
; DS:DX(031DH)=割り込み処理ルーチンのアドレス
; DS:031DH IRET 割込からのリターン命令
; Ctrl-Cキー割込に何もせずリターン。
3B66:0635 ,BA 02B6 mov dx,offset int_24h_entry ; DX=02B6H
3B66:0638 B8 2524 mov ax,2524h ; 割込ベクタの設定,割込タイプ番号 24H 致命的ディスクエラー発生
3B66:063B CD 21 int 21h ; DOS Services ah=function 25h
; set intrpt vector al to ds:dx
; DS:DX(02B6H)=割り込み処理ルーチンのアドレス
3B66:063D B8 3521 mov ax,3521h ; 割込ベクタの取得 割込番号 21H システムコール
3B66:0640 CD 21 int 21h ; DOS Services ah=function 35h
; get intrpt vector al in es:bx
; ES:BX=割込ルーチンのアドレス
3B66:0642 89 1E 0512 mov word ptr data_81,bx ; DS:0512Hのアドレスのメモリに割込ハンドルのオフセットアドレスを代入,DS:0512H=BX
3B66:0646 8C 06 0514 mov word ptr data_81+2,es ; DS:0514Hのアドレスのメモリに割込ハンドルのセグメントアドレスを代入,DS:0514H=ES
; 割込ハンドルES:BX=[0514H]:[0512H]
3B66:064A BA 032E mov dx,32Eh ; DX=032EH
3B66:064D ,BB 0084 mov bx,data_2e ; BX=0084H
BB data16 MOV BX,data16 word move data to BX
3B66:0650 2B C0 sub ax,ax ; AX=0000H
3B66:0652 8E C0 mov es,ax ; ES=0000H
3B66:0654 26: 89 17 mov es:[bx],dx ; ES:[0084H]=032EH, 0086:0084は本来のシステムコールアドレス,システムコールの無効化?
3B66:0657 26: 8C 5F 02 mov es:[bx+2],ds ; ES:[0086H]=DS, [0086H]:[0084H]=DS:032EH, 032EHは,PUSHF
3B66:065B FB sti ; Enable interrupts 割込フラグセット,次の命令の最後で割込を可能に
3B66:065C C3 retn
sub_7 endp
;キーバッファ設定
3B66:076D 2B C0 sub ax,ax ; AX=0000H
3B66:076F 8E C0 mov es,ax ; ES=0000H
3B66:0771 26: 80 0E 0500 20 or byte ptr es:[0500H],20h ; 98のワークエリアのセグメント0000H,オフセット0500Hの第5ビットを1にする
; キーバッファオーバーフロー時にビープを鳴らさない設定
; http://www.webtech.co.jp/company/doc/undocumented_mem/memsys.txt
;画面クリア
3B66:0777 ,BA 07A4 mov dx,offset data_96 ; (3B66:07A4='ESC[2J') 画面をクリアし,カーソルをホームに移動
3B66:077A B4 09 mov ah,9 ; 文字列の表示,DS:DX=07A4Hで始まる$までの文字列を画面に表示する
3B66:077C CD 21 int 21h ; DOS Services ah=function 09h
; display char string at ds:dx 1Bはエスケープキーの文字コード
3B66:077E E8 FEDD call sub_8 ; (065E)
;##########################################################################
; SUBROUTINE
; ストリング2000H本ノックルーチン
; Called from: 3B66:077E
;##########################################################################
3B66:065E sub_8 proc near
3B66:065E FC cld ; Clear direction 割込フラグをクリア,外部割込禁止
3B66:065F B8 A000 mov ax,0A000h ; AX=0A000H テキストVRAMセグメント
3B66:0662 8E C0 mov es,ax ; ES=0A000H
3B66:0664 2B FF sub di,di ; DI=0000H
3B66:0666 B8 0020 mov ax,20h ; AX=0020H
3B66:0669 B9 1000 mov cx,1000h ; CX=1000H
3B66:066C F3/ AB rep stosw ; Rep when cx >0 Store ax to es:[di] ES:[DI]から始まるメモリにAXレジスタの内容0020Hをストア
; CXレジスタの回数分1000H回繰り返して終了。0A000:0000HからAXレジスタの内容を1000H回分ストア
; TVRAMに1000H回0020H(2バイト)をストア,終了時DI=2000H
3B66:066E B8 00E1 mov ax,0E1h ; AX=00E1H
3B66:0671 B9 1000 mov cx,1000h ; CX=1000H,終了時DI=4000H
3B66:0674 F3/ AB rep stosw ; Rep when cx >0 Store ax to es:[di] 同上。ただし,ストアされる内容は00E1H
3B66:0676 C3 retn
sub_8 endp
;メーカー名,タイトル表示,プログラム読み込み中表示
3B66:0781 ,BA 07A9 mov dx,07A9H ; (3B66:07A9=' [mAdvShell for ')
3B66:0784 B4 09 mov ah,9 ; 文字列の表示,DS:DXで始まる$までの文字列を画面に表示する
3B66:0786 CD 21 int 21h ; DOS Services ah=function 09h
; display char string at ds:dx
3B66:0788 B4 12 mov ah,12h ; カーソルの表示停止(UNDOCUMENTED 9801/9821,P.65)
3B66:078A CD 18 int 18h ; ROM basic
3B66:078C B0 0F mov al,0Fh ;DISP ENABLE テキストとグラフィック両方の画面表示のON。
; http://www.webtech.co.jp/company/doc/undocumented_mem/io_disp.txt
3B66:078E E6 68 out 68h,al ; port 68h I/O Non-standard
3B66:0790 E8 FF8B call sub_12 ; (071E)
;##########################################################################
; SUBROUTINE
;
; Called from: 3B66:0790
;##########################################################################
;カレントドライブ確認ルーチン
3B66:071E sub_12 proc near
3B66:071E B4 19 mov ah,19h ;Current Disk カレントドライブ番号の取得
3B66:0720 CD 21 int 21h ; DOS Services ah=function 19h
; get default drive al (00H=A:,01H=B:)
3B66:0722 84 C0 test al,al ; ドライブ番号のANDを取る。
3B66:0724 74 1F jz loc_26 ; Jump if zero ドライブAならZF=1になり,0745Hへ
;***********************************************************************************************
;ここからエラー表示
;起動ドライブエラー
3B66:0726 BA 086A mov dx,86Ah ; ドライブAでない場合,DX=086AH
3B66:0729 E8 FAEC call sub_1 ; (0218)
;##########################################################################
; SUBROUTINE
;
; Called from: 3B66:0729 ;異常時文字列表示ルーチン
;##########################################################################
3B66:0218 sub_1 proc near
3B66:0218 loc_1: ; xref 3B66:0254
3B66:0218 E8 0069 call sub_3 ; (0284) エラー文字列表示ルーチンへ
;##########################################################################
; SUBROUTINE
;
; Called from: 3B66:0218 ;起動ドライブ違いエラールーチン
;##########################################################################
3B66:0284 sub_3 proc near
3B66:0284 B4 09 mov ah,9 ; DX=086AHで飛んできた。文字列 'ドライブA:から起動しなおしてください。'
3B66:0286 CD 21 int 21h ; DOS Services ah=function 09h 文字列の表示,DS:DXから$までの文字列を画面に表示
; display char string at ds:dx
3B66:0288 loc_10: ; xref 3B66:028A
3B66:0288 ,FA cli ; Disable interrupts 外部割込禁止
3B66:0289 F4 hlt ; Halt processor 割込がかかるまでCPUを停止させる
3B66:028A EB FC jmp short loc_10 ; (0288)
sub_3 endp
3B66:021B 90 nop
3B66:021C loc_2: ; xref 3B66:021C
3B66:021C EB FE jmp short loc_2 ; (021C) 無限ループ
sub_1 endp
;以上,エラー表示終了
;**********************************************************************************************
;カレントドライブAのときここへ
3B66:0745 loc_26: ; xref 3B66:0724
3B66:0745 E8 FF30 call sub_9 ; (0678) ドライブAからの起動確認後ここに来た。AL=00H確認ずみ。
;##########################################################################
; SUBROUTINE
;
; Called from: 3B66:0745
;##########################################################################
3B66:0678 sub_9 proc near
3B66:0678 E8 00D5 call sub_13 ; (0750)
;##########################################################################
; SUBROUTINE
;
; Called from: 3B66:0678, 074C ;ディスクリザルト,ディスクリセット+ディスク確認呼出ルーチン
;##########################################################################
3B66:0750 sub_13 proc near
3B66:0750 2B C0 sub ax,ax ; AX=0000H
3B66:0752 8E C0 mov es,ax ; ES=0000H
3B66:0754 BB 0564 mov bx,0564 ; BX=0564H
3B66:0757 B0 C0 mov al,0C0h ; AX=00C0H
3B66:0759 B9 0004 mov cx,4 ; CX=0004H カウンタを4回にセット
3B66:075C locloop_27: ; xref 3B66:0762
3B66:075C 26: 08 07 or es:[bx],al ; DISK RESULT
; 98のワークエリア0000H:0564Hの第6,7ビットを1にする。
; 第1FDDのInterrupt Codeの0と1をセット。
; http://www.webtech.co.jp/company/doc/undocumented_mem/memsys.txt
3B66:075F 83 C3 08 add bx,8 ; BX=056CH
3B66:0762 E2 F8 loop locloop_27 ; Loop if cx > 0
;(ループ内容)
;残り3回
3B66:075C 260807 OR ES:[BX],AL ; 98のワークエリア0000H:056CHの第6,7ビットを1にする。
; 第2FDDのInterrupt Codeの0と1をセット。
3B66:075F 83C308 ADD BX,0008H ; BX=0574H
3B66:0762 E2F8 LOOP 075CH ; CXの値を1減じて0でなければ065CHへ。CX=0002H。
;残り2回
3B66:075C 260807 OR ES:[BX],AL ; 98のワークエリア0000H:0574Hの第6,7ビットを1にする。
; 第3FDDのInterrupt Codeの0と1をセット。
3B66:075F 83C308 ADD BX,0008H ; BX=057CH
3B66:0762 E2F8 LOOP 075CH ; CXの値を1減じて0でなければ065CHへ。CX=0001H。
;残り1回
3B66:075C 260807 OR ES:[057C],AL ; 98のワークエリア0000H:057CHの第6,7ビットを1にする。
; 第4FDDのInterrupt Codeの0と1をセット。
3B66:075F 83C308 ADD BX,0008H ; BX=0584H
3B66:0762 E2F8 LOOP 075CH ; CXの値を1減じて0なので無視。CX=0000H。
3B66:0764 B4 0D mov ah,0Dh ; Disk Reset ディスクのリセット
3B66:0766 CD 21 int 21h ; DOS Services ah=function 0Dh 全ファイルバッファの内容をディスクに書き出し,
; flush disk buffers to disk ファイルバッファを空にする。(DOS6.2PRM P.61)
3B66:0768 C3 retn ; AX=0D0CH
sub_13 endp
3B66:067B 2A C0 sub al,al ;AX=0D00H
3B66:067D E8 006A call sub_11 ; (06EA)
;##########################################################################
; SUBROUTINE(ソーサーが作ってくれなかったサブルーチン)
;
; Called from: 3B66:067D ; ディスク確認ルーチン
;##########################################################################
;ドライブAディスク確認ルーチン~057D,AX=0D00H
3B66:06EA 1E PUSH DS
3B66:06EB 07 POP ES ; DS=ES
3B66:06EC 50 PUSH AX ; AX退避,AX=0D00H。
3B66:06ED 8AE0 MOV AH,AL ; AX=0000H。
3B66:06EF 054160 ADD AX,6041H ; AX=6041H。
3B66:06F2 88269F08 MOV [089FH],AH ; DS:[089FH]=60H 'A' ; [089FH]のメモリに全角Aの文字コードを入力した
3B66:06F6 A2FA08 MOV [08FAH],AL ; DS:[08FAH]=41H 'A' ; [08FAH]のメモリに半角Aの文字コードを入力した
3B66:06F9 58 POP AX ; AX=0D00H ; AX復帰。AX=0D00H
3B66:06FA BB0009 MOV BX,0900H ; BX=0900H
3B66:06FD 8BFB MOV DI,BX ; DI=0900H
3B66:06FF B90100 MOV CX,0001H ; CX=0001H
3B66:0702 BA0300 MOV DX,0003H : DX=0003H
3B66:0705 57 PUSH DI ; DI退避
3B66:0706 CD25 INT 25H ; Absolute disk read, drive al
; if disk under 32MB, dx=start
; cx=#sectors, ds:bx=buffer
; else cx=-1, ds:dx=parm block
; (MS-DOS エンサイクロペディア Volume2 リファレンス編,マイクロソフトプレス編,株式会社アスキー発行P.813~)
; (応用MS-DOS改訂新版,村瀬康治著,株式会社アスキー発行,'89/12/31,P189~)
; (MS-DOSシステムコールハンドブック,河西朝雄著,ナツメ社発行,'91/11/11,P.60~)
; ftp://ftp.abk.nu/pub/text/dos/msdos.txt
; 物理セクタ番号によるディスク読み出し
; AL=ドライブ番号(A:=00H,B:=01H,,,),AL=00HなのでA:
; BX=ディスク転送アドレスのオフセット,読み出すデータの先頭アドレス DS:BX=DS:0900H
; 読み出すセクタ数 CX=0001H 1セクタ
; 読み出しを開始する相対的(論理)セクタ番号 DX=003H 3セクタ
; ディレクトリ領域を正常に読めればCF=0
; セグメントレジスタ(CS,SS,DS,ES)以外の全てのレジスタ破壊。
; フラグはスタックに積まれる(PUSHF)ので,終了後はPOPFまたはADD SP,2。
; ディスク操作が正しく行われるとCF=0
; DS:0900Hに論理セクタ番号3(ディレクトリエントリ)のデータ'ハレノチオオサワギA)',00H*4以下がロードされた。
3B66:0708 58 POP AX ; フラグレジスタをAXに載せる
3B66:0709 5F POP DI ; DI=0900H
3B66:070A BAFFFF MOV DX,0FFFFH ; DX=0FFFFH
3B66:070D 720C JC 071BH ; Jump if carry Set,CF=1(正常に読めない)なら071BHへ。
3B66:070F BEF008 MOV SI,08F0H ; ADVSHELL.COMの[08F0H]には,
; 'ハレノチオオサワギA)',00H*4が書かれている。
;[SI]=CA DA C9 C1 B5 B5 BB DC B7 DE 41 29 00 00 00 00
3B66:0712 B90800 MOV CX,0008H ;
3B66:0715 FC CLD ;ディレクションフラグを0(増加)にリセット
3B66:0716 F3/ A7 repe cmpsw ; Rep zf=1+cx >0 Cmp [si] to es:[di] ; ZF=1で,かつCXが0でない間CXを1減じつつCMPSWを繰り返す。
; ES=DS:[DI]とDS:[SI] にある一致していないワードを探す。
; データブロックの比較
; DS:[SI]とES:[DI]で示されるメモリをワード値で比較し,
; SIとDIの値を2増加させる。8ワード分比較する。
; ES:[DI]には論理セクタ番号3(ディレクトリエントリ)
; 先頭データ'ハレノチオオサワギA)',00H*4が格納されているので一致する
3B66:0718 7501 JNE 071BH ; Jump if not zero, ZF=0(不一致)なら071BHへ
;**********************************************************************************************
;正常時処理
3B66:071A 42 INC DX ; DX=0000H,ZF=1
;エラー時は1行飛ばし 3B66:071B 8BC2 MOV AX,DX ; 正常時AX=0000H,ZF=1,エラー時AX=0FFFFH,ZF=0
3B66:071D C3 RET ;
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3B66:0680 85 C0 test ax,ax ; AX=0000HならZF=1,エラー時AX=0FFFFHなのでZF=0
3B66:0682 75 05 jnz 0689H ; Jump if not zero ZF=0ならRET直行
3B66:0684 B0 01 mov al,1 ; ZF=1(一致)なら,AL=01H。AX=0001H。
3B66:0686 E8 0061 call sub_11 ; (06EA) Bディスク確認ルーチンへ。
;ドライブBディスク確認ルーチン
以下,第2弾へ。
3B66:06EA 1E PUSH DS ;
3B66:06EB 07 POP ES ; DS=ES
3B66:06EC 50 PUSH AX ; AX退避,AX=0001H。
3B66:06ED 8AE0 MOV AH,AL ; AX=0101H
3B66:06EF 054160 ADD AX,6041H ; AX=6142H
3B66:06F2 88269F08 MOV [089FH],AH ; DS:[089FH]=61H 'B'
3B66:06F6 A2FA08 MOV [08FAH],AL ; DS:[08FAH]=42H 'B'
3B66:06F9 58 POP AX ; AX=0001H
3B66:06FA BB0009 MOV BX,0900H ; BX=0900H
3B66:06FD 8BFB MOV DI,BX ; DI=0900H, 読み出したデータの先頭アドレス
3B66:06FF B90100 MOV CX,0001H ; CX=0001H, 1セクタ読み出し
3B66:0702 BA0300 MOV DX,0003H : DX=0003H, 論理セクタ3(ディレクトリエントリ)のデータ
3B66:0705 57 PUSH DI ; DI退避
3B66:0706 CD25 INT 25H ; アブソリュートディスクリード
; AL=ドライブ番号(A:=00H,B:=01H,,,),AL=01HなのでB:
3B66:0708 58 POP AX ; フラグレジスタをAXに載せる
3B66:0709 5F POP DI ; DI=0900H
3B66:070A BAFFFF MOV DX,0FFFFH ; DX=0FFFFH
3B66:070D 720C JB 071BH ; CF=1(正常に読めない)なら071BHへ。
3B66:070F BEF008 MOV SI,08F0H ; DS:[08F0H]には,'ハレノチオオサワギB)',00H*4が書かれている。
; 06F6HでA→Bに書き換えずみ
; [SI]=CA DA C9 C1 B5 B5 BB DC B7 DE 42 29 00 00 00 00
3B66:0712 B90800 MOV CX,0008H ;
3B66:0715 FC CLD ; ディレクションフラグを0(増加)にリセットした。
3B66:0716 F3/ A7 repe cmpsw ; Rep zf=1+cx >0 Cmp [si] to es:[di]
; ZF=1で,かつCXが0でない間CXを1減じつつCMPSWを繰り返す。
; ES:[DI]とDS:[SI] にある一致していないワードを探す。
; データブロックの比較
; DS:[SI]とES:[DI]で示されるメモリをワード値で比較し,
; SIとDIの値を2増加させる。8ワード分比較する。
; ES:[DI]には論理セクタ番号3(ディレクトリエントリ)
; 先頭データ'ハレノチオオサワギB)',00H*4が格納されている。
3B66:0718 7501 JNE 071BH ; ZF=0(データ不一致)なら071BHへ。DX=0FFFFH
3B66:071A 42 INC DX ; DX=0000H
3B66:071B 8BC2 MOV AX,DX ; AX=0000H,ZF=1,0718Hから来たときは,AX=0FFFFH,ZF=0
3B66:071D C3 RET ; 0689Hへ復帰。
3B66:0689 loc_ret_22: ; xref 3B66:0682
3B66:0689 C3 retn
sub_9 endp
3B66:0748 85 C0 test ax,ax ; AX=0000Hなので,ZF=1
3B66:074A 75 E0 jnz 072CH ; Jump if not zero ,ZF=1なのでスルー
; エラー時は072CHへ
;**********************************************************************************************
エラー時表示ルーチン
3B66:072C loc_25: ; xref 3B66:074A
3B66:072C ,BA 0896 mov dx,0896h ;'ドライブA:のディスクを確認してください。$'
3B66:072F B4 09 mov ah,9 ; Bディスク確認エラーなら06F2Hで089FHをAからBに書き換えずみ
3B66:0731 CD 21 int 21h ; DOS Services ah=function 09h 文字列の表示
; display char string at ds:dx DXを先頭アドレスとする$までの文字列
3B66:0733 B4 11 mov ah,11h ; カーソルの表示開始(UND P.65)
3B66:0735 CD 18 int 18h ; ROM basic
3B66:0737 E8 FBE4 call sub_6 ; (031E)キー入力確認ルーチンへ
;キー入力確認ルーチン~0637H
3B66:031E B401 MOV AH,01H ;キーバッファ状態のセンス 出力 BH=00 キー入力データなし
3B66:0320 CD18 INT 18H ;(UNDOCUMENTED 9801/9821,P.41) BH=01 キー入力データあり
;AH=キーコード,AL=キーデータ
;キーバッファにキー入力データがなければすぐに終了する。
3B66:0322 53 PUSH BX ;BX=BH00H
3B66:0323 B400 MOV AH,00H ;キーデータの読み出し(1文字の入力待ち)
3B66:0325 CD18 INT 18H ;(UNDOCUMENTED 9801/9821,P.40) AH=キーコード,AL=キーデータ
;入力を待つので進まない。
3B66:0327 5B POP BX ;BX=BH00H
3B66:0328 84FF TEST BH,BH ;キー入力なしならZF=1,キー入力ありZF=0
3B66:032A 75F2 JNE 021EH ;キー入力あり(ZF=0)なら,021EHへ。無限ループ?
3B66:032C C3 RET ;
3B66:073A B4 12 mov ah,12h ; カーソルの表示停止
3B66:073C CD 18 int 18h ; ROM basic,(UNDOCUMENTED 9801/9821 小高輝真・河野健著 株式会社インプレス発行 '94/03/21,P.65)
3B66:073E ,BA 08C2 mov dx,08C2h ; (3B66:08C2='全角スペース21個',0DH,'$')
3B66:0741 B4 09 mov ah,9 ; '$'検出までの文字列の表示
3B66:0743 CD 21 int 21h ; DOS Services ah=function 09h
; display char string at ds:dx
エラー時表示ルーチン終了
;**********************************************************************************************
3B66:074C E8 0001 call sub_13 ; (0750)
以下,晴れのちおおさわぎ!(PC-98,カクテル・ソフト)ADVSHELL.COM解析(その2)に続く。
晴れのちおおさわぎ!(PC-98,カクテル・ソフト)ADVSHELL.COM解析(その3)はこちら。
<<著作権に関して>>
本記事に引用している全てのソフトの名称・画像の著作権・その他権利は、制作、販売されたソフトハウス、メーカー、または作者様に帰属します。本サイトでの上記著作物の取扱いは、著作権など各権利関係を侵害することが目的ではありません。問題などある場合は、メール(gekigangarあっとmail.goo.ne.jp)にてその旨お知らせください。