在 C 語言中,main(int argc, char *argv[], char *envp[]) 直接提供了解析好的參數數組。而在組合語言中,程序啟動時 DS/ES 指向 PSP(Program Segment Prefix),參數原始數據存放在 PSP:80h 起始的區域(長度在 80h,內容從 81h 開始,以 0Dh 結束)。程序員必須手動解析這段緩衝區,處理空格、重定向符、大小寫等細節。本文通過完整示例 PARATEST.ASM 演示如何實現健壯的命令行解析。
| 偏移 | 長度 | 含義 |
|---|---|---|
| 80h | 1 byte | 參數字符串長度(不含回車符) |
| 81h~ | 最多 127 bytes | 參數字符串(首字符通常為空格),以 0Dh 結束 |
注意:重定向符(< > |)及其後內容不會出現在此處,已被 COMMAND.COM 處理。
/ 開頭,忽略前導空格/? 顯示幫助,/p 或 /P 顯示測試信息/ 後首字符org 100h ; COM 文件入口
start:
main proc far
push cs
pop ds ; DS = PSP 段地址
cld ; 方向標誌清零,LODSB 自增 SI
mov si, 81h ; SI 指向第一個參數字符
lea bx, parameter ; BX 指向參數存儲緩衝區
lodsb ; AL = [SI], SI++
cmp al, 0dh ; 直接回車?無參數
jz scanexit
cmp al, ' ' ; 空格?
jz judgespace
lodsb ; 讀取下一字符(跳過首空格)
continue:
push si ; 保存 SI
cmp al, '/' ; 必須以 / 開頭
jz parascanloop
jmp error ; 非法參數
judgespace:
lodsb
; call debug ; 可插入斷點調試
cmp al, 0dh
je scanexit
cmp al, ' '
je judgespace ; 連續空格繼續跳過
jne continue
parascanloop: ; 存儲參數標識(/ 及其後首字符)
mov [bx], al
lodsb
cmp al, 0dh
jz choise
inc bx
jnb parascanloop
scanexit:
lea dx, noparametermsg
call disp
call rettodos
choise:
lea si, parameter
mov al, [si+1] ; 取 / 後首字符
cmp al, '?'
jz help
cmp al, 'p'
jz print
cmp al, 'P'
jz print
jmp error
; ... 其餘顯示/退出邏輯 ...
INT 21h/07h 實現斷點源碼中預留的 debug 子程序演示了如何在無調試器環境下設置斷點:
debug proc near
push ax, dx
mov ax, 0900h
mov dx, offset debugmsg
int 21h ; 顯示提示
mov ax, 0700h
int 21h ; 等待按鍵(無回显)
pop dx, ax
ret
debug endp
debugmsg db 0dh,0ah,'Program stop here, press any key to continue...','$'
調用時需保存/恢復現場(PUSH/POP 相關寄存器),可在關鍵分支前插入 CALL DEBUG 觀察寄存器狀態。
/p 和 /P 分別判斷,建議統一轉大寫再比較。/x)與值(filename),支持 /o filename 或 /o=filename 等形式。00h 結束,可提取 PATH 等變量。; ************************************************
; * Program: Use asm language to creat a command *
; * line and parameter program. *
; *==============================================*
; * Designer: Howard Original Place: Wuhan *
; * Creat Date: 09/30/1999 *
; * Modification Date: 10/05/1999 *
; * Now Version: 1.0 *
; * Pass: Tasm 5.0, Tlink 3.1 *
; ************************************************
.model small
.386
.code
org 100h
start:
main proc far
push cs
pop ds
cld
mov si, 81h
lea bx, parameter
lodsb
cmp al, 0dh
jz scanexit
cmp al, ' '
jz judgespace
lodsb
continue:
push si
cmp al, '/'
jz parascanloop
jmp error
judgespace:
lodsb
cmp al, 0dh
je scanexit
cmp al, ' '
je judgespace
jne continue
parascanloop:
mov [bx], al
lodsb
cmp al, 0dh
jz choise
inc bx
jnb parascanloop
scanexit:
lea dx, noparametermsg
call disp
call rettodos
choise:
lea si, parameter
mov al, [si+1]
cmp al, '?'
jz help
cmp al, 'p'
jz print
cmp al, 'P'
jz print
jmp error
print:
lea dx, message
call disp
call rettodos
help:
lea dx, helpmsg
call disp
call rettodos
error:
lea dx, wrongparamsg
call disp
mov ax, 0200h
pop si
dec si
prnwrongparameter:
lodsb
cmp al, 0dh
jz retdos
mov dl, al
int 21h
loop prnwrongparameter
retdos:
mov dl, '"'
int 21h
mov dl, '!'
int 21h
call rettodos
main endp
disp proc near
mov ah, 09h
int 21h
ret
disp endp
rettodos proc near
mov ah, 4ch
int 21h
rettodos endp
noparametermsg db 0ah,0dh,'There is no parameter, enter paratest /? for help.','$'
message db 0dh,0ah,'This is a parameter test program.','$'
wrongparamsg db 0dh,0ah,'The wrong parameter:"','$'
helpmsg db 0dh,0ah,'1.Paratest /?',0dh,0ah,' Print the help message.'
db 0dh,0ah,'2.Paratest /p',0dh,0ah,' Print the test message.','$'
parameter db 2 dup(?)
end start
掌握 PSP 參數解析是組合語言編程進階的必經之路。通過親手實現解析器,能深入理解作業系統如何向用戶程序傳遞上下文信息,為後續學習加載器、Shell 開發、引導扇區代碼打下堅實基礎。建議讀者在 DOSBox 或虛擬機中編譯運行示例,並嘗試擴展支持多參數、選項值、幫助文本自動生成等功能。