首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 組合語言

組合語言命令行參數解析:基於 PSP 的完整實現指南

     編輯:組合語言

引言:為什麼組合語言處理參數比 C 語言複雜?

在 C 語言中,main(int argc, char *argv[], char *envp[]) 直接提供了解析好的參數數組。而在組合語言中,程序啟動時 DS/ES 指向 PSP(Program Segment Prefix),參數原始數據存放在 PSP:80h 起始的區域(長度在 80h,內容從 81h 開始,以 0Dh 結束)。程序員必須手動解析這段緩衝區,處理空格、重定向符、大小寫等細節。本文通過完整示例 PARATEST.ASM 演示如何實現健壯的命令行解析。

PSP 參數區結構回顧

偏移長度含義
80h1 byte參數字符串長度(不含回車符)
81h~最多 127 bytes參數字符串(首字符通常為空格),以 0Dh 結束

注意:重定向符(< > |)及其後內容不會出現在此處,已被 COMMAND.COM 處理。

示例程序功能設計

  • 無參數或全空格:顯示幫助提示
  • 參數以 / 開頭,忽略前導空格
  • 支持 /? 顯示幫助,/p 或 /P 顯示測試信息
  • 非法參數:顯示錯誤信息並回显錯誤參數原文
  • 參數存儲單元僅 2 字節,僅校驗 / 後首字符

核心解析邏輯(源碼註釋版)

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 觀察寄存器狀態。

常見陷阱與最佳實踐

  1. 大小寫敏感:示例中 /p 和 /P 分別判斷,建議統一轉大寫再比較。
  2. 參數緩衝區溢出:示例僅 2 字節,實際項目應根據最大參數長度分配並做邊界檢查。
  3. 多參數支持:需引入狀態機,區分選項(/x)與值(filename),支持 /o filename 或 /o=filename 等形式。
  4. 環境塊解析:PSP:2Ch 存儲環境段地址,環境塊以雙 00h 結束,可提取 PATH 等變量。

完整源碼(PARATEST.ASM)

; ************************************************
; * 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 或虛擬機中編譯運行示例,並嘗試擴展支持多參數、選項值、幫助文本自動生成等功能。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved