填充动态分配的内存会冻结程序执行

问题描述

使用 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?