【问题标题】:ASM EXE program 16bit: Error changing size of memoryASM EXE 程序 16 位:更改内存大小时出错
【发布时间】:2017-04-04 18:27:09
【问题描述】:

我用SMALL模型编写EXE程序。
我想在我的程序的帮助下加载其他程序。我读到首先我必须释放一些内存。我使用DOS 4Ah INT 21h 中断。但是我在使用 AX 时出现错误 7(控制单元内存被破坏)。我做错了什么?

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

【问题讨论】:

  • 你忘了设置es
  • @Jester mov es, ax - in main
  • 您不需要在.exe 程序中释放内存。只有.com 程序保留所有内存。
  • @rkhb 好的,请把它写成答案。谢谢你,伙计

标签: assembly tasm 16-bit


【解决方案1】:

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

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

您可以使用包含在 MASM 套件(版本 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) 必须告诉的内容 :-)

【讨论】:

  • 实际上你确实需要在 TLINK 创建的 .EXE 程序中释放内存,因为它将 EXE 标头中的最大段落分配字段设置为 FFFFh,这意味着 MS-DOS 将分配最大的块它的内存,就像一个 .COM 文件。这当然假设您需要为其他事情分配内存,例如生成另一个程序,否则无论您使用的是 .EXE 还是 .COM 文件,您都不需要释放内存。
  • @RossRidge:你是对的。我找不到下载像exemod.exe 这样的实用程序的链接。你认识一个吗?我想当我添加一个段落和一个链接时,我不需要删除这个答案(漂亮的 15 分太糟糕了)。
  • @RossRidge 好的,我怎样才能释放内存来生成新程序?
  • @AJIOB:请看我调整后的答案。
  • Microsoft 有另一个用于编辑 MZ EXE 标头的实用程序,称为 EXEHDR,我认为它更常见,但如果没有 MSDN 订阅,我不知道您现在从哪里获得它。不过,编写一个更改最大段落字段的程序并不难。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-22
  • 2011-11-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多