Variables and the data segment

Variables live in the data segment, after .DATA. A variable is just a name for an address: the assembler lays the data out byte after byte and remembers where each name starts (its offset).

Defining data

LineWhat it reserves
N DB 5one byte holding 5 (DB: define byte)
W DW 1234Hone word, 2 bytes (DW: define word)
LIST DB 1, 2, 3three bytes, an array
MSG DB 'Hi$'a string: one byte per character
BUF DB 10 DUP(0)10 bytes, all 0 (DUP: duplicate)
X DW ?a word with no starting value (?)
TEN EQU 10no memory at all: a name for the number 10

$ inside a DB or EQU line means "the current offset", so LEN EQU $ - MSG right after MSG is the string's length.

; Bytes, words, strings and arrays in the data segment.
.MODEL SMALL
.STACK 100H
.DATA
    N     DB 5
    TOTAL DW ?             ; no starting value
    LIST  DB 10, 20, 30
    MSG   DB 'Done$'
    LEN   EQU $ - MSG      ; 5: the length of MSG, counted by the assembler
.CODE
MAIN PROC
    MOV AX, @DATA
    MOV DS, AX
    MOV AL, N              ; AL = 5 (the value at N)
    ADD AL, LIST           ; + 10 (the first byte of LIST)
    MOV LIST + 2, AL       ; store 15 in LIST's third byte
    MOV TOTAL, 300         ; a word variable takes a 16-bit value
    MOV CL, LEN            ; CL = 5
    LEA DX, MSG            ; the address of MSG, for service 9
    MOV AH, 9
    INT 21H
    MOV AH, 4CH
    INT 21H
MAIN ENDP
END MAIN
Open in compiler

In the CPU view, the data segment shows each variable, its offset (DS:0000h, ...) and its bytes. A byte written as ? shows as ? until the program stores something there.

Address or value?

MOV AL, N reads the value stored at N. LEA DX, MSG (or MOV DX, OFFSET MSG) loads its address. INT 21h's string service wants the address, which is why lesson 1 used LEA.

Square brackets mean "the memory at": MOV AL, [BX] reads the byte whose address is in BX. A variable name alone already means its memory, so MOV AL, N and MOV AL, [N] are the same.

Words are stored low byte first

The 8086 is little-endian: a word is stored with its low byte at the lower address. W DW 1234H puts 34h first, then 12h:

; A word is stored low byte first.
.MODEL SMALL
.STACK 100H
.DATA
    W DW 1234H             ; memory holds 34h, then 12h
.CODE
MAIN PROC
    MOV AX, @DATA
    MOV DS, AX
    MOV AX, W              ; read the whole word: AX = 1234h
    MOV BL, BYTE PTR W     ; the byte at offset 0: 34h
    MOV BH, BYTE PTR W + 1 ; the byte at offset 1: 12h
    MOV BYTE PTR W, 0      ; change only the low byte: W = 1200h
    MOV CX, W
    MOV AH, 4CH
    INT 21H
MAIN ENDP
END MAIN
Open in compiler

BYTE PTR and WORD PTR say how much memory to use when the assembler cannot tell, for example MOV BYTE PTR [BX], 0. Here they read one byte out of a word variable.

Common mistakes

  • Confusing a variable's value (MOV AL, N) with its address (LEA BX, N).
  • Using a DB variable with a 16-bit register: MOV AX, N when N is a byte. Use MOV AL, N.
  • Expecting DW 1234H to be stored as 12h, 34h: the low byte, 34h, comes first.
  • Writing MOV [BX], 5: the assembler cannot tell byte from word. Write MOV BYTE PTR [BX], 5.

Quick check

1. How many bytes does ARR DB 5 DUP(?) reserve?
2. W DW 0ABCDH is at offset 0. Which byte is at offset 0?
3. What does LEA DX, MSG put in DX?
4. What does TEN EQU 10 reserve in memory?
My notes

Write down what you want to remember from this lesson. Notes are saved on this device as you type, and appear on your dashboard.