IQuit wrote:
我 電腦 還 收藏 有 近 20,000 隻 病毒
COVID-19 included?
cruiseton wrote:
短暫玩過APPLE II ( MOS 6502) + ZILOG Z80 add-in card + CP/M ^++^
====
為什麼 every DOS 程序開頭都是 CD 20?
在 1980 年代初期,CP/M-80 是 8 位元電腦(Intel 8080 / Zilog Z80)的霸主。微軟與西雅圖計算機產品公司(Seattle Computer Products)為了讓開發者願意把 CP/M 上的軟體轉移到 16 位元的 8086 / MS-DOS 上,推出了「自動轉譯工具」(把 8080 組合語言直接機械式轉換成 8086 組合語言)。
為了讓這些轉譯過來的舊程式不用改動核心邏輯、也不會當機,DOS 在程式記憶體的最開頭(PSP,Program Segment Prefix, 256 bytes)複製了 CP/M 的記憶體佈局:
1. 程式結束(Exit)的兼容:
CP/M 做法:跳轉到記憶體 0000h 位置(例如 JMP 0000h 或 RET)。
DOS 的應對:在 PSP 的 Offset 0000h 放上 CD 20(即 INT 20h)。
結果:轉譯後的 CP/M 程式照舊執行 JMP 0000h 時,CPU 一跳過去就會讀到 CD 20,觸發 INT 20h 中斷,安全的把控制權交還給 DOS,完全不會崩潰。
2. 系統呼叫(API Call)的兼容:
CP/M 做法:呼叫 0005h 位置(CALL 0005h)來執行系統功能(BDOS)。
DOS 的應對:在 PSP 的 Offset 0005h 放上 9A ...(遠跳轉 CALL FAR 到 DOS 的 API 入口)。
結果:舊程式呼叫 CALL 0005h 時,也能順利呼叫到 DOS 的服務。
CP/M 與 DOS PSP 的記憶體對照表
PSP 偏移量 (Offset) CP/M 原始用途 DOS PSP 對應機器碼 / 內容 作用
0000h Warm Boot(重啟/退出程式) CD 20 (INT 20h) 讓舊程式跳回 0000h 時能優雅退出
0002h 記憶體上限 最高可用記憶體段位址 告知程式剩餘記憶體大小
0005h BDOS 系統呼叫入口 9A ... (CALL FAR DOS) 讓舊程式呼叫 0005h 時能執行 DOS 功
所以,每個 DOS 程式(不論是 .COM 還是 .EXE)載入時,DOS 都會在記憶體頭部 256 位元組(PSP)的第 0 個位置固定塞入 CD 20。這就是為什麼你在反組譯或用 DEBUG.EXE 觀察記憶體時,開頭永遠都會看到 CD 20 的原因!

IQuit wrote:你 寫 這些 AI 文 只是 原理,
並 沒有 回在 點上.
1 Byte 程式碼 並 沒有 主動 JMP 到 CS:0x0000
主要 關鍵 是 MS 在 堆疊頂 就 預堆 0x00 0x00
所以 1 Byte 程式碼 執行 RET 這時 從 堆疊 取回 0x00 0x00
接著 才是 後續 ...

C30000h-00FFh(256 bytes)0100h: C30100h 開始執行:RET0000hRET 會跳到:PSP:0000CD 20INT 20h0100: C3從 stack 取出 0000h0000: CD 20RETRET 回到作業系統。CALL 0005h0005h 放了一個「跳板(stub)」。| 偏移 |
用途 |
|---|---|
0000h |
INT 20h(程式結束) |
0005h |
CP/M 相容的系統呼叫跳板 |
cruiseton wrote:
好吧, (大) 補貼 XD
1 byte 程式怎麼運作?
假設檔案只有 1 byte:
C3
載入後記憶體大概是:
PSP
0000h-00FFh(256 bytes)
程式
0100h: C3
CPU 從 0100h 開始執行:
RET
RET 不是應該回到呼叫者嗎?
對,一般情況是這樣。
但 DOS 在啟動 COM 程式時,故意先把堆疊(stack)準備好。
它在 stack 裡放入一個返回位址:
0000h
所以 RET 會跳到:
PSP:0000
PSP 的開頭放了什麼?
DOS 建立的 PSP(Program Segment Prefix)前兩個 byte 是:
CD 20
也就是:
INT 20h
這是最早的 DOS「結束程式」功能。
整個流程
0100: C3
RET
從 stack 取出 0000h
0000: CD 20
INT 20h
返回 DOS
所以這個 1-byte 程式其實是利用了 DOS 預先安排好的堆疊與 PSP。
這其實是在模仿 CP/M
在 CP/M 中,程式結束時常常只要:
RET
因為載入器會先在 stack 放好返回位址,讓 RET 回到作業系統。
DOS 為了讓移植 CP/M 程式更容易,就保留了這種行為。
另一個重要相容技巧:CALL 5
CP/M 程式呼叫系統服務時常用:
CALL 0005h
DOS 也在 PSP 的 0005h 放了一個「跳板(stub)」。
PSP 內容(簡化)
偏移
用途
0000h INT 20h(程式結束)
0005h CP/M 相容的系統呼叫跳板
因此很多從 CP/M 翻譯過來的程式,只要稍微修改就能在 DOS 上運作。
DOS 是「真相容」嗎?
不是。
要分清楚兩種相容:
二進位相容(Binary compatible)
8080/Z80 的 CP/M 程式 不能直接在 DOS 執行。
原始碼相容(Source compatible)
程式重新組譯後,通常只需少量修改即可移植到 DOS。
為什麼這麼重要?
這些小技巧讓 IBM PC 在 1981 年能快速獲得大量軟體:
WordStar
dBase
SuperCalc
各種 CP/M 工具程式
開發者不必重寫整個程式,只要移植。
只要移植。

