使用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标志指令21 h。
之后,我最终试图填充刚刚分配的内存,如:
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, SS
MOV AX, ES
SUB BX, AX
MOV AX, SP
ADD AX, 0fh
SHR AX, 4
ADD BX, AX
MOV AH, 4ah
INT 21h
MOV AH, 48h
MOV BX, 64000/16
INT 21h
MOV buffer, AX
MOV BX, OFFSET BUFFER
MOV ES, BX
XOR DI,DI
MOV CX,64000/2
MOV AL,12
MOV AH,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,0,..,0
^ ^ ^
0883h 0884h 0894h <== paragraph addresses
<-- 272 bytes = 17 paragraphs -->
buffer是BSS (.DATA?
)中第一个(也是唯一一个)变量的名称。
mov ax, offset buffer
以0加载AX
,因为缓冲区变量占用了BSS中的第一个单词。
mov ax, seg buffer
用0883h加载AX
, 0883h是程序加载时分配给BSS的段地址。
mov ax, buffer
用0894h加载AX
,这是缓冲区变量的内容,这是DOS分配给64000字节分配的段地址。
关于分段和段落的更多解释,请阅读:什么是分段以及如何在8086模式下对分段进行处理?