2017-04-04 51 views
1

我写EXE程序与模型。
我想借助我的程序加载其他程序。我读到,首先我必须释放一些记忆。我用DOS 4Ah INT 21h中断。但是在使用AX时,我有错误7(控制单元内存被破坏)。我做错了什么?ASM EXE程序16bit:错误改变内存大小

;-------------------MACRO----------------- 
println MACRO info 
    push ax 
    push dx 

    mov ah, 09h 
    mov dx, offset info 
    int 21h 

    ;print new line 
    mov dl, 10 
    mov ah, 02h 
    int 21h 

    mov dl, 13 
    mov ah, 02h 
    int 21h 

    pop dx 
    pop ax 
ENDM 
;-----------------end macro---------------- 

.model small 

.stack 100h 

.data 

initToRunErrorText db "Bad init to run other programs", '$' 

myDataEnd db '0' 

.code 

main: 
    mov ax, @data 
    mov es, ax 
    mov ds, ax 

    call initToRun 

    mov ah, 4Ch 
    int 21h 

; Result 
;  ax = 0 => all is good 
;  ax != 0 => we have an error 
initToRun PROC 
    push ax bx 

    mov ah, 4Ah 
    mov bx, offset myDataEnd + 100h 
    shr bx, 4 
    add bx, 2 
    int 21h 

    jnc initToRunAllGood 

    add ax, '0' 
    mov dl, al 
    mov ah, 06h 
    int 21h 

    mov ax, 1 
    println initToRunErrorText 

    jmp initToRunEnd 

initToRunAllGood: 
    mov ax, 0 

initToRunEnd: 
    pop bx ax 
    ret 
ENDP 

program_length equ $-main 

end main 

对于编译我用TASM 16位与DOSBox中0.74

+1

您忘记设置'es'。 – Jester

+0

@Jester mov es,ax - 主 – AJIOB

+0

您不需要在'.exe'程序中释放内存。只有'.com'程序保留所有内存。 – rkhb

回答

2

你不需要在.exe程序来释放内存。只有一个.com程序保留所有内存。确定.exe程序的实际最后一个字节并查找分配块的段是相当复杂的。顺便说一句:在.com程序中,您必须调整堆栈指针!

正如@RossRidge所提到的,一些链接器(例如TLINK)在头部写入信息以分配最大内存。这很烦人。

您可以使用包含在MASM套件(版本< 6)中的工具(如微软的exemod)来修改此标题项目。套房可下载here。 exemod实用程序可以在DISK4中找到。使用它像:

exemod <exefile> /max 1 

另一种方法是调整程序内分配的内存。使第一一个简单的程序HELLO.EXE到由父程序来执行:

.MODEL small 
.STACK   ; default: 1000h 
.DATA 
    hello db "Hello world", 13, 10, "$" 
.CODE 
main PROC 
    mov ax, @data 
    mov ds, ax 
    mov dx, OFFSET hello 
    mov ah, 09h 
    int 21h 
    mov ax, 4C00h 
    int 21h 
main ENDP 
END main 

现在母体:

.MODEL small 

.STACK 

.DATA 
    hello db "HELLO.EXE", 0 

    params label word 
     dw 0 
     dw OFFSET command_line, SEG command_line 
     dw 0ffffh,0ffffh ; fcb1 
     dw 0ffffh,0ffffh ; fcb2 

    command_line db 0,13 

.CODE 

free_memory PROC 
    mov ax, sp    ; SS:SP -> nearly the end of program 
    shr ax, 4 
    mov bx, ss 
    add bx, ax 
    add bx, 2    ; BX = a paragraph beyond program 
    mov ax, es    ; ES -> first paragraph of the program (containing PSP) 
    sub bx, ax    ; BX = program size in paragraphs 
    mov ah, 4ah    ; Resize memory block - http://www.ctyme.com/intr/rb-2936.htm 
    int 21h     ; Call MS-DOS 

    ret 
free_memory ENDP 

execute_hello PROC 
    push ds     ; Save DS 
    push es     ; Save ES 

    mov cs:[stk_seg],ss  ; Save stack pointer 
    mov cs:[stk_ptr],sp 

    mov ax, 4B00h 
    mov dx, OFFSET hello 
    mov bx, SEG params 
    mov es, bx 
    mov bx, OFFSET params 

    mov ax,4b00h   ; Exec - load and/or execute program - http://www.ctyme.com/intr/rb-2939.htm 
    int 21h     ; Call MS-DOS 

    cli      ; Let no interrupt disturb 
    mov ss,cs:[stk_seg]  ; Restore stack pointer 
    mov sp,cs:[stk_ptr] 
    sti      ; Allow interrupts 

    pop es     ; Restore ES and DS 
    pop ds 
    ret 

    ; Data for this function in the code segment 
    stk_ptr dw 0 
    stk_seg dw 0 
execute_hello ENDP 

main PROC 
    mov ax, @data   ; Initialize DS 
    mov ds, ax 

    call free_memory  ; ES should point to PSP (default) 
    call execute_hello 

    mov ax, 4C00h   ; Terminate with return code - http://www.ctyme.com/intr/rb-2974.htm 
    int 21h     ; Call MS-DOS 
main ENDP 

END main 

该方案的端部由堆栈指针来确定。因此,您应该确保STACK段是程序中的最后一个段。使用tlink命令行选项/s生成.MAP文件。它应该看起来像:

Start Stop Length Name    Class 

00000H 0005BH 0005CH _TEXT    CODE 
00060H 00079H 0001AH _DATA    DATA 
00080H 0047FH 00400H STACK    STACK 


Detailed map of segments 

0000:0000 005C C=CODE S=_TEXT   G=(none) M=INBBC8~1.ASM ACBP=48 
0006:0000 001A C=DATA S=_DATA   G=DGROUP M=INBBC8~1.ASM ACBP=48 
0006:0020 0400 C=STACK S=STACK   G=DGROUP M=INBBC8~1.ASM ACBP=74 

Program entry point at 0000:004C 

正如你可以看到STACK在这里列出的最后一段。

现在您可以运行父级并阅读孩子(HELLO.EXE)必须告诉:-)

+0

实际上你需要释放TLINK创建的.EXE程序中的内存,因为它将EXE头中的最大段落分配给FFFFh,这意味着MS-DOS会为它分配最大的内存块,就像.COM文件一样。这当然假设你需要为其他东西分配内存,比如产生另一个程序,否则无论你使用.EXE还是.COM文件,都不需要释放内存。 –

+0

@RossRidge:你说得对。我找不到链接来下载像exemod.exe这样的工具。你知道吗?我想当我添加一个段落和一个链接时,我不需要删除这个答案(关于漂亮的15分太糟糕了)。 – rkhb

+0

@RossRidge好的,我怎样才能释放内存来产生新的程序? – AJIOB