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

EXECSUB:編譯型 BASIC 呼叫組合語言執行外部程式 (支援參數/FCB)

     編輯:組合語言

前言:BASIC 擴充系統呼叫的進階範例 — EXEC 封裝

編譯型 BASIC (QuickBASIC 等) 內建 `SHELL` 指令功能有限,無法精細控制子程式參數、FCB、環境區、錯誤回傳。EXECSUB.ASM 實作一個 FAR PROC 供 BASIC 以 `CALL EXECSUB(PROG$, PARM$, FCB1$, FCB2$, RETCD%)` 呼叫,完整封裝 DOS INT 21h, AH=4Bh (EXEC) 功能:釋放記憶體、保存/恢復中斷向量 (INT 1Bh/1Ch/24h 影子向量)、建立參數區塊、執行子程式、恢復堆疊與中斷向量、回傳錯誤碼。程式展示了 BASIC 字串描述子解析、記憶體管理、中斷向量影子備份、參數區塊構建、堆疊切換等高階混合語言技巧。

BASIC 呼叫介面

CALL EXECSUB(PROG$, PARM$, FCB1$, FCB2$, RETCD%)
PROG$   : 程式檔名 (如 "COMMAND.COM")
PARM$   : 命令列參數 (如 "/C DIR *.BAS")
FCB1$   : 第一個 FCB (某些程式需求)
FCB2$   : 第二個 FCB
RETCD%  : 錯誤碼返回 (0=成功, 1=記憶體不足, 2=檔案不存在...)

核心流程

  1. 保存 BASIC 執行期關鍵狀態:
    • 基本資料段 BASICDS (位於絕對位址 0:510h)
    • 中斷向量影子備份:INT 1Bh (Ctrl-Break), 1Ch (Timer Tick), 24h (Critical Error) 的實模式向量與 BASIC 影子向量 (在 0:512h 起)。子程式執行可能修改這些向量,返回前必須恢復。
  2. 釋放記憶體:取得 PSP 位址 (0:4F2h 處儲存目前 PSP 段值),計算頂端記憶體,呼叫 INT 21h, AH=4Ah 保留最小空間給載入器。
  3. 解析 BASIC 字串描述子:參數在堆疊為描述子指標 (SS:[BP+n]),描述子結構 `[長度:WORD][位址:DWORD]`。提取 `PROG$` (DX), `PARM$` (命令列), `FCB1$`, `FCB2$` 位址/長度,填入參數區塊 (prm1..prm4)。
  4. 保存堆疊指標:cli / MOV CS:[stak], SP / MOV CS:[stak+2], SS / sti。
  5. 呼叫 EXEC:MOV AH, 4Bh / MOV AL, 0 / MOV DX, PROG$位址 / MOV BX, 參數區塊位址 / INT 21h。
  6. 恢復堆疊與中斷向量:逆序恢復 INT 1Ch/1Bh/24h 影子向量與實向量,恢復 BASICDS。
  7. 回傳錯誤碼:寫入 `RETCD%` 變數 (MOV SI, [BP+6] / MOV [SI], AX)。

關鍵技術細節

1. 中斷向量影子備份機制

編譯型 BASIC 執行期會 Hook INT 1Bh/1Ch/24h 並在 0:512h 區域維護影子副本。子程式執行期間 (特別是 `COMMAND.COM /C ...`) 可能覆寫這些向量。EXECSUB 採用「雙重備份」策略:

push ds:[i24ip]      ; 實向量 IP
push ds:[b24ip]      ; 影子向量 IP
push ds:[b24ip]
pop ds:[i24ip]       ; 實向量 ← 影子向量 (確保實向量指向 BASIC 處理常式)
push ds:[i24cs]
push ds:[b24cs]
push ds:[b24cs]
pop ds:[i24cs]       ; 同理 CS
... (INT 1Bh, 1Ch 同理) ...

返回時逆序恢復,確保 BASIC 執行期環境完整。

2. 參數區塊構建

prm1 equ this byte
 dw 0                 ; 環境區段 (0=繼承父程式)
prm2 equ this word
 dw 0                 ; 命令列緩衝區位址 (IP)
 dw 0                 ; 命令列緩衝區段值 (CS)
prm3 equ this byte
 dw 0                 ; FCB1 位址
 dw 0
prm4 equ this byte
 dw 0                 ; FCB2 位址
 dw 0

從 BASIC 字串描述子提取位址/段值填入。命令列緩衝區格式:長度位元組 + 內容 + CR (0Dh)。

3. 堆疊切換與 CLI/STI 保護

cli
mov sp, cs:[stak]
mov ss, cs:[stak+2]
sti

在關中斷下切換 SS:SP,避免中斷發生時堆疊不一致導致崩潰。

完整原始碼

skip equ 2 cseg segment para public 'code' public execsub execsub proc far assume cs:cseg,ds:cseg,ss:nothing,es:nothing basicds equ 510h i24ip equ 90h i24cs equ 92h i1bip equ 6ch i1bcs equ 6eh i1cip equ 70h i1ccs equ 72h b24ip equ 51ah b24cs equ 51ch b1bip equ 516h b1bcs equ 518h b1cip equ 512h b1ccs equ 514h push bp mov bp,sp jmp p010 stak equ this byte dw 0 dw 0 prm1 equ this byte dw 0 prm2 equ this word dw 0 dw 0 prm3 equ this byte dw 0 dw 0 prm4 equ this byte dw 0 dw 0 p010: xor ax,ax mov es,ax mov bx,ds mov ds,ax cli push ds:[basicds] push ds:[i24ip] push ds:[b24ip] push ds:[b24ip] pop ds:[i24ip] push ds:[i24cs] push ds:[b24cs] push ds:[b24cs] pop ds:[i24cs] push ds:[i1bip] push ds:[b1bip] push ds:[b1bip] pop ds:[i1bip] push ds:[i1bcs] push ds:[b1bcs] push ds:[b1bcs] pop ds:[i1bcs] push ds:[i1cip] push ds:[b1cip] push ds:[b1cip] pop ds:[i1cip] push ds:[i1ccs] push ds:[b1ccs] push ds:[b1ccs] pop ds:[i1ccs] sti mov ds,bx mov di,4f2h mov ax,es:[di] mov es,ax mov di,2 mov bx,es:[di] sub bx,ax mov ah,4ah int 21h jnc p020 mov ah,0 jmp p090 p020: mov si,[bp+12] add si,skip mov ax,[si] mov si,offset prm2 mov cs:[si],ax mov ax,ds mov cs:[si+2],ax mov si,[bp+10] add si,skip mov ax,[si] mov si,offset prm3 mov cs:[si],ax mov ax,ds mov cs:[si+2],ax mov si,[bp+8] add si,skip mov ax,[si] mov si,offset prm4 mov cs:[si],ax mov ax,ds mov cs:[si+2],ax push bp push ds push es pushf mov si,offset stak mov cs:[si],sp mov cs:[si+2],ss mov ah,4bh mov al,0 mov si,[bp+14] add si,skip mov dx,[si] push cs pop es mov bx,offset prm1 int 21h jnc p050 mov ah,1 jmp p060 p050: mov ax,0 p060: mov bx,cs mov ds,bx mov si,offset stak cli mov sp,cs:[si] mov ss,cs:[si+2] sti popf pop es pop ds pop bp mov cx,ds xor bx,bx mov ds,bx cli pop ds:[b1ccs] pop ds:[i1ccs] pop ds:[b1cip] pop ds:[i1cip] pop ds:[b1bcs] pop ds:[i1bcs] pop ds:[b1bip] pop ds:[i1bip] pop ds:[b24cs] pop ds:[i24cs] pop ds:[b24ip] pop ds:[i24ip] pop ds:[basicds] sti mov ds,cx p090: mov si,[bp+6] mov [si],ax pop bp ret 10 execsub endp cseg ends end

教學價值與現代映照

  • BASIC 字串描述子解析:`skip=2` 區分解釋型 (1) / 編譯型 (2) 描述子結構差異,展示跨執行期版本相容處理。
  • 中斷向量影子備份:識別 BASIC 執行期關鍵 Hook 點 (Ctrl-Break, Timer, Critical Error),雙重備份/恢復確保宿主環境不受子程式污染 — 現代插件/擴充架構同樣需隔離宿主與插件的中斷/信號/回調處理。
  • 參數區塊動態構建:從高階語言字串提取位址/長度/段值,填入系統呼叫結構 — 現代 FFI/互操作層 (JNI, P/Invoke, ctypes) 核心邏輯。
  • 堆疊指標保存於代碼段:`STK_SEG/STK_PTR` 置於 CS,因 EXEC 會重置 SS:SP,CS 為少數穩定段值 — 現代協程/綠色執行緒同樣需在穩定記憶體區保存堆疊指標。
  • 錯誤碼透傳:EXEC 失敗時 AX 含錯誤碼,直接寫入 BASIC 整數變數 — 現代 `HRESULT`/`error_code` 透傳同源。

EXECSUB 以約 200 行程式碼,解決了「高階語言執行期環境保護 + 系統載入器參數封裝 + 子程式執行狀態隔離」三大難題,是混合語言系統程式設計、執行期庫擴充、嵌入式多階段啟動的進階教材。

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