?? 匯010.txt
字號:
ORG 100H ;空出前256個字節
start: LEA DX, MSG
MOV AH, 09H
INT 21H
MOV AX, 4C00H
INT 21H
MSG DB "Hello$" ;定義字符串
CSEG ENDS
END start
對上面程序,其生成的COM文件只有23個字節,而其EXE文件的字節數會超過1K。
在PWB編程環境下,可在Option→Project Templates→Set Project Template→在列表框中選DOS COM來指定生成COM文件。在Turbo Assember系統中,可用TASM、TLINK /T來指定生成COM文件。
10.7 駐留程序
駐留程序TSR(Terminate but Stay Resident)是一種特殊應用程序,它在裝入內存運行后,其部分代碼仍然駐留在內存,當該段代碼被激活時,它又進入運行狀態。常用的駐留程序是作為某個中斷處理程序的一部分,其激活條件就是系統產生了此中斷的中斷請求。
雖然駐留程序可根據具體的需要有不同的編寫方式,但其典型結構包括以下幾部分:
1、 保存、修改中斷向量表;
2、 程序第一次運行時的初始化部分:
◆用自己定義的地址來取代中斷向量表中的原地址
◆確定駐留代碼部分的字節數
◆用中斷21H之功能31H把需要駐留代碼部分駐留在內存
3、 駐留內存的代碼部分。
例10.15 在NumLock處于“開狀態”時,每按小鍵盤(Numeric Keypad)上的數字鍵,給出“啪啪”響聲。
例10.15 在NumLock處于“開狀態”時,每按小鍵盤(Numeric Keypad)上的數字鍵,給出“啪啪”響聲。
解:
CSEG SEGMENT 'CODE'
ORG 100H
start:
JMP init
INT9 DD ?
TSR:
PUSH AX
PUSH CX
PUSH DS ;保存寄存器
MOV AH, 2
INT 16H ;讀取鍵盤當前狀態
TEST AL, 00100000B ;檢測NumLock的狀態
JZ TSRExit
IN AL, 60H
CMP AL, 71
JL TSRExit
CMP AL, 83
JG TSRExit
MOV AL, 10110110B
OUT 43H, AL ;向端口43H送特定的數0B6H
MOV AX, 1000
OUT 42H, AL
MOV AL, AH
OUT 42H, AL ;向端口42H送聲音頻率
IN AL, 61H ;讀取揚聲器的當前狀態
MOV AH, AL ;把揚聲器的狀態保存在AH中
OR AL, 03
OUT 61H, AL ;開聲音
MOV CX, 9000
delay:
LOOP delay ;聲音延遲
MOV AL, AH
OUT 61H, AL ;恢復揚聲器原來的狀態,即關聲音
TSRExit:
POP DS
POP CX
POP AX ;恢復寄存器
JMP CS:INT9 ;轉向中斷9H原來的處理程序
init:
CLI ;關中斷
MOV AH, 35H
MOV AL, 09H
INT 21H
MOV WORD PTR INT9, BX
MOV WORD PTR INT9+2, ES ;保存中斷9H原處理程序入口地址
MOV AH, 25H
MOV AL, 09H
LEA DX, TSR
INT 21H ;設置中斷9H新的處理程序入口地址
STI ;開中斷
LEA DX, init
ADD DX, 15
MOV CL, 4 ;把init的偏移量轉換成“節數”
SHR DX, CL ;每節內有16個字節
MOV AX, 3100H
INT 21H
CSEG ENDS
END start
例10.16 編寫一個駐留程序,它可顯示當前時間的秒數。
例10.16 編寫一個駐留程序,它可顯示當前時間的秒數。
解:
CSEG SEGMENT 'CODE'
ORG 100H
start:
JMP init
INT1C DD ?
SEC DW ?
TSR:
PUSH AX
PUSH BX
PUSH CX
PUSH DX
PUSH BP
PUSH DS
PUSH ES ;保存所用到的寄存器
MOV AX, CS
MOV DS, AX
MOV ES, AX ;把CS的值賦給DS和ES
MOV AH, 2H
INT 1AH ;讀取當前時間
MOV DL, DH
AND DH, 0FH
MOV CL, 4
SHR DL, CL
ADD DX, 3030H
MOV SEC, DX ;把當前秒數轉化成字符串
MOV AH, 13H
MOV AL, 0
MOV BH, 0
MOV BL, 7
MOV CX, 2
MOV DX, 004EH ;指定顯示位置為(0,78)
LEA BP, SEC
INT 10H ;在指定位置顯示秒數
POP ES ;恢復所用寄存器的值
POP DS
POP BP
POP DX
POP CX
POP BX
POP AX
JMP CS:INT1C ;轉向中斷1CH原服務程序
init:
CLI
MOV AX, 351CH
INT 21H
MOV word ptr INT1C, BX
MOV word ptr INT1C+2, ES
MOV AX, 251CH
LEA DX, TSR
INT 21H
STI
LEA DX, init
ADD DX, 15
MOV CL, 4 ;把init的偏移量轉換成“節數”
SHR DX, CL ;每節內有16個字節
MOV AX, 3100H
INT 21H
CSEG ENDS
END start
10.8 程序段前綴及其應用
程序段前綴PSP(Program Segment Prefix)是一個具有256個字節的信息區,是可執行文件(EXE和COM)所特有的,其內容在操作系統裝入該文件運行時存入。
10.8.1 程序段前綴的字段含義
PSP信息區的字段分布如下表10.1所列。
表10.1 PSP信息區的字段分布表
偏移量 內容含義 偏移量 內容含義
00~01H 程序結束指令中斷20H 2E~31H 保留
02~03H 分配給該程序的最后段的段地址 32~33H 文件句柄表的長度
04~09H 保留 34~37H 指向文件句柄表的遠指針
0A~0DH 中斷22H的地址(處理終止程序) 38~4FH 保留
0E~11H 中斷23H的地址(處理^Break) 50~51H 中斷21H的功能調用
12~15H 中斷24H的地址(處理嚴重錯誤) 52~5BH 保留
16~17H 保留 5C~6BH 參數區1
18~2BH 缺省的文件句柄表 6C~7FH 參數區2
2C~2DH 程序環境塊的段地址 80~FFH 存儲缺省DTA的緩沖區
PSP信息區的字段說明:
◆18~2BH字段:
該字段內共有20個字節,每個字節存儲一個文件句柄,所以,系統允許應用程序在某一時刻最多只能打開20個文件。
前5個字節存儲系統標準設備的句柄,可參閱8.3.6節——系統標準設備的句柄。
若某文件需要同時打開更多的文件,則需要調整文件句柄數。即:先用中斷21H之功能4AH釋放內存,再用其功能67H來設置新的文件句柄數。
MOV BX, NewNum ;新的文件句柄最大數(20~65535)
MOV AH, 67H
INT 21H
◆ 2C~2DH字段: 該字段存放程序運行環境的段地址,程序的缺省運行環境有160個字節,最多可達32K。該環境含有系統命令,如:COMSPEC、PATH、PROMPT和SET。
◆ 5C~6BH字段: 該字段存放命令行的第一個參數。假設要執行下列命令:
Masm D:test.asm
這時,04H(驅動器D)、8個字符的文件名和3個字符的后綴存放在該區域,沒有存放字符的單元用空格(20H)來填充。若省缺驅動器和文件名,則第一個字節為00H,其它單元為20H。
◆ 6C~7FH字段: 該字段存放命令行的第二個參數。假設要執行下列命令:
Masm D:test.asm, test.obj
這時,test.obj作為第二參數存入該字段,存儲方式如上字段。
◆ 80~FFH字段: 該字段的第一個字節存放命令行參數的字符數,第二個字節為空格,從第三個字節開始存放命令行參數字符。
10.8.2 程序段前綴的應用
了解和掌握PSP中的信息分布就是為了利用其信息。對于EXE文件,可用中斷21H之功能51H獲取其段地址。如:
MOV AH, 51H
INT 21H ;BX=PSP的段地址
MOV ES, BX
CMP byte ptr ES:[80H], 0 ;檢查PSP的長度
JE next
…
對于COM文件,因為其只有一個段,所以,可用更簡單的方式來檢查PSP的內容。
MOV BX, 80H
CMP byte ptr [BX], 0 ;檢查PSP的長度
JE next
…
例10.17 利用PSP中的信息來終止當前程序的運行。
解:顯示解答
例10.18 編寫程序,顯示其命令行參數信息。
解:在使用命令行時,操作系統通常允許在被裝入的程序名之后附加多達127個字符(包括最后的回車符)作為其命令的參數。
本例子的目的就是要了解命令行參數的存儲方法,為以后使用命令行參數作準備。
顯示解答
例10.19 編寫一個類型于DOS內部命令TYPE的程序,該命令的使用方法如下:
……>type 文件1,文件2,…
其功能是分別顯示其參數文件1、文件2等內容,在顯示文件內容前先顯示文件名。顯示完內容后,暫停,等待用戶按任意鍵。若某文件不存在,則顯示相應的提示信息。
解:為了較好地解答本題,我們可以對該問題按以下步驟來解決:
1、若命令行參數中的字符數為0,則結束本程序的運行;
2、從命令行參數中分離出一個文件名;
3、調用子程序,顯示當前文件名、文件內容和等待用戶按鍵;
4、重復步驟1~3,直到所有參數被處理完。
例10.19 編寫一個類型于DOS內部命令TYPE的程序,該命令的使用方法如下:
……>type 文件1,文件2,…
其功能是分別顯示其參數文件1、文件2等內容,在顯示文件內容前先顯示文件名。顯示完內容后,暫停,等待用戶按任意鍵。若某文件不存在,則顯示相應的提示信息。
解:為了較好地解答本題,我們可以對該問題按以下步驟來解決:
1、若命令行參數中的字符數為0,則結束本程序的運行;
2、從命令行參數中分離出一個文件名;
3、調用子程序,顯示當前文件名、文件內容和等待用戶按鍵;
4、重復步驟1~3,直到所有參數被處理完。
.MODEL SMALL, C
.DATA
File
DB 14 DUP(' ')
Buff
DB 128 DUP(0)
Msg1
DB 0DH, 0AH, "$"
Msg2
DB "Not Found$"
Msg3
DB "Press any key...$"
.CODE
;顯示字符串MSG后,再進行回車、換行
DispStr PROC USES AX DX, MSG:PTR BYTE
MOV DX, MSG ;顯示指定的信息
MOV AH, 09H
INT 21H
LEA DX, Msg1 ;顯示回車、換行
MOV AH, 09H
INT 21H
RET
DispStr ENDP
;文件名的長度為傳遞參數Len。若文件不存在,則顯示提示信息,否則,顯示文件內容;
;完成上述操作后,等待用戶按鍵
Disp PROC USES AX BX CX DX, Len:BYTE
XOR BX, BX
MOV BL, Len
MOV File[BX], '$'
INVOKE DispStr, ADDR File ;顯示文件名
MOV File[BX],0
LEA DX, File
MOV AL, 0H
MOV AH, 3DH
INT 21H
.IF CARRY? ;若創建失敗,則顯示失敗信息
INVOKE DispStr, ADDR Msg2
JMP
over1
.ENDIF
MOV BX, AX ;參見例8.14中的有關說明
read:
LEA DX, Buff
MOV CX, 128
MOV AH, 3FH
INT 21H
.IF CARRY? || AX==0
JZ
close
.ENDIF
PUSH BX
LEA DX, Buff
MOV CX, AX
MOV BX, 1
MOV AH, 40H
INT 21H
POP BX
JMP read
close:
MOV AH, 3EH ;關閉已打開的文件
INT 21H
over1:
INVOKE DispStr, ADDR Msg3 ;顯示等待用戶按鍵提示信息
MOV AH, 07H
INT 21H ;等待用戶按鍵
RET
Disp ENDP
.STARTUP
MOV AH, 51H
INT 21H
MOV ES, BX
MOV BX, 80H
MOV CL, ES:[BX]
DEC CL
INC BX
.WHILE CL>0 ;CL=未被處理的參數字符數
XOR
AL, AL ;記錄文件名的長度
LEA
DI, File
.REPEAT
INC
BX
MOV
AH, ES:[BX]
DEC
CL
.BREAK .IF AH==','
MOV
[DI], AH ;從參數中分離出字符,存入文件名中
INC
DI
INC
AL
.UNTIL
CL==0
INVOKE
Disp, AL ;處理當前分離出來的文件名
.ENDW
.EXIT 0
END
10.9 習題
10.1、編寫一個子程序,實現字符串的逆轉。如:ABCD ==> DCBA。
10.2、編寫一段程序,接收4位十六進制數,然后用移位的方法把它轉換成8進制數并輸出在屏幕上。
10.3、編寫一段程序,以十六進制顯示內存0400H:1000H開始的100字,要求每行顯示16個字,每字之間有空格。
10.4、簡述COM文件的主要特點,它與EXE文件有哪些差異?
10.5、編寫一個顯示"Hello"的程序,試比較它的COM格式文件和EXE格式文件的大小。
10.6、編寫一個在屏幕上連續顯示"Welcome…"的信息,要求顯示顏色和顯示位置都是隨機的。在新位置顯示時,原位置的信息抹去。當按任意鍵時,程序結束運行。
10.7、從鍵盤輸入一個表示年份的正整數(1~65535),然后判斷其是否為閏年。若是,則輸出"Yes",否則,輸出"No"。
10.8、編寫一個帶命令行參數的程序Words,輸出指定正文文件中的單詞,假設單詞為連續的字母串。
比如:words file.txt,顯示文件file.txt中的每個單詞
10.9、編寫一個建立雙向鏈表的程序,每接受一個整數,鏈表增加一個結點,當遇到負數時,結束鏈表結點的增加,然后從表尾向前輸出各結點中的數值。
10.10、編寫一個帶命令行參數的程序Calc,其命令行參數是一些整數,程序輸出它們之和。如果某參數為非法整數,則忽略之。
比如:Calc 120 +34 -56,則程序顯示98。
10.11、在10.10的基礎上,在不考慮運算符優先級的情況下,實現一個可進行算術四則運算(只有加、減、乘和除,沒有括號等)的計數器,并顯示其計算結果。
10.12、編寫一個簡單的加密程序,它把一個文件中的所有字母字符按下列規律進行轉換,非字母的字符保持不變。
轉換規律:'A'→'Z','B'→'Y',……。
10.13、編寫一個程序,它可顯示BMP的圖形文件。
10.14、編寫一個程序,它可顯示JPG的圖形文件。
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -