2012-04-04 11 views
9

Jestem rozpaczliwie szuka rozwiązania tego problemu. Próbuję opracować kod zestawu pozwalający mi na załadowanie i wykonanie (przez wejście użytkownika) 2 innych złożonych programów .EXE. Mam dwa problemy:Ładowanie programów do pamięci RAM i ich wykonywanie NASM 16b

  • I nie wydają się być w stanie przypisać ścieżkę do ważnego rejestru (albo błędna składnia)

  • muszę być w stanie wykonać drugi program po pierwszym (może być) uruchomił jego wykonanie.

To, co mam tak daleko:

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 

ja po prostu nie wiem jak uruchomić inny program poprzez wejście w programie „macierzystego”, po jednym jest już wykonywany.

Z góry dziękuję za pomoc! Wszelkie dodatkowe informacje, które z przyjemnością udzielę.

  • Nie jest nakładką.
  • Używam 16 bitów NAS, Windows 7 32 bitów.
+2

Naprawdę potrzebuję pomocy, oddając całą moją reputację jako nagrodę. –

+1

Interfejs API DOS ('int 21h') jest nieprzydatnym, praktycznie nieużywanym i niechcianym oprogramowaniem, którego nie wolno już używać. Czy jesteś ** absolutnie ** pewny, że musisz go użyć? –

+2

@DanielKozar Tak, absolutnie. W przeciwnym razie nie odmawiałbym mojej reputacji. Naprawdę potrzebuję pomocy w tej sprawie. –

Odpowiedz

7

Po kilku hakowaniach i szarpaniu, udało mi się sprawić, żeby to działało. To nie jest tak proste, jak miałem nadzieję, że tak będzie, więc trzymaj się swojego miejsca (siedzeń).

Po pierwsze, musisz zdać sobie sprawę (tak abstrakcyjnie, jak to może brzmieć), że DOS jest systemem jedno-i wielozadaniowym. W tym konkretnym przypadku oznacza to, że nie można współdziałać z dwoma procesami jednocześnie. Ty potrzebujesz, aby poczekać, aż jeden proces zakończy wykonywanie, zanim przejdzie do innego procesu. Współbieżność procesowa może być w pewnym stopniu emulowana przez procesy TSR (Terminate and Stay Resident), które pozostają w pamięci pomimo ich zakończenia i możliwe jest wznowienie ich wykonywania przez podpięcie niektórych przerwań z ich kodu i wywołanie go później z innego kodu. Jednak nie jest to ten sam rodzaj współbieżności, który jest używany przez nowoczesne systemy operacyjne, takie jak Windows i Linux. Ale nie o to chodziło.

Powiedziałeś, że używasz NASM jako swojego asemblera z wyboru, dlatego założyłem, że wyprowadzasz swój kod do plików COM, które z kolei są wykonywane przez polecenie systemowe DOS. Pliki COM ładowane są przez wiersz polecenia pod offsetem 100h (po załadowaniu skoku do tego miejsca jest wykonywany) i nie zawierają niczego innego poza "chudym" kodem i danymi - bez nagłówków, dlatego są najłatwiejsze do wytworzenia.

Zamierzam wyjaśnić źródło montażu w częściach, abyś mógł (być może) lepiej rzucić okiem na to, co dzieje się pod maską.

Program rozpoczyna się

org 100h 

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

dyrektywy org, który określa pochodzenie pliku, kiedy faktycznie załadowane do pamięci - w naszym przypadku jest to 100h. Deklaracje trzech etykiet to: exename i exename2, które są zakończonymi znakiem NUL ścieżkami programów do wykonania, oraz cmdline, która określa wiersz polecenia, który powinien otrzymać nowo utworzony proces. Zauważ, że nie jest to zwykły ciąg znaków: pierwszy bajt to liczba znaków w linii komend, a następnie sama linia poleceń i powrót karetki. W tym przypadku nie mamy parametrów wiersza poleceń, więc wszystko sprowadza się do db 0,0dh. Załóżmy, że chcemy przekazać -h -x 3 jako parametry: w takim przypadku będziemy musieli zadeklarować tę etykietę jako db 8," -h -x 3",0dh (proszę zwrócić uwagę na dodatkową przestrzeń na początku!). Przechodząc ...

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 

Etykieta dummy znajduje się zaledwie 20 bajtów, które zawierają zera. Poniżej znajduje się etykieta paramblock, która jest reprezentacją struktury EXEC wspomnianej przez Daniela Roethlisbergera. Pierwszy element to zero, co oznacza, że ​​nowy proces powinien mieć to samo środowisko, co jego element macierzysty. Podążają trzy adresy: do linii poleceń, do pierwszego FCB i drugiego FCB. Należy pamiętać, że adresy w trybie rzeczywistym składają się z dwóch części: adresu segmentu i przesunięcia w segmencie. Oba te adresy mają długość 16 bitów. Zostały zapisane w pamięci w nieco endianowskim stylu, z offsetem będącym pierwszym. Dlatego określamy linię poleceń jako offset cmdline, a adresy FCB jako przesunięcia na etykiecie dummy, ponieważ same FCB nie będą używane, ale adresy muszą wskazywać na prawidłowe położenie pamięci w dowolny sposób. Segmenty muszą być wypełnione w czasie wykonywania, ponieważ program ładujący wybiera segment, w którym jest ładowany plik COM.

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

Program rozpoczynamy od ustawienia pól segmentów w strukturze paramblock. Ponieważ w przypadku plików COM, CS = DS = ES = SS, tj. Wszystkie segmenty są takie same, po prostu ustawiamy te wartości w rejestrze cs.

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

Jest to właściwie jeden z najtrudniejszych punktów aplikacji. Kiedy plik COM jest ładowany do pamięci przez DOS, domyślnie przypisywana jest do niego cała dostępna pamięć (CPU nie ma o tym pojęcia, ponieważ jest w trybie rzeczywistym, ale i tak wewnętrzni DOS go śledzą). Dlatego wywołanie komendy EXEC powoduje niepowodzenie z No memory available. Dlatego musimy powiedzieć DOSowi, że naprawdę nie potrzebujemy całej tej pamięci, wykonując "ZMIEŃ PAMIĘĆ ZABLOKOWANIA" dzwoń pod numer (Ralf Brown). Rejestr bx ma mieć nowy rozmiar bloku pamięci w 16-bajtowych jednostkach ("akapitach"), więc ustawiamy go na 50, mając 800 bajtów dla naszego programu. Muszę przyznać, że ta wartość została wybrana losowo, próbowałem ustawić ją na coś, co miałoby sens (np. Wartość bazującą na rzeczywistym rozmiarze pliku), ale wciąż nie dochodziło do niczego.ES jest segmentem, który chcemy "zmienić rozmiar", w naszym przypadku jest to CS (lub jakikolwiek inny, ponieważ wszystkie są takie same po załadowaniu pliku COM). Po zakończeniu tego połączenia jesteśmy gotowi załadować nasz nowy program do pamięci i wykonać go.

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 

Kod ten powinien być dość oczywista, to wybiera ścieżkę do programu włożonej DX na podstawie standardowego wejścia.

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

To gdzie rzeczywista EXEC syscall (AH=4Bh) jest tzw. AL zawiera 0, co oznacza, że ​​program powinien zostać załadowany i wykonany. DS:DX zawiera adres ścieżki do pliku wykonywalnego (wybranego przez wcześniejszy fragment kodu), a ES:BX zawiera adres etykiety paramblock, która zawiera strukturę EXEC.

.end: 
    mov  ax,  4c00h 
    int  21h 

Po zakończeniu realizacji programu zwanego przez exec program rodzic jest zakończony z kodem wyjścia zero wykonując AH=4Ch syscall.

Dzięki vulture- z ## asm na Freenode po pomoc. Testowałem to z DOSBoxem i MS-DOS 6.22, więc mam nadzieję, że to działa również dla ciebie.

+0

Czy myślisz, że mogę uruchomić w tym samym czasie 2 programy? –

+4

** nie można ** uruchamiać aplikacji ** dosłownie ** w tym samym czasie. DOS na to nie pozwala. –

+1

@ DanielparamilKozar: Dobra odpowiedź. To jest tak całkowicie w 1980 roku ... –

4

Według this reference, nie jesteś ustawienie EXEC blok parametrów:

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 

Odnośny strona brakuje <pre>/</pre> tagów dla tej tabeli, dlatego trudno jest odczytać na stronie.

Będziesz musiał ustawić taki blok parametrów i punkt ES: BX na jego adres.


Czy jest jakiś szczególny powód, dla którego są targetting 16 bitowy (DOS API) zamiast Win32 API? Zakładając, że można uciec z targetting API Win32 zamiast, można uruchomić pliki wykonywalne zewnętrznych za pomocą wywołania WinExec w coś takiego szkieletu:

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 

Alternatywnie, można użyć bardziej nowoczesny ShellExecute połączenia.

+1

Jak robię kilka kursów, muszę zaprojektować na 16 bitów. Czy myślisz, że możesz mi pomóc z rozwiązaniem napisanym dla 16-bitowego DOS-a? Byłoby to bardzo doceniane. A przy okazji, czy powinienem po prostu pozbyć się tych popf? –

+1

Tak, po prostu usuń instrukcje 'popf'. –

+0

Edytowane w celu dodania 16-bitowych wskazówek. Nie uruchamiam DOS (a.k.a. Windows :)), więc nie mogę tego przetestować. –

Powiązane problemy