Загрузка программ в ОЗУ и их выполнение 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 звонок.