1

Using TASM I'm trying to allocate some memory which should serve as a buffer.

To do this I first deallocate all the memory which has been given to the executable using:

    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

Afterwards I'm trying to allocate 64000 bytes using:

    MOV     AH, 48h
    MOV     BX, 64000/16 
    INT     21h
    MOV     buffer, AX

which seems to work flawlessly as the CARRY flag ain't set after executing instruction 21h.

Later on I'm ultimately trying to fill the just allocated memory like:

    MOV     BX, OFFSET BUFFER
    MOV     ES, BX

    XOR     DI,DI
   
    MOV     CX,64000/2
    MOV     AL,12
    MOV     AH,AL
    REP     STOSW

which unfortunately fails as the program freezes at the REP STOSW instruction. Now I'm a little lost as I can't find something obviously wrong. So why is this happening?

Here's my full source:

.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      
obscure
  • 11,916
  • 2
  • 17
  • 36

1 Answers1

2
MOV     BX, OFFSET BUFFER
MOV     ES, BX

The info that DOS function 48h gave you is a paragraph address.

The above code loads the offset to the variable that contains this address. You need to dereference it:

MOV     ES, buffer

Directly from 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

[edit]

.MODEL LARGE

.STACK 100h
.DATA? 
buffer      DW ?

.CODE

With the above code, the high end of your program memory finally looks like:

    .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 is the name of the first (and only) variable in your BSS (.DATA?).

mov ax, offset buffer loads AX with 0 because the buffer variable occupies the very first word in the BSS.
mov ax, seg buffer loads AX with 0883h, the paragraph address of the BSS as assigned at program load time.
mov ax, buffer loads AX with 0894h, the contents of the buffer variable and that is the paragraph address that DOS assigned to the 64000-byte allocation.

For some more explanation about segments and paragraphs read this: What are Segments and how can they be addressed in 8086 mode?.

Sep Roland
  • 33,889
  • 7
  • 43
  • 76
  • Sorry for coming back to this but I could use some clarification Roland. Dos 48h allocates some memory for me (if available) and in case returns a paragraph address. Now I thought 'paragraph' is just another word for 'segment', isn't it? However if I do something like **MOV ES, buffer MOV AX, SEG buffer** (to obtain the segment address) and ultimately compare the values inside the AX and ES, I get 894h for ES vs 883h for the segment address in AX. What causes the difference? – obscure Jan 26 '21 at 15:50
  • *buffer* is the name of a variable in your BSS (`.DATA?`). There, that variable is located at a certain "OFFSET" as well as the BSS itself being located at a certain "SEG". The assembler allows you to retrieve these values via `mov ax, offset buffer` and `mov ax, seg buffer`. What the `mov es, buffer` instruction does is retrieving **the value that is stored IN the variable**. So nothing to do with **WHERE** that variable is in memory. – Sep Roland Jan 27 '21 at 22:23
  • Yeah, I'm completely aware what those instructions and my own variables do - what I do not know is the difference between a segment and a paragraph. From what I thought the paragraph address returned to the AX register after int 21h IS the segment address. Obviously it ain't since those two values differ by 17 bytes. So What are those two? =) – obscure Jan 27 '21 at 22:31
  • Reread my explanation. Those two values must differ (with a very high probability). They are totally different things. Why would they have to hold the same value? – Sep Roland Jan 27 '21 at 22:34
  • Segment addresses and paragraph addresses are in essense the same thing. Every segment (64KB) starts at a paragraph address in memory. And every paragraph is a 16-byte chunk of memory. There are 65536 heavily overlapping 64KB segments in the 1MB memory. – Sep Roland Jan 27 '21 at 22:36
  • Here's a novel idea! Rename your confusingly named *buffer* variable (which is a mere WORD in the BSS) into *PointerToMyBigBuffer*. That ought to make the distinction... – Sep Roland Jan 27 '21 at 22:38
  • The edit to the answer explains the difference between 883h and 894h. Hope it helps. – Sep Roland Jan 28 '21 at 00:22