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
| Line | What it reserves |
|---|---|
N DB 5 | one byte holding 5 (DB: define byte) |
W DW 1234H | one word, 2 bytes (DW: define word) |
LIST DB 1, 2, 3 | three 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 10 | no 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 MAINIn 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 MAINBYTE 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, Nwhen N is a byte. UseMOV AL, N. - Expecting
DW 1234Hto be stored as 12h, 34h: the low byte, 34h, comes first. - Writing
MOV [BX], 5: the assembler cannot tell byte from word. WriteMOV BYTE PTR [BX], 5.
Quick check
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.