将程序加载到RAM并执行它们NASM 16b [英] Loading programs to RAM and executing them NASM 16b

查看:102
本文介绍了将程序加载到RAM并执行它们NASM 16b的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我很想解决这个问题.我正在尝试开发允许我加载和执行(通过用户输入)2个其他Assembly .EXE程序的Assembly代码.我有两个问题:

I'm desperate for a solution to this. I'm trying to develop Assembly code allowing me to load and execute(by input of the user) 2 other Assembly .EXE programs. I'm having two problems:

  • 我似乎无法将路径名分配给有效的寄存器(或者语法错误)

  • I don't seem to be able to assign the pathname to a valid register(Or maybe incorrect syntax)

在第一个程序(可能是一个程序)开始执行之后,我需要能够执行另一个程序.

I need to be able to execute the other program after the first one (could be either) started its execution.

这是我到目前为止所拥有的:

This is what I have so far:

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

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

I just don't know how to start another program by input in the 'parent' program, after one is already executing.

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

Thanks in advance for your help! Any additional information I'll be more than happy to provide.

  • 不是叠加层.
  • 我正在使用16位NASM,Windows 7 32位.

推荐答案

经过一番黑客和细读,我能够使它正常工作.这并不像我希望的那么简单,所以请紧握您的座位.

After some hacking and twiddling, I was able to get this working. It's not as straightforward as I hoped it would be, so hold on to your seat(s).

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

Firstly, you need to realize (as abstract as that may sound) that DOS is a single-user, non-multitasking system. In this particular case, it means that you can't have two processes running concurrently. You need to wait for one process to finish execution before moving to another process. Process concurrency may be somewhat emulated with TSR (Terminate and Stay Resident) processes, which stay in memory despite being terminated and it's possible to resume their execution by hooking some interrupts from their code and calling it from some other code later on. Still, it's not the same kind of concurrency that's used by modern OSes, like Windows and Linux. But that wasn't the point.

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

You said that you're using NASM as your assembler of choice, therefore I assumed that you output your code to COM files, which are in turn executed by the DOS command prompt. COM files are loaded by the command prompt at offset 100h (after loading a jump to that location is executed) and don't contain anything else but "lean" code and data - no headers, thus they're the easiest to produce.

我将逐个解释汇编源代码,以便您(也许)更好地了解引擎盖下发生的事情.

I'm going to explain the assembly source in pieces, so that you can (perhaps) get a better glimpse of what's going on under the hood.

程序始于

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(请注意开头有多余的空格!).继续...

the org directive, which specifies the origin of the file when actually loaded into memory - in our case, this is 100h. Declarations of three labels follow, exename and exename2 which are null-terminated paths of the programs to execute, and cmdline, which specifies the command line that the newly created process should receive. Note that it isn't just a normal string : the first byte is the number of characters in the commandline, then the commandline itself, and a Carriage Return. In this case, we have no commandline parameters, so the whole thing boils down to db 0,0dh. Suppose we wanted to pass -h -x 3 as the params : in that case, we'd need to declare this label as db 8," -h -x 3",0dh (note the extra space at the beginning!). Moving on...

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文件的段.

The label dummy is just 20 bytes which contain zeroes. What follows is the paramblock label, which is a representation of the EXEC structure mentioned by Daniel Roethlisberger. The first item is a zero, which means that the new process should have the same environment as its parent. Three addresses follow : to the commandline, to the first FCB, and the second FCB. You should remember that addresses in real mode consist of two parts : the address of the segment and the offset into the segment. Both those addresses are 16 bits long. They're written in the memory in little endian fashion, with the offset being first. Therefore, we specify the commandline as offset cmdline, and addresses of the FCBs as offsets to the label dummy, since the FCBs themselves are not going to be used but the addresses need to point to a valid memory location either way. The segments need to be filled at runtime, since the loader chooses the segment at which the COM file is loaded.

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寄存器中的值即可.

We begin the program by setting the segment fields in the paramblock structure. Since for COM files, CS = DS = ES = SS, i.e. all the segments are the same, we just set those values to what's in the cs register.

mov     ax, 4a00h
mov     bx, 50
int     21h

这实际上是应用程序最棘手的地方之一.当DOS将COM文件加载到内存中时,默认情况下会为它分配所有可用内存(由于CPU处于实模式,因此CPU对此一无所知,但是DOS内部始终会跟踪它).因此,调用EXEC syscall会导致它失败,并显示No memory available.因此,我们需要通过执行"RESIZE MEMORY BLOCK" AH=4Ah调用(拉尔夫·布朗). bx寄存器应该以16字节为单位具有新的内存块大小(段落"),因此我们将其设置为50,程序中有800字节.我必须承认这个值是随机选择的,我尝试将其设置为有意义的值(例如,基于实际文件大小的值),但我一直无所适从. ES是我们要调整大小"的段,在本例中为CS(或其他任何段,因为加载COM文件时它们都相同).完成此调用后,我们准备将新程序加载到内存中并执行它.

This is actually one of the trickiest points of the application. When a COM file is loaded into the memory by DOS, it is assigned all the available memory by default (the CPU has no idea about this, since it's in real mode, but DOS internals keep track of it anyway). Therefore, calling the EXEC syscall causes it to fail with No memory available. Therefore, we need to tell DOS that we don't really need all that memory by executing the "RESIZE MEMORY BLOCK" AH=4Ah call (Ralf Brown). The bx register is supposed to have the new size of the memory block in 16-byte units ("paragraphs"), so we set it to 50, having 800 bytes for our program. I have to admit that this value was chosen randomly, I tried setting it to something which would make sense (e.g. a value based on the actual file size), but I kept getting nowhere. ES is the segment that we want to "resize", in our case that's CS (or any other one, since they're all the same when a COM file is loaded). After completing this call, we're ready to load our new program to memory and execute it.

    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中的程序的路径.

This code should be pretty self-explanatory, it chooses the path to the program inserted into DX based on the stdin.

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

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

This is where the actual EXEC syscall (AH=4Bh) is called. AL contains 0, which means that the program should be loaded and executed. DS:DX contains the address of the path to the executable (chosen by the earlier piece of code), and ES:BX contains the address of the paramblock label, which contains the EXEC structure.

.end:
    mov     ax,     4c00h
    int     21h

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

After finishing the execution of the program called by exec, the parent program is terminated with an exit code of zero by executing the AH=4Ch syscall.

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

Thanks to vulture- from ##asm on Freenode for help. I tested this with DOSBox and MS-DOS 6.22, so hopefully it works for you as well.

这篇关于将程序加载到RAM并执行它们NASM 16b的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆