Загрузка программ в ОЗУ и их выполнение NASM 16b
Я отчаянно нуждаюсь в решении этого. Я пытаюсь разработать код сборки, позволяющий загружать и выполнять(по вводу пользователя) 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:UsersUsuarioNASMAdding.exe',0
PROGNAME2 db 'C:UsersUsuarioNASMSubstracting.exe',0
Я просто не знаю, как запустить другую программу путем ввода в "родительскую" программу, после того, как она уже выполняется.
заранее спасибо за вашу помощь! Любую дополнительную информацию я буду более чем счастлив предоставить.
- не является наложением.
- Я использую NASM 16 бит, Windows 7 32 бит.
2 ответов
после некоторого взлома и скручивания, я смог заставить это работать. Это не так просто, как я надеялся, поэтому держитесь за свое место(места).
во-первых, вам нужно понять (как абстрактно это может звучать), что DOS-это однопользовательская, не многозадачная система. В этом конкретном случае это означает, что вы не можете одновременно запускать два процесса. Вы нужно дождаться завершения выполнения одного процесса перед переходом к другому процессу. Процесс параллелизм может быть несколько эмулирован с процессами TSR (Terminate и Stay Resident), которые остаются в памяти, несмотря на завершение, и можно возобновить их выполнение, подключив некоторые прерывания из своего кода и вызвав его из другого кода позже. Тем не менее, это не тот же вид параллелизма, который используется современными ОС, такими как Windows и Linux. Но дело было не в этом.
Вы сказали, что используете NASM как ваш ассемблер по выбору, поэтому я предположил, что вы выведите код в COM-файлы, которые, в свою очередь, выполняются командной строкой DOS. COM-файлы загружаются из командной строки в offset 100h
(после загрузки выполняется переход в это место) и не содержат ничего, кроме "бережливого" кода и данных - нет заголовков, поэтому их легче всего создать.
я собираюсь объяснить источник сборки по частям, так что вы можете (возможно) получить лучшее представление о том, что происходит под капотом.
программа начинается с
org 100h
section .data
exename db "C:\hello.com",0
exename2 db "C:\nasm\nasm.exe",0
cmdline db 0,0dh
the org
директива, которая указывает происхождение файла при фактической загрузке в память - в нашем случае это 100h
. Далее следуют объявления трех меток,exename
и exename2
которые являются завершенными null путями программ для выполнения и cmdline
, который указывает командную строку, которую должен получить вновь созданный процесс. Обратите внимание, что это не просто обычная строка : первый байт-это количество символов в командной строке, то сама командная линия и возвращение кареты. В этом случае у нас нет параметров командной строки, поэтому все сводится к db 0,0dh
. Предположим, мы хотим пройти -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
label, который является представлением структуры EXEC, упомянутой Даниэлем Ротлисбергер. Первый элемент равен нулю, что означает, что новый процесс должен иметь ту же среду, что и его родитель. Далее следуют три адреса: к командной строке, к первому FCB и ко второму FCB. Следует помнить, что адреса в реальном режиме состоят из двух частей : адреса сегмента и смещения в сегмент. Оба этих адреса имеют длину 16 бит. Они записаны в памяти в стиле Литтл-Энди, причем смещение-первое. Поэтому мы указываем командную строку как смещение cmdline
, и адреса FCBs как смещения к метке dummy
, так как сами FCBs не будут использоваться, но адреса должны указывать на действительное местоположение памяти в любом случае. Сегменты должны быть заполнены во время выполнения, так как загрузчик выбирает сегмент, в котором загружается 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
это на самом деле один из самых сложных пунктов Приложения. Когда COM-файл загружается в память DOS, ему по умолчанию назначается вся доступная память (CPU понятия не имеет об этом, так как он находится в реальном режиме, но DOS internals все равно отслеживают его). Поэтому вызов EXEC syscall приводит к сбою с No memory available
. Поэтому нам нужно сказать DOS, что нам действительно не нужна вся эта память выполнив "изменение размера блока памяти"AH=4Ah
вызов (Ральф Браун). The bx
регистр должен иметь новый размер блока памяти в 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
на основе stdin.
.exec:
mov bx, paramblock
mov ax, 4b00h
int 21h
на EXEC
syscall (AH=4Bh
) называется. AL
содержит 0, что означает, что программа должна быть загружена и казнен. DS:DX
содержит адрес пути к исполняемому файлу (выбранному более ранним фрагментом кода) и ES:BX
содержит адрес paramblock
метка, которая содержит EXEC
структура.
.end:
mov ax, 4c00h
int 21h
после завершения выполнения программы вызывается exec
, родительская программа завершается с нулевым кодом выхода, выполнив AH=4Ch
syscall.
спасибо vulture-
из ##asm на Freenode за помощью. Я проверял это DOSBox и MS-DOS 6.22, поэтому, надеюсь, он работает и для вас.
по данным этой ссылке, вы не устанавливаете блок параметров 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 на его адрес.
есть ли какая-либо конкретная причина, по которой вы нацеливаете 16 бит (DOS API) вместо Win32 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 звонок.