我迫切需要一个解决方案。我正在尝试开发允许我加载和执行(通过用户输入)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
。紧随其后的是三个标签的声明,exename
和exename2
是要执行的程序的空终止路径,而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/