Assembler Directives, Labels, and Macros
Control how the assembler builds your program — directives are instructions to the tool, not the CPU
Open interactive version (quiz + challenge)Real-world analogy
What is it?
Assembler directives are commands that control the assembler tool itself rather than generating CPU instructions. They define data (DB, DW, DD), create constants (EQU), set memory origins (ORG), organize segments (SEGMENT/ENDS, ASSUME), name procedures (PROC/ENDP), and create code templates (MACRO/ENDM). Labels mark locations in code and data for reference by instructions and other directives.
Real-world relevance
Every real assembly program uses directives extensively. BIOS source code uses SEGMENT directives to map ROM regions. DOS programs use ORG 100h for COM files. Kernel bootloaders define data structures with DB/DW. Device driver developers use MACROs to wrap port I/O patterns. EQU constants name hardware register addresses for readability.
Key points
- Directives vs Instructions — Instructions (MOV, ADD, JMP) generate machine code that the CPU executes. Directives (DB, DW, SEGMENT, ORG, EQU, MACRO) are commands to the assembler — they control memory layout, define data, and organize the program. Directives produce no executable code themselves.
- DB, DW, DD — Data Definition — DB (Define Byte) allocates 1-byte values. DW (Define Word) allocates 2-byte values (stored little-endian). DD (Define Doubleword) allocates 4-byte values. These directives can define single values, lists, strings, or repeated patterns.
- EQU — Named Constants — EQU assigns a name to a constant value at assembly time. Unlike DB/DW, no memory is allocated. The assembler substitutes the value wherever the name appears. EQU values cannot be changed once defined.
- ORG — Origin Directive — ORG sets the location counter, telling the assembler where the next instruction or data should be placed in memory. In COM programs, ORG 100h accounts for the 256-byte PSP (Program Segment Prefix) that DOS places before the code.
- SEGMENT / ENDS — SEGMENT and ENDS define logical segments of a program. In the simplified .MODEL/.CODE/.DATA style, these are implicit. In full segment definitions, you explicitly name and configure segments with alignment, combine type, and class.
- ASSUME Directive — ASSUME tells the assembler which segment register corresponds to which segment. This lets the assembler generate correct segment override prefixes when needed. It does NOT actually load the segment registers — you must do that with MOV.
- Labels and Their Types — Labels mark locations in code or data. A code label followed by a colon (loop_start:) marks an instruction address. A data label before DB/DW marks a data address. Labels can be NEAR (same segment offset) or FAR (segment:offset).
- PROC / ENDP — PROC defines a procedure (subroutine) with an optional NEAR or FAR attribute. ENDP marks its end. The assembler uses the attribute to determine whether CALL/RET should be near or far. This is both a directive and an organizational tool.
- MACRO / ENDM — MACRO defines a reusable code template that the assembler expands inline at each call site. Unlike PROC, a macro does not use CALL/RET — the code is copied. Macros can accept parameters and generate different code each time.
- Macro vs Procedure Trade-offs — Macros are faster (no CALL/RET overhead) but increase code size because they are expanded at every use. Procedures save code size but have CALL/RET overhead. Use macros for small, frequently used snippets. Use procedures for larger reusable blocks.
- DUP Operator and Nested DUP — DUP repeats a value a specified number of times within DB, DW, or DD. It can be nested for multi-dimensional initialization. The ? in DUP means uninitialized (assembler reserves space but does not write a value).
Code example
; Program: Demonstrate key directives and macros
; Uses: DB, DW, EQU, MACRO, PROC, labels
; --- Macro Definitions ---
print_str MACRO string_addr
LEA DX, string_addr
MOV AH, 09h
INT 21h
ENDM
newline MACRO
MOV AH, 02h
MOV DL, 0Dh
INT 21h
MOV DL, 0Ah
INT 21h
ENDM
; --- Constants ---
DOS_PRINT EQU 09h
DOS_EXIT EQU 4Ch
MAX_ITEMS EQU 5
.MODEL SMALL
.STACK 100h
.DATA
title_msg DB 'Directive Demo', 0Dh, 0Ah, '$'
items DB MAX_ITEMS DUP(0) ; 5 zero bytes
count DW 0
separator DB '---', 0Dh, 0Ah, '$'
.CODE
MAIN PROC
MOV AX, @DATA
MOV DS, AX
print_str title_msg ; macro expands inline
print_str separator
; Initialize items array
MOV CX, MAX_ITEMS ; EQU constant = 5
LEA SI, items
MOV AL, 10
fill:
MOV [SI], AL
ADD AL, 10
INC SI
LOOP fill
newline ; macro expands inline
MOV AH, DOS_EXIT ; EQU constant
INT 21h
MAIN ENDP
END MAINLine-by-line walkthrough
- 1. print_str MACRO — defines a reusable template that loads a string address and calls DOS print. Each use is expanded to 3 instructions inline
- 2. newline MACRO — prints CR (0Dh) and LF (0Ah) for a new line. Expands to 5 instructions each time used
- 3. DOS_PRINT EQU 09h — creates a named constant. Wherever DOS_PRINT appears, the assembler substitutes 09h. No memory used
- 4. MAX_ITEMS EQU 5 — another constant. Used for both the DUP count and the loop counter, ensuring consistency
- 5. items DB MAX_ITEMS DUP(0) — allocates 5 bytes initialized to zero. DUP tells the assembler to repeat the value
- 6. print_str title_msg — the assembler expands this to: LEA DX, title_msg / MOV AH, 09h / INT 21h
- 7. MOV CX, MAX_ITEMS — EQU substitution: assembles as MOV CX, 5
- 8. The fill loop manually initializes items to [10, 20, 30, 40, 50] by incrementing AL by 10 each iteration
- 9. MOV AH, DOS_EXIT — EQU substitution again: assembles as MOV AH, 4Ch
Spot the bug
print_msg MACRO msg
MOV AH, 09h
LEA DX, msg
INT 21h
ENDM
.DATA
greeting DB 'Hi there', 0Dh, 0Ah, 0
.CODE
print_msg greeting
MOV AH, 4Ch
INT 21hNeed a hint?
Show answer
Explain like I'm 5
Fun fact
Hands-on challenge
More resources
- 8086 Assembler Directives (GeeksforGeeks)
- MASM Directives Reference (Microsoft Docs)
- Assembly Macros and Directives (YouTube)
- MASM Macro Language (Wikibooks)