9

私はこれに対する解決策を切望しています。他の 2 つのアセンブリ .EXE プログラムを (ユーザーの入力によって) ロードして実行できるようにするアセンブリ コードを開発しようとしています。私は2つの問題を抱えています:

  • パス名を有効なレジスタに割り当てることができないようです (または、構文が正しくない可能性があります)。

  • 最初のプログラム (どちらかである可能性があります) が実行を開始した後、他のプログラムを実行できるようにする必要があります。

これは私がこれまでに持っているものです:

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 ビットを使用しています。
4

2 に答える 2

7

いくつかのハッキングといじりの後、これを機能させることができました。思ったほど簡単ではありませんので、席を立ってお待ちください。

まず、DOS がシングルユーザーの非マルチタスク システムであることを (抽象的に聞こえるかもしれませんが) 理解する必要があります。この特定のケースでは、2 つのプロセスを同時に実行できないことを意味します。別のプロセスに移動する前に、1 つのプロセスが実行を終了するのを待つ必要があります。プロセスの同時実行性は、TSR (Terminate and Stay Resident) プロセスである程度エミュレートされる場合があります。TSR プロセスは終了してもメモリ内に留まり、コードからいくつかの割り込みをフックし、後で他のコードから呼び出すことで実行を再開できます。それでも、Windows や Linux などの最新の OS で使用されているのと同じ種類の同時実行ではありません。しかし、それは重要ではありませんでした。

NASM を選択したアセンブラーとして使用しているとのことでしたので、コードを 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. 3 つのラベルの宣言が続きます。これらは、実行するプログラムのヌル終了パスでありexename、新しく作成されたプロセスが受け取るコマンド ラインを指定する です。これは単なる通常の文字列ではないことに注意してください。最初のバイトはコマンドラインの文字数、次にコマンドライン自体、およびキャリッジ リターンです。この場合、コマンドライン パラメーターがないため、全体は. params として渡したいとします。その場合、このラベルを次のように宣言する必要があります(先頭の余分なスペースに注意してください!)。先に進む...exename2cmdlinedb 0,0dh-h -x 3db 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 バイトです。以下は、paramblockDaniel Roethlisberger によって言及された EXEC 構造の表現であるラベルです。最初の項目はゼロです。これは、新しいプロセスがその親プロセスと同じ環境を持つ必要があることを意味します。コマンドライン、最初の FCB、2 番目の FCB の 3 つのアドレスが続きます。リアル モードのアドレスは、セグメントのアドレスとセグメントへのオフセットの 2 つの部分で構成されることに注意してください。これらのアドレスはどちらも 16 ビット長です。これらは、オフセットが最初になるリトルエンディアン形式でメモリに書き込まれます。したがって、コマンドラインをオフセットとして指定しcmdline、FCB のアドレスをラベルへのオフセットとして指定します。dummyFCB自体は使用されませんが、アドレスは有効なメモリ位置を指している必要があるためです。ローダーは 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

これは実際には、アプリケーションの最もトリッキーなポイントの 1 つです。COM ファイルが DOS によってメモリにロードされると、デフォルトで使用可能なすべてのメモリが割り当てられます (リアル モードであるため、CPU はこれを認識しませんが、DOS 内部はそれを追跡します)。したがって、EXEC syscall を呼び出すと、 で失敗しNo memory availableます。AH=4Ahしたがって、"RESIZE MEMORY BLOCK"呼び出しを実行して、そのすべてのメモリが実際には必要ないことを DOS に伝える必要があります(Ralf Brown)。のbxregister は、メモリ ブロックの新しいサイズを 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

これは、実際のEXECsyscall ( AH=4Bh) が呼び出される場所です。ALこれは、プログラムをロードして実行する必要があることを意味します。DS:DX実行可能ファイルへのパスのアドレス (前のコード部分によって選択された)が含まれ、構造を含むラベルES:BXのアドレスが含まれます。paramblockEXEC

.end:
    mov     ax,     4c00h
    int     21h

によって呼び出されたプログラムの実行が終了execした後、親プログラムはAH=4Chsyscall の実行によって終了コード 0 で終了します。

vulture-Freenode の from ##asm の助けに感謝します。私はこれを DOSBox と MS-DOS 6.22 でテストしました。

于 2012-04-09T00:15:33.853 に答える
4

このリファレンスによると、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 をそのアドレスにポイントする必要があります。


Win32 API ではなく 16 ビット (DOS API) をターゲットにしている特定の理由はありますか? 代わりに Win32 API をターゲットにすることができると仮定すると、次のようなスケルトンでWinExec呼び出しを使用して外部実行可能ファイルを開始できます。

global _WinMain@16

; WinExec(char *lpCmdLine, int uCmdShow)
extern _WinExec@8

[section .code]
_WinMain@16:
    ; ... read input and jump to loadrun1 or loadrun2 here

loadrun1:
    push dword 1
    push dword progname1
    call _WinExec@8
    ret

loadrun2:
    push dword 1
    push dword progname2
    call _WinExec@8
    ret

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

または、より最新のShellExecute呼び出しを使用できます。

于 2012-04-07T23:35:48.780 に答える