我迫切希望找到解决方案.我正在尝试开发汇编代码,允许我加载和执行(通过用户输入)2个其他Assembly .EXE程序.我有两个问题:
我似乎无法将路径名分配给有效的寄存器(或者可能是不正确的语法)
我需要能够在第一个程序(可能是其中一个)开始执行之后执行另一个程序.
这是我到目前为止:
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
Run Code Online (Sandbox Code Playgroud)
我只是不知道如何通过"父"程序中的输入启动另一个程序,在一个程序已经执行之后.
在此先感谢您的帮助!我非常乐意提供的任何其他信息.
在经历了一些黑客攻击和琐事之后,我才得以实现这一目标.这并不像我希望的那样简单,所以坚持你的座位.
首先,你需要认识到(尽管可能听起来很抽象)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
Run Code Online (Sandbox Code Playgroud)
该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
Run Code Online (Sandbox Code Playgroud)
标签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
Run Code Online (Sandbox Code Playgroud)
我们通过在paramblock结构中设置段字段来开始该程序.因为对于COM文件,CS = DS = ES = SS即所有段都相同,我们只需将这些值设置为cs寄存器中的值即可.
mov ax, 4a00h
mov bx, 50
int 21h
Run Code Online (Sandbox Code Playgroud)
这实际上是应用程序中最棘手的一点.当一个COM文件被DOS加载到内存中时,默认情况下会为它分配所有可用的内存(CPU不知道这个,因为它处于实模式,但DOS内部仍会跟踪它).因此,调用EXEC系统调用会导致失败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
Run Code Online (Sandbox Code Playgroud)
这段代码应该是不言自明的,它DX根据stdin 选择插入程序的路径.
.exec:
mov bx, paramblock
mov ax, 4b00h
int 21h
Run Code Online (Sandbox Code Playgroud)
这是EXEC调用实际的syscall(AH=4Bh)的地方.AL包含0,表示应该加载和执行程序.DS:DX包含可执行文件路径的地址(由前面的代码片段选择),并ES:BX包含paramblock标签的地址,其中包含EXEC结构.
.end:
mov ax, 4c00h
int 21h
Run Code Online (Sandbox Code Playgroud)
在完成被调用的程序的执行之后exec,通过执行AH=4Ch系统调用来终止父程序,退出代码为零.
感谢vulture-来自Freenode的## asm寻求帮助.我用DOSBox和MS-DOS 6.22测试了这个,所以希望它对你也有用.