2012-04-04 52 views
9

我迫切希望找到解決方案。我試圖開發彙編代碼,允許我加載和執行(通過輸入用戶)2個其他Assembly .EXE程序。我有兩個問題:將程序加載到RAM並執行它們NASM 16b

  • 我似乎不能夠路徑名分配到一個有效的寄存器(或者不正確的語法)

  • 我需要能夠執行其它程序在第一個(也可以是)開始執行之後。

這是我到目前爲止有:

mov ax,cs ; moving code segment to data segment 
mov ds,ax 

mov ah,1h ; here I read from keyboard 
int 21h 
mov dl,al 

cmp al,'1' ; if 1 jump to LOADRUN1 
JE LOADRUN1 

cmp al,'2' ; if 2 jump to LOADRUN2 
JE LOADRUN2 

LOADRUN1: 
    MOV AH,4BH 
    MOV AL,00 
    LEA DX,[PROGNAME1] ; Not sure if it works 
    INT 21H 


LOADRUN2: 
    MOV AH,4BH 
    MOV AL,00 
    LEA DX,[PROGNAME2] ; Not sure if it works 
    INT 21H 

; Here I define the bytes containing the pathnames 
PROGNAME1 db 'C:\Users\Usuario\NASM\Adding.exe',0 
PROGNAME2 db 'C:\Users\Usuario\NASM\Substracting.exe',0 

我只是不知道如何通過輸入在「父」程序啓動其他程序,後一個是已經在執行。

在此先感謝您的幫助!任何額外的信息,我會很樂意提供。

  • 不是疊加層。
  • 我使用NASM 16位,Windows 7 32位。
+2

我真的需要幫助,給我所有的聲譽作爲獎勵。 – 2012-04-07 23:34:28

+1

DOS('int 21h')API是一個過時的,無效的,幾乎廢棄且不需要的軟件,不能再使用了。你是否絕對確信你需要使用它? – 2012-04-08 00:33:51

+2

@DanielKozar是的,絕對。否則我不會放棄我的名聲。我真的需要幫助。 – 2012-04-08 01:19:14

回答

7

經過一些黑客和搗亂,我能夠得到這個工作。這並不像我希望的那樣直截了當,所以請抓住你的座位。首先,你需要認識到(儘可能抽象)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。下面是三個標籤的聲明:exenameexename2,它們是要執行的程序的以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 

這是實際的系統調用EXECAH=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測試了這個,所以希望它也適用於你。

+0

你認爲我可以同時運行2個程序嗎? – 2012-04-09 02:19:47

+4

你**不能**應用程序在同一時間運行**。 DOS不允許這樣做。 – 2012-04-09 06:40:58

+1

@DanielKamilKozar:很好的答案。這完全是二十世紀八十年代... – 2012-04-10 20:57:57

4

this reference,你是不是設置EXEC參數塊:

Format of EXEC parameter block for AL=00h,01h,04h: 

Offset Size Description  (Table 01590) 
00h WORD segment of environment to copy for child process (copy caller's 
environment if 0000h) 
02h DWORD pointer to command tail to be copied into child's PSP 
06h DWORD pointer to first FCB to be copied into child's PSP 
0Ah DWORD pointer to second FCB to be copied into child's PSP 
0Eh DWORD (AL=01h) will hold subprogram's initial SS:SP on return 
12h DWORD (AL=01h) will hold entry point (CS:IP) on return 

引用的頁面缺乏<pre>/</pre>標籤此表,這就是爲什麼它是很難在頁面閱讀。

您將不得不建立這樣的參數塊,並指向ES:BX到它的地址。


有你靶向16位(DOS API)什麼特別的原因,而不是在Win32 API?假設你可以逃脫靶向在Win32 API,而不是,您可以使用WinExec呼叫這樣的骨架啓動外部可執行文件:

global [email protected] 

; WinExec(char *lpCmdLine, int uCmdShow) 
extern [email protected] 

[section .code] 
[email protected]: 
    ; ... read input and jump to loadrun1 or loadrun2 here 

loadrun1: 
    push dword 1 
    push dword progname1 
    call [email protected] 
    ret 

loadrun2: 
    push dword 1 
    push dword progname2 
    call [email protected] 
    ret 

[section .data] 
    progname1 db 'C:\Users\Usuario\NASM\Adding.exe',0 
    progname2 db 'C:\Users\Usuario\NASM\Substracting.exe',0 

或者,你可以用更現代的ShellExecute電話。

+1

因爲我正在做幾門課,所以我必須設計16位。你認爲你可以用16位DOS編寫的解決方案來幫助我嗎?這將是grealy表示讚賞。順便說一下,我應該擺脫那些popf? – 2012-04-07 23:40:43

+1

是的,只需刪除'popf'指令即可。 – 2012-04-07 23:47:18

+0

編輯添加一些16位提示。我不運行DOS(a.k.a. Windows :)),所以我實際上不能測試它。 – 2012-04-07 23:56:01

相關問題