いくつかのハッキングとツイディリングの後、私はこの作業を得ることができました。それは私が望むほど簡単ではありませんので、あなたの座席をつかんでください。
まず、DOSはシングルユーザーでマルチタスクではないシステムであることを認識する必要があります。この特定の場合、2つのプロセスを同時に実行することはできません。 が必要です。あるプロセスが別のプロセスに移動する前に実行を完了するのを待つ必要があります。プロセスの並行処理は、TSR(Terminate and Stay Resident)プロセスでいくらかエミュレートされる可能性があります。プロセスは終了したにもかかわらずメモリに残り、コードからいくつかの割り込みをフックし、後で別のコードから呼び出すことで実行を再開できます。それでも、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つのラベルの宣言は、実行するプログラムのNULL終端されたパスであるexename
とexename2
と、新しく作成されたプロセスが受け取るべきコマンドラインを指定するcmdline
です。最初のバイトはコマンドラインの文字数、次にコマンドライン自体、およびキャリッジリターンであることに注意してください。この場合、コマンドラインパラメータはありません。したがって、すべてがdb 0,0dh
になります。 paramsとして-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、2番目のFCBの3つのアドレスが続きます。実際のモードのアドレスは、セグメントのアドレスとセグメントへのオフセットという2つの部分で構成されています。これらのアドレスは両方とも16ビット長です。彼らはリトルエンディアン方式でメモリに書き込まれ、最初はオフセットされています。したがって、コマンドラインをオフセットcmdline
、FCBのアドレスをラベルdummy
へのオフセットとして指定します。これは、FCB自体は使用されませんが、アドレスは有効なメモリ位置を指す必要があるためです。ローダーがCOMファイルがロードされるセグメントを選択するため、セグメントは実行時に埋められる必要があります。
paramblock
構造のセグメントフィールドを設定してプログラムを開始します。 COMファイルの場合、CS = DS = ES = SS
、つまりすべてのセグメントが同じであるため、これらの値をcs
レジスタの値に設定するだけです。
mov ax, 4a00h
mov bx, 50
int 21h
これは実際にアプリケーションの最も難しい点の1つです。 COMファイルがDOSによってメモリにロードされると、デフォルトで使用可能なすべてのメモリが割り当てられます(CPUはリアルモードであるため、DOS内部ではそれを追跡します)。したがって、EXECシステムコールを呼び出すと、それはNo memory available
で失敗します。したがって、私たちはDOSに "RESIZE MEMORY BLOCK" AH=4Ah
コール(Ralf Brown)を実行することによって、そのメモリをすべて必要としないことを伝える必要があります。 bx
レジスタは16バイト単位でメモリブロックの新しいサイズ( "段落")を持つはずですので、プログラムには800バイトを持つ50に設定します。この値は無作為に選ばれたことを認めなければなりません。実際のファイルサイズに基づく値など、意味をなさないものに設定しようとしましたが、私はどこにも行きませんでした。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
には、EXEC
構造を含むparamblock
ラベルのアドレスが含まれています。
.end:
mov ax, 4c00h
int 21h
exec
によって呼び出されたプログラムの実行を終了した後、親プログラムがAH=4Ch
システムコールを実行することにより、ゼロの終了コードで終了します。
vulture-
ありがとうございます。## asm on Freenodeからお問い合わせください。私はこれをDOSBoxとMS-DOS 6.22でテストしました。うまくいけば、あなたのためにもうまくいきます。
本当に助けが必要です。私の評判はすべて報酬として与えられます。 –
DOS( 'int 21h')APIは、廃止された、効果のない、かなり使われていない不要なソフトウェアです。これはもう使用してはいけません。あなたは絶対に**あなたはそれを使う必要があると確信していますか? –
@DanielKozarはい、絶対に。私はそうでなければ私の評判を払わないだろう。私は本当にこれについて助けが必要です。 –