經過一些黑客和搗亂,我能夠得到這個工作。這並不像我希望的那樣直截了當,所以請抓住你的座位。首先,你需要認識到(儘可能抽象)DOS是一個單用戶,非多任務系統。在這種特殊情況下,這意味着您不能同時運行兩個進程。您需要需要等待一個進程完成執行,然後再轉移到另一個進程。 TSR(終止和駐留)進程可以在某種程度上仿效進程併發,儘管它們被終止,但它仍然保留在內存中,並且可以通過從代碼中鉤住一些中斷並稍後從其他代碼中調用它來恢復執行。儘管如此,這與現代操作系統(如Windows和Linux)使用的併發性並不相同。但那不是重點。
你說你使用NASM作爲你選擇的彙編程序,因此我假設你將代碼輸出到COM文件,而COM文件又由DOS命令提示符執行。 COM文件通過命令提示符在偏移量100h
(加載到該位置執行跳轉後)加載,除「精簡」代碼和數據外不包含任何其他內容 - 因此它們是最容易生成的。
我將分解組件源,以便您可以(可能)更好地瞭解底層發生了什麼。
該計劃始於
org 100h
section .data
exename db "C:\hello.com",0
exename2 db "C:\nasm\nasm.exe",0
cmdline db 0,0dh
的org
指令,規定在實際加載到內存中的文件的來源 - 在我們的情況下,這是100h
。下面是三個標籤的聲明:exename
和exename2
,它們是要執行的程序的以null結尾的路徑,以及cmdline
,它指定新創建的進程應接收的命令行。請注意,它不僅僅是一個普通的字符串:第一個字節是命令行中的字符數,然後是命令行本身以及回車。在這種情況下,我們沒有命令行參數,因此整個事情歸結爲db 0,0dh
。假設我們想通過-h -x 3
作爲參數:在這種情況下,我們需要將此標籤聲明爲db 8," -h -x 3",0dh
(請注意開頭的額外空間!)。繼續前進......
dummy times 20 db 0
paramblock dw 0
dw cmdline
dw 0 ; cmdline_seg
dw dummy ; fcb1
dw 0 ; fcb1_seg
dw dummy ; fcb2
dw 0 ; fcb2_seg
標籤dummy
是包含零僅有20個字節。以下是paramblock
標籤,它是Daniel Roethlisberger提到的EXEC結構的代表。第一項是零,這意味着新過程應該具有與其父項相同的環境。接下來有三個地址:命令行,第一個FCB和第二個FCB。您應該記住,實模式中的地址由兩部分組成:段的地址和段的偏移量。這兩個地址都是16位長。它們以小尾數方式寫入內存,偏移量居第一位。因此,我們將命令行指定爲偏移量cmdline
,並將FCB的地址指定爲標籤dummy
的偏移量,因爲FCB本身不會被使用,但地址需要指向有效內存位置。段需要在運行時填充,因爲加載器選擇加載COM文件的段。
section .text
entry:
mov ax, cs
mov [paramblock+4], ax
mov [paramblock+8], ax
mov [paramblock+12],ax
我們通過在paramblock
結構設置段開始場的計劃。由於對於COM文件,CS = DS = ES = SS
,即所有段都相同,我們只需將這些值設置爲cs
寄存器中的值即可。
mov ax, 4a00h
mov bx, 50
int 21h
這實際上是應用程序中最棘手的一點。當一個COM文件被DOS加載到內存中時,默認情況下會爲它分配所有可用的內存(CPU不知道這一點,因爲它處於實模式,但DOS內部始終保持跟蹤)。因此,調用EXEC系統調用會導致它失敗,並顯示No memory available
。因此,我們需要通過執行「調整內存塊大小」AH=4Ah
調用(Ralf Brown)來告訴DOS我們並不真的需要所有的內存。 bx
寄存器應該以16字節爲單位(「段落」)具有新的內存塊大小,所以我們將其設置爲50,我們的程序有800字節。我不得不承認,這個值是隨機選取的,我試圖將其設置爲有意義的值(例如,基於實際文件大小的值),但是我一直不知所措。ES
是我們想要「調整大小」的段,在我們的例子中是CS
(或任何其他的,因爲它們在加載COM文件時都是相同的)。完成這個調用後,我們準備將我們的新程序加載到內存中並執行它。
mov ax, 0100h
int 21h
cmp al, '1'
je .prog1
cmp al, '2'
je .prog2
jmp .end
.prog1:
mov dx, exename
jmp .exec
.prog2:
mov dx, exename2
此代碼應該是不言自明,它選擇基於標準輸入插入DX
程序的路徑。
.exec:
mov bx, paramblock
mov ax, 4b00h
int 21h
這是實際的系統調用EXEC
(AH=4Bh
)被調用。 AL
包含0,這意味着程序應該被加載並執行。 DS:DX
包含可執行文件路徑的地址(由前一段代碼選擇),並且ES:BX
包含paramblock
標籤的地址,其中包含EXEC
結構。
.end:
mov ax, 4c00h
int 21h
整理由exec
調用的程序的執行後,父程序通過執行系統調用AH=4Ch
終止爲零的退出代碼。
感謝來自Freenode的## asm的vulture-
尋求幫助。我用DOSBox和MS-DOS 6.22測試了這個,所以希望它也適用於你。
我真的需要幫助,給我所有的聲譽作爲獎勵。 – 2012-04-07 23:34:28
DOS('int 21h')API是一個過時的,無效的,幾乎廢棄且不需要的軟件,不能再使用了。你是否絕對確信你需要使用它? – 2012-04-08 00:33:51
@DanielKozar是的,絕對。否則我不會放棄我的名聲。我真的需要幫助。 – 2012-04-08 01:19:14