问题描述
使用 TASM 我试图分配一些应该用作缓冲区的内存。
要做到这一点,我首先使用以下方法释放分配给可执行文件的所有内存:
MOV BX,SS
MOV AX,ES
SUB BX,AX
MOV AX,SP
ADD AX,0fh
SHR AX,4
ADD BX,AX
MOV AH,4ah
INT 21h
之后我尝试使用以下方法分配 64000 个字节:
MOV AH,48h
MOV BX,64000/16
INT 21h
MOV buffer,AX
这似乎完美无缺,因为执行后未设置 CARRY 标志 指令 21h。
稍后我最终会尝试填充刚刚分配的内存,例如:
MOV BX,OFFSET BUFFER
MOV ES,BX
XOR DI,DI
MOV CX,64000/2
MOV AL,12
MOV AH,AL
REP STOSW
不幸的是,由于程序在 REP STOSW
指令处冻结而失败。
现在我有点迷茫,因为我找不到明显错误的东西。那么为什么会发生这种情况?
这是我的完整来源:
.MODEL LARGE
.STACK 100h
.DATA?
buffer DW ?
.CODE
Main:
MOV BX,4ah
INT 21h
MOV AH,AX
MOV BX,AL
REP STOSW
MOV AH,4ch
INT 21h
END Main
解决方法
MOV BX,OFFSET BUFFER
MOV ES,BX
DOS函数48h给你的信息是段地址。
以上代码将偏移量加载到包含此地址的变量中。您需要取消引用它:
MOV ES,buffer
直接来自AX
:
MOV AH,48h
MOV BX,64000/16
INT 21h ; -> AX CF
JC Fail ; Never forget to check for failure
MOV buffer,AX
MOV ES,AX
XOR DI,DI
MOV CX,64000/2
MOV AX,0C0Ch
CLD ; Clear direction flag at least once in your program
REP STOSW
Fail:
MOV AX,4C00h
INT 21h
[编辑]
.MODEL LARGE
.STACK 100h
.DATA?
buffer DW ?
.CODE
通过上面的代码,你的程序内存的高端最终看起来像:
.DATA? .STACK func 48h alloc
... <-- 16 bytes --><-- 256 bytes --><-- 64000 bytes --> ...
94h,08h,..,0
^ ^ ^
0883h 0884h 0894h <== paragraph addresses
<-- 272 bytes = 17 paragraphs -->
buffer 是 BSS (.DATA?
) 中第一个(也是唯一一个)变量的名称。
mov ax,offset buffer
加载 AX
为 0,因为 buffer 变量占据了 BSS 中的第一个单词。mov ax,seg buffer
使用 0883h 加载 AX
,这是在程序加载时分配的 BSS 段落地址。mov ax,buffer
加载 AX
与 0894h,buffer 变量的内容,这是 DOS 分配给 64000 字节分配的段落地址。
有关段和段落的更多解释,请阅读:What are Segments and how can they be addressed in 8086 mode?。