2012-04-04 12 views
9

Sono disperato per una soluzione a questo. Sto provando a sviluppare il codice Assembly che mi consente di caricare ed eseguire (per input dell'utente) altri 2 programmi Assembly .EXE. Sto avendo due problemi:Caricamento dei programmi nella RAM ed eseguirli NASM 16b

  • Non mi sembra di essere in grado di assegnare il percorso di un registro valido (o forse la sintassi non corretta)

  • ho bisogno di essere in grado di eseguire l'altra programma dopo che il primo (potrebbe essere o) ha iniziato la sua esecuzione.

Questo è quello che ho finora:

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 

io non so come avviare un altro programma da ingresso nel programma 'genitore', dopo che uno è già in esecuzione.

Grazie in anticipo per il vostro aiuto! Qualsiasi informazione aggiuntiva sarò più che felice di fornire.

  • Non è un overlay.
  • Sto usando NASM a 16 bit, Windows 7 a 32 bit.
+2

Ho davvero bisogno di aiuto, dando tutta la mia reputazione come ricompensa. –

+1

L'API DOS ('int 21h') è una parte di software assoluta, inefficace, piuttosto in disuso e indesiderata che non deve essere più utilizzata. Sei ** assolutamente ** sicuro di aver bisogno di usarlo? –

+2

@DanielKozar Sì, assolutamente. Non darei la mia reputazione altrimenti. Ho davvero bisogno di aiuto su questo. –

risposta

7

Dopo un po 'di hacking e giocherellando, sono riuscito a farlo funzionare. Non è così semplice come speravo sarebbe, quindi aggrappati al tuo posto (s).

In primo luogo, è necessario rendersi conto (per quanto astratto possa sembrare) che DOS sia un sistema single-user, non-multitasking. In questo caso particolare, significa che non è possibile avere due processi in esecuzione contemporaneamente. È necessario attendere che un processo finisca l'esecuzione prima di passare a un altro processo. La concorrenza di processo può essere in qualche modo emulata con i processi TSR (Terminate and Stay Resident), che rimangono in memoria nonostante siano stati terminati ed è possibile riprendere la loro esecuzione agganciando alcuni interrupt dal loro codice e chiamandolo successivamente da qualche altro codice. Tuttavia, non è lo stesso tipo di concorrenza che viene utilizzato dai sistemi operativi moderni, come Windows e Linux. Ma non era questo il punto.

Hai detto che stai utilizzando la NASM come assemblatore di scelta, quindi ho presupposto che tu avessi inviato il tuo codice ai file COM, che a loro volta vengono eseguiti dal prompt dei comandi DOS. I file COM vengono caricati dal prompt dei comandi all'offset 100h (dopo aver caricato un salto in quella posizione viene eseguito) e non contengono nient'altro che codice e dati "snelli", senza intestazioni, quindi sono i più facili da produrre.

Ho intenzione di spiegare la sorgente di assemblaggio a pezzi, in modo che tu possa (forse) avere un'idea migliore di ciò che sta succedendo sotto il cofano.

Il programma inizia con

org 100h 

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

direttiva org, che specifica l'origine del file quando in realtà caricato nella memoria - nel nostro caso, si tratta di 100h. Seguono dichiarazioni di tre etichette, exename e exename2, che sono percorsi con terminazione null dei programmi da eseguire e cmdline, che specifica la riga di comando che deve essere ricevuta dal processo appena creato. Si noti che non è solo una stringa normale: il primo byte è il numero di caratteri nella riga di comando, quindi la riga di comando stessa e un ritorno a capo. In questo caso, non abbiamo parametri della riga di comando, quindi l'intera cosa si riduce a db 0,0dh. Supponiamo di voler passare -h -x 3 come parametri: in tal caso, dovremmo dichiarare questa etichetta come db 8," -h -x 3",0dh (notare lo spazio extra all'inizio!). Passando ...

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 

L'etichetta dummy soli 20 byte che contengono zeri. Quello che segue è l'etichetta paramblock, che è una rappresentazione della struttura EXEC menzionata da Daniel Roethlisberger. Il primo elemento è uno zero, il che significa che il nuovo processo dovrebbe avere lo stesso ambiente del suo genitore. Seguono tre indirizzi: alla riga di comando, al primo FCB e al secondo FCB. È necessario ricordare che gli indirizzi in modalità reale sono costituiti da due parti: l'indirizzo del segmento e l'offset nel segmento. Entrambi gli indirizzi sono lunghi 16 bit. Sono scritti nella memoria in modo little endian, con il primo offset. Pertanto, si specifica la riga di comando come offset cmdline e gli indirizzi degli FCB come offset sull'etichetta dummy, poiché gli FCB stessi non verranno utilizzati, ma gli indirizzi devono puntare a una posizione di memoria valida in entrambi i casi. I segmenti devono essere riempiti in fase di esecuzione, poiché il caricatore sceglie il segmento in cui viene caricato il file COM.

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

Iniziamo il programma impostando i campi dei segmenti nella struttura paramblock. Poiché per i file COM, CS = DS = ES = SS, vale a dire che tutti i segmenti sono uguali, è sufficiente impostare tali valori su ciò che si trova nel registro cs.

mov  ax, 4a00h 
mov  bx, 50 
int  21h 

Questo è in realtà uno dei punti più difficili dell'applicazione. Quando un file COM viene caricato nella memoria da DOS, viene assegnata tutta la memoria disponibile per impostazione predefinita (la CPU non ne ha idea, dal momento che è in modalità reale, ma gli interni DOS ne tengono comunque traccia). Pertanto, la chiamata al syscall di EXEC causa il fallimento con No memory available. Pertanto, dobbiamo dire a DOS che non abbiamo davvero bisogno di tutta quella memoria eseguendo il "RESIZE MEMORY BLOCK" AH=4Ah chiamata (Ralf Brown). Il registro bx dovrebbe avere la nuova dimensione del blocco di memoria in unità da 16 byte ("paragrafi"), quindi lo impostiamo su 50, con 800 byte per il nostro programma. Devo ammettere che questo valore è stato scelto in modo casuale, ho provato a impostarlo su qualcosa che avrebbe senso (ad esempio un valore basato sulla dimensione effettiva del file), ma non sono riuscito a ottenere nulla.ES è il segmento che vogliamo "ridimensionare", nel nostro caso quello è CS (o qualsiasi altro, poiché sono tutti uguali quando viene caricato un file COM). Dopo aver completato questa chiamata, siamo pronti per caricare il nostro nuovo programma in memoria ed eseguirlo.

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 

Questo codice dovrebbe essere abbastanza auto-esplicativo, si sceglie il percorso del programma inserito nel DX in base alla stdin.

.exec: 
    mov  bx, paramblock 
    mov  ax, 4b00h 
    int  21h 

Questo è dove è chiamato l'attuale EXEC syscall (AH=4Bh). AL contiene 0, il che significa che il programma deve essere caricato ed eseguito. DS:DX contiene l'indirizzo del percorso dell'eseguibile (scelto dalla parte di codice precedente) e ES:BX contiene l'indirizzo dell'etichetta paramblock, che contiene la struttura EXEC.

.end: 
    mov  ax,  4c00h 
    int  21h 

Dopo aver terminato l'esecuzione del programma chiamato da exec, il programma principale viene terminato con un codice di uscita pari a zero eseguendo il AH=4Ch syscall.

Grazie a vulture- da ## asm su Freenode per assistenza. Ho provato questo con DOSBox e MS-DOS 6.22, quindi spero che funzioni anche per te.

+0

Pensi che io possa eseguire 2 programmi contemporaneamente con questo? –

+4

** non è possibile ** avere applicazioni in esecuzione ** letteralmente ** allo stesso tempo. DOS non lo consente. –

+1

@DanielKamilKozar: Bella risposta. Questo è così totalmente anni '80 ... –

4

Secondo this reference, non sta impostando il blocco di parametri 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 

La pagina di riferimento manca i tag <pre>/</pre> per questa tabella, è per questo che è difficile da leggere nella pagina.

È necessario impostare un blocco di parametri e indicare ES: BX nel suo indirizzo.


C'è un motivo particolare ci si rivolge a 16 bit (API DOS) al posto della API Win32? Supponendo che si può ottenere via con targeting l'API Win32, invece, è possibile avviare eseguibili esterni utilizzando la chiamata WinExec in qualcosa di simile a questo scheletro:

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 

In alternativa, è possibile utilizzare il più moderno ShellExecute chiamata.

+1

Dato che sto facendo un paio di corsi, devo progettare per 16 bit. Pensi di potermi aiutare con una soluzione scritta per DOS a 16 bit? Sarebbe molto apprezzato. E a proposito, dovrei semplicemente sbarazzarmi di quei popf? –

+1

Sì, basta rimuovere le istruzioni 'popf'. –

+0

Modificato per aggiungere alcuni suggerimenti a 16 bit. Non eseguo DOS (a.k.a. Windows :)), quindi non posso testarlo. –

Problemi correlati