ASM EXE 程序 16 位:更改内存大小时出错
ASM EXE program 16bit: Error changing size of memory
我用 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
您不需要在 .exe
程序中释放内存。只有 .com
程序保留所有内存。确定 .exe
程序的真正最后一个字节并找到分配块的段是相当复杂的。顺便说一句:在 .com
程序中你必须调整堆栈指针!
正如@RossRidge 所提到的,一些链接器(例如 TLINK)写入 header 信息以分配最大内存。这很烦人。
您可以使用 MASM 套件(版本 < 6)中包含的 Microsoft exemod
等工具修改此 header 项目。可以下载套件 here。 exemod 实用程序可以在 DISK4 中找到。像这样使用它:
exemod <exefile> /max 1
另一种选择是调整程序内部分配的内存大小。首先制作一个简单的程序 HELLO.EXE
由 parent 程序执行:
.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
现在 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
程序结束由堆栈指针决定。因此,您应该确保 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
是此处列出的最后一段。
现在您可以 运行 parent 并阅读 child (HELLO.EXE) 必须讲述的内容:-)
我用 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
您不需要在 .exe
程序中释放内存。只有 .com
程序保留所有内存。确定 .exe
程序的真正最后一个字节并找到分配块的段是相当复杂的。顺便说一句:在 .com
程序中你必须调整堆栈指针!
正如@RossRidge 所提到的,一些链接器(例如 TLINK)写入 header 信息以分配最大内存。这很烦人。
您可以使用 MASM 套件(版本 < 6)中包含的 Microsoft exemod
等工具修改此 header 项目。可以下载套件 here。 exemod 实用程序可以在 DISK4 中找到。像这样使用它:
exemod <exefile> /max 1
另一种选择是调整程序内部分配的内存大小。首先制作一个简单的程序 HELLO.EXE
由 parent 程序执行:
.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
现在 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
程序结束由堆栈指针决定。因此,您应该确保 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
是此处列出的最后一段。
现在您可以 运行 parent 并阅读 child (HELLO.EXE) 必须讲述的内容:-)