ASM EXE program 16bit: Error changing size of memory

匆匆过客 提交于 2020-12-26 04:27:59

问题


I write EXE program with SMALL model.
I want to load other programs with the help of my program. I read that first of all I must free some memory. I use DOS 4Ah INT 21h interrupt. But I have error 7 (control units memory is destroyed) in AX when use it. What I made incorrect?

;-------------------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

For compile I use TASM 16 bit with DOSBox 0.74


回答1:


You don't need to free memory in an .exeprogram. Only a .com program reserves all memory. It's rather complicated to determine the real last byte of an .exe program and to find the segment of the allocated block. BTW: In a .com program you must adjust the stack pointer!

As @RossRidge mentions, some linkers (e.g. TLINK) write into the header an information to allocate the maximum memory. This is annoying.

You can modify this header item by using a tool like Microsoft's exemod which is contained in the MASM suites (versions < 6). A suite is downloadable here. The exemod utility can be found in DISK4. Use it like:

exemod <exefile> /max 1

Another option is to resize the allocated memory inside the program. Make first a simple program HELLO.EXE to be executed by a parent program:

.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

Now the parent:

.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

The end of the program is determined by the stack pointer. You should therefore be sure that the STACK segment is the last segment in the program. Generate a .MAP file with the tlink command line option /s. It should look like:

 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

As you can see STACK is the last segment listed here.

Now you can run the parent and read what the child (HELLO.EXE) has to tell :-)



来源:https://stackoverflow.com/questions/43214906/asm-exe-program-16bit-error-changing-size-of-memory

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!