Laden von Programmen in den Arbeitsspeicher und Ausführen von Programmen auf dem NASM 16b

Ich bin verzweifelt nach einer Lösung dafür. Ich versuche, Assembly-Code zu entwickeln, mit dem ich (nach Eingabe des Benutzers) 2 andere Assembly-EXE-Programme laden und ausführen kann. Ich habe zwei Probleme:

Ich kann den Pfadnamen anscheinend keinem gültigen Register zuordnen (oder falsche Syntax)

Ich muss in der Lage sein, das andere Programm auszuführen, nachdem das erste (könnte eines von beiden sein) seine Ausführung gestartet hat.

Das habe ich bisher:

<code>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
</code>

Ich weiß nur nicht, wie ich ein anderes Programm durch Eingabe in das übergeordnete Programm starten soll, nachdem es bereits ausgeführt wurde.

Vielen Dank im Voraus für Ihre Hilfe! Für weitere Informationen stehe ich Ihnen gerne zur Verfügung.

Ist kein Overlay.Ich verwende NASM 16-Bit, Windows 7 32-Bit.
 Jean Carlos Suárez Marranzini08. Apr. 2012, 03:19
@ DanielKozar Ja, absolut. Sonst würde ich meinen Ruf nicht verraten. Ich brauche wirklich Hilfe dabei.
 Jean Carlos Suárez Marranzini08. Apr. 2012, 01:34
Ich brauche wirklich Hilfe und gebe meinen Ruf als Belohnung.
 Jean Carlos Suárez Marranzini08. Apr. 2012, 03:53
@DanielKozar Könnten Sie bitte eine Lösung für dieses Problem vorstellen, die auf den Anforderungen basiert, die ich geschrieben habe? Es würde meinen Tag machen. Danke im Voraus.
 Daniel Kamil Kozar08. Apr. 2012, 02:33
Das DOS (int 21h) API ist eine absolute, ineffektive, ziemlich ungenutzte und unerwünschte Software, die nicht mehr verwendet werden darf. Bist duabsolut sicher, dass Sie es verwenden müssen?

Antworten auf die Frage(2)

Lösung für das Problem

ist nicht so einfach, wie ich es mir erhofft hatte. Halten Sie sich an Ihren Plätzen fest.

Erstens müssen Sie erkennen (so abstrakt das auch klingen mag), dass DOS ein Einzelbenutzer-System ohne Multitasking ist. In diesem speziellen Fall können nicht zwei Prozesse gleichzeitig ausgeführt werden. Siebrauchen Warten, bis ein Prozess die Ausführung beendet hat, bevor Sie zu einem anderen Prozess wechseln. Die gleichzeitige Ausführung von Prozessen kann mit TSR-Prozessen (Terminate and Stay Resident) etwas emuliert werden, die trotz Beendigung im Speicher verbleiben. Sie können die Ausführung fortsetzen, indem Sie einige Interrupts aus ihrem Code einbinden und später von einem anderen Code aufrufen. Es ist jedoch nicht dieselbe Art von Nebenläufigkeit, die von modernen Betriebssystemen wie Windows und Linux verwendet wird. Darum ging es aber nicht.

Sie sagten, dass Sie NASM als Assembler Ihrer Wahl verwenden. Ich ging daher davon aus, dass Sie Ihren Code in COM-Dateien ausgeben, die wiederum von der DOS-Eingabeaufforderung ausgeführt werden. COM-Dateien werden von der Eingabeaufforderung am Offset geladen100h (Nach dem Laden wird ein Sprung an diesen Ort ausgeführt) und enthält nichts anderes als "schlanken" Code und Daten - keine Überschriften, daher sind sie am einfachsten zu produzieren.

Ich werde die Assembly-Quelle in Stücken erklären, damit Sie (vielleicht) einen besseren Einblick in das bekommen, was unter der Haube vor sich geht.

Das Programm beginnt mit

<code>org 100h

section .data
exename db "C:\hello.com",0
exename2 db "C:\nasm\nasm.exe",0
cmdline db 0,0dh
</code>

dasorg Direktive, die den Ursprung der Datei angibt, wenn sie tatsächlich in den Speicher geladen wird - in unserem Fall ist dies100h. Es folgen Erklärungen von drei Etiketten,exename undexename2 die nullterminierte Pfade der auszuführenden Programme sind, undcmdlineGibt die Befehlszeile an, die der neu erstellte Prozess erhalten soll. Beachten Sie, dass es sich nicht nur um eine normale Zeichenfolge handelt: Das erste Byte ist die Anzahl der Zeichen in der Befehlszeile, dann die Befehlszeile selbst und ein Carriage Return. In diesem Fall haben wir keine Kommandozeilenparameter, also läuft das Ganze aufdb 0,0dh. Angenommen, wir wollten bestehen-h -x 3 als params: in diesem fall müssten wir dieses label als deklarierendb 8," -h -x 3",0dh (Beachten Sie den zusätzlichen Platz am Anfang!). Weitermachen ...

<code>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
</code>

Das Etikettdummy ist nur 20 Bytes, die Nullen enthalten. Was folgt ist dasparamblock label ist eine Darstellung der von Daniel Roethlisberger erwähnten EXEC-Struktur. Das erste Element ist eine Null, was bedeutet, dass der neue Prozess dieselbe Umgebung wie sein übergeordnetes Element haben sollte. Es folgen drei Adressen: zur Befehlszeile, zum ersten FCB und zum zweiten FCB. Sie sollten sich daran erinnern, dass Adressen im Real-Modus aus zwei Teilen bestehen: der Adresse des Segments und dem Offset im Segment. Beide Adressen sind 16 Bit lang. Sie werden in Little-Endian-Form in das Gedächtnis geschrieben, wobei der Offset an erster Stelle steht. Deshalb geben wir die Kommandozeile als Offset ancmdline, und Adressen der FCBs als Versatz zum Etikettdummy, da die FCBs selbst nicht verwendet werden, die Adressen jedoch auf einen gültigen Speicherort verweisen müssen. Die Segmente müssen zur Laufzeit gefüllt werden, da der Loader das Segment auswählt, in das die COM-Datei geladen wird.

<code>section .text
entry:
    mov     ax,             cs
    mov     [paramblock+4], ax
    mov     [paramblock+8], ax
    mov     [paramblock+12],ax
</code>

Wir beginnen das Programm mit dem Setzen der Segmentfelder imparamblock Struktur. Seit für COM-Dateien,CS = DS = ES = SSd.h. alle Segmente sind gleich, wir setzen diese Werte einfach auf das, was in dercs registrieren.

<code>mov     ax, 4a00h
mov     bx, 50
int     21h
</code>

Dies ist tatsächlich einer der schwierigsten Punkte der Anwendung. Wenn eine COM-Datei von DOS in den Speicher geladen wird, wird ihr standardmäßig der gesamte verfügbare Speicher zugewiesen (die CPU hat keine Ahnung davon, da sie sich im Real-Modus befindet, aber DOS-Interna verfolgen dies trotzdem). Daher führt der Aufruf des EXEC-Systemaufrufs zum FehlschlagenNo memory available. Deshalb müssen wir DOS mitteilen, dass wir nicht wirklich den gesamten Speicher benötigen, indem wir den "RESIZE MEMORY BLOCK" ausführen.AH=4Ah Anruf(Ralf Brown). Dasbx register soll die neue Größe des Speicherblocks in 16-Byte-Einheiten ("Absätzen") haben, also setzen wir sie auf 50 und haben 800 Byte für unser Programm. Ich muss zugeben, dass dieser Wert nach dem Zufallsprinzip ausgewählt wurde. Ich habe versucht, einen sinnvollen Wert festzulegen (z. B. einen Wert, der auf der tatsächlichen Dateigröße basiert), bin aber immer weitergekommen.ES ist das Segment, dessen Größe wir ändern möchten, in unserem Fall alsoCS (oder eine andere, da sie alle gleich sind, wenn eine COM-Datei geladen wird). Nach Abschluss dieses Aufrufs können Sie unser neues Programm in den Speicher laden und ausführen.

<code>    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
</code>

Dieser Code sollte ziemlich selbsterklärend sein, er wählt den Pfad zu dem Programm, in das er eingefügt wurdeDX basierend auf dem stdin.

<code>.exec:
    mov     bx, paramblock
    mov     ax, 4b00h
    int     21h
</code>

Hier ist das eigentlicheEXEC syscall (AH=4Bh) wird genannt.AL enthält 0, was bedeutet, dass das Programm geladen und ausgeführt werden soll.DS:DX enthält die Adresse des Pfads zur ausführbaren Datei (ausgewählt durch den vorherigen Code) undES:BX enthält die Adresse desparamblock Etikett, das das enthältEXEC Struktur.

<code>.end:
    mov     ax,     4c00h
    int     21h
</code>

Nach Beendigung der Ausführung des von aufgerufenen Programmsexecwird das übergeordnete Programm mit einem Beendigungscode von Null beendet, indem der Befehl ausgeführt wirdAH=4Ch Syscall.

Dank anvulture- von ## asm auf Freenode um Hilfe. Ich habe dies mit DOSBox und MS-DOS 6.22 getestet, also funktioniert es hoffentlich auch für Sie.

 Jean Carlos Suárez Marranzini09. Apr. 2012, 04:19
Glaubst du, ich kann damit 2 Programme gleichzeitig ausführen?
 Daniel Roethlisberger10. Apr. 2012, 22:57
@ DanielKamilKozar: Schöne Antwort. Dies ist so total 1980er Jahre ...
 Daniel Kamil Kozar09. Apr. 2012, 08:40
Siekippen Anwendungen laufenbuchstäblich zur selben Zeit. DOS erlaubt dies nicht.

Gemäßdiese Referenz, Sie setzen den EXEC-Parameterblock nicht:

<code>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
</code>

Der referenzierten Seite fehlt die<pre>/</pre> Tags für diese Tabelle, deshalb ist es schwer, auf der Seite zu lesen.

Sie müssen einen solchen Parameterblock einrichten und ES: BX auf seine Adresse zeigen.

Gibt es einen bestimmten Grund, warum Sie 16-Bit (DOS-API) anstelle der Win32-API als Ziel festlegen? Angenommen, Sie können nicht mehr auf die Win32-API abzielen, sondern externe ausführbare Dateien mithilfe von startenWinExec Rufen Sie so etwas wie dieses Skelett ein:

<code>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
</code>

Alternativ können Sie die modernere verwendenShellExecute Anruf.

 Jean Carlos Suárez Marranzini08. Apr. 2012, 02:07
Ich entschuldige mich für meinen Mangel an Wissen, ich bin nur ein Anfänger in der Montage. Um ganz ehrlich zu sein, verstehe ich den Absatz über den EXEC-Parameterblock nicht. Ich weiß, das mag beschämend klingen, aber ich brauche wirklich mehr Hilfe. Fast mein ganzer Ruf ist ein Indikator dafür. Und vielen Dank für Ihre Hilfe.
 Daniel Roethlisberger08. Apr. 2012, 01:56
Bearbeitet, um einige 16-Bit-Hinweise hinzuzufügen. Ich führe DOS nicht aus (a.k.a. Windows :)), daher kann ich dies nicht testen.
 Daniel Roethlisberger08. Apr. 2012, 01:47
Ja, entfernen Sie einfach diepopf Anleitung.
 Jean Carlos Suárez Marranzini08. Apr. 2012, 01:40
Da ich ein paar Kurse mache, muss ich für 16 Bits entwerfen. Glaubst du, du kannst mir mit einer Lösung für 16-Bit-DOS helfen? Es wäre sehr dankbar. Und nebenbei, sollte ich diesen Topf einfach loswerden?

Ihre Antwort auf die Frage