assembly - 将程序加载到RAM并执行它们NASM 16b

标签 assembly x86 nasm

我迫切需要一个解决方案。我正在尝试开发允许我加载和执行(通过用户输入)2个其他Assembly .EXE程序的Assembly代码。我有两个问题:


我似乎无法将路径名分配给有效的寄存器(或者语法错误)
在第一个程序(可以是任何一个)开始执行之后,我需要能够执行另一个程序。


这是我到目前为止的内容:

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


我只是不知道在已经执行完后如何通过在“父”程序中输入来启动另一个程序。

在此先感谢您的帮助!我会很乐意提供任何其他信息。


不是叠加层。
我使用的是NASM 16位,Windows 7 32位。

最佳答案

经过一番黑客和打乱之后,我能够使它工作。它不像我希望的那样简单明了,所以请紧握您的座位。

首先,您需要意识到DOS是一个单用户,非多任务系统(听起来可能很抽象)。在这种情况下,这意味着您不能同时运行两个进程。您需要等待一个进程完成执行,然后再移至另一进程。 TSR(终止并驻留)进程可以在某种程度上模拟进程并发性,尽管它们被终止,但仍保留在内存中,并且有可能通过钩住代码中的某些中断并随后从其他代码中调用来恢复其执行。但是,它与现代操作系统(例如Windows和Linux)所使用的并发类型不同。但这不是重点。

您说您正在使用NASM作为首选的汇编程序,因此我假设您将代码输出到COM文件,这些文件又由DOS命令提示符执行。 COM文件是通过命令提示符在偏移量100h处加载的(在执行到该位置的跳转加载后),并且除“精简”代码和数据外不包含其他任何内容-没有标头,因此它们最容易生成。

我将分批解释汇编源代码,以便您(也许)可以更好地了解引擎盖下的情况。

该程序开始于

org 100h

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


org指令,它指定实际加载到内存中时文件的来源-在我们的示例中为100h。紧随其后的是三个标签的声明,exenameexename2是要执行的程序的空终止路径,而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标签,它表示Daniel Roethlisberger提到的EXEC结构。第一项为零,表示新进程应与其父进程具有相同的环境。三个地址:命令行,第一个FCB和第二个FCB。您应该记住,实模式下的地址由两部分组成:段的地址和段的偏移量。这些地址均为16位长。它们以小尾数形式写入内存中,偏移量是第一个。因此,我们将命令行指定为偏移量cmdline,将FCB的地址指定为标签dummy的偏移量,因为将不使用FCB本身,但是地址必须以两种方式都指向有效的内存位置。由于加载程序会选择在其中加载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


这实际上是应用程序最棘手的地方之一。当DOS将COM文件加载到内存中时,默认情况下会为它分配所有可用内存(由于CPU处于实模式,因此CPU对此一无所知,但DOS内部始终会跟踪它)。因此,调用EXEC syscall会导致它失败,并显示No memory available。因此,我们需要通过执行“ RESIZE MEMORY BLOCK” AH=4Ah调用(Ralf Brown)来告诉DOS,我们实际上并不需要所有的内存。 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中的程序的路径。

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


这是实际的EXEC系统调用(AH=4Bh)的调用位置。 AL包含0,表示应加载并执行程序。 DS:DX包含可执行文件路径的地址(由前面的代码选择),而ES:BX包含paramblock标签的地址,其中包含EXEC结构。

.end:
    mov     ax,     4c00h
    int     21h


在完成由exec调用的程序的执行之后,通过执行AH=4Ch syscall,以退出代码零终止父程序。

感谢Freenode上## asm的vulture-的帮助。我使用DOSBox和MS-DOS 6.22进行了测试,因此希望它也对您有用。

关于assembly - 将程序加载到RAM并执行它们NASM 16b,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10006072/

相关文章:

C - 外部汇编函数使用相同的输入返回不同的结果

assembly - 微融合和寻址模式

x86 - 术语 'amd64' 'x64' 和 'x86' 的含义是什么?

string - dw 和 dd 与字符串的 db 指令有何不同?

WiX 安装程序始终安装到 x86 和 x64 上的 "Program Files"目录

assembly - 8086 无操作系统编程;分割

c - NASM 在 C 中无法正确运行

assembly - 如何修复汇编中的 "Segmentation fault (core dumped)"?

linux - nasm 可以生成二进制文件的调试符号吗?

使用 gnu 链接器更改入口点