# Labels and data

*Naming addresses so you don't count bytes*

A label is a name for a memory address in assembly language; the assembler builds a symbol table mapping each label to the address its line lands at, so you can write LOAD x instead of a hardcoded number and reserve data bytes with a directive like x: .byte 5.

Group: Processor
URL: https://digiwleea.wleeaf.dev/learn/assembly-labels/

Writing `LOAD 14` works, but it is brittle. If you add one instruction near the top, every later address shifts by one and every hardcoded number is now wrong. Real assembly avoids this with **labels**: you name a location once, and the **assembler** works out the actual address for you. You stop counting bytes.

## A label names a location

A **label** is a name written before an instruction or a piece of data, like `x:`. It marks *this address* with a name. Elsewhere you use the name as an operand, `LOAD x`, and the assembler substitutes the real address. To set aside a byte of data, a **directive** like `.byte` reserves memory with an initial value: `x: .byte 5` means "a byte named `x`, starting at 5." Directives are instructions to the assembler, not the CPU; they shape memory rather than becoming opcodes.

```asm
      LOAD  x       ; ACC = x
      ADD   y       ; ACC = x + y
      STORE z       ; z = ACC
      HALT
x:    .byte 6       ; a named data byte
y:    .byte 9
z:    .byte 0       ; the result lands here
```

_A program with labels. It loads x, adds y, and stores the result in z. Nowhere is a raw address written; the names x, y, z stand in for wherever the assembler places them._

## How the assembler resolves labels

The assembler makes **two passes**. On the first pass it walks the program assigning each line an address in order (the four instructions take addresses 0 to 3, then the data bytes take 4, 5, 6), and it records every label in a **symbol table**: `x = 4`, `y = 5`, `z = 6`. On the second pass it emits the bytes, replacing each label operand with its address from the table. `LOAD x` becomes `LOAD 4`, byte `0x14`; `ADD y` becomes `ADD 5`, byte `0x25`.

```asm
symbol table       addr  byte   source
  x = 4             0    0x14   LOAD x    (LOAD 4)
  y = 5             1    0x25   ADD y     (ADD 5)
  z = 6             2    0x36   STORE z   (STORE 6)
                    3    0xF0   HALT
                    4    0x06   x: .byte 6
                    5    0x09   y: .byte 9
                    6    0x00   z: .byte 0
```

_The symbol table (left) and the assembled program (right). The assembler placed code at addresses 0-3 and data at 4-6, filled the symbol table, then substituted each label with its address to produce the bytes._

> **KEY:** This is a real, if tiny, program layout: **code first, then data**, both in the same [memory](https://digiwleea.wleeaf.dev/learn/ram/). That single shared memory for instructions and data is the *von Neumann* idea, the same bytes are code when the [program counter](https://digiwleea.wleeaf.dev/learn/counter/) fetches them and data when a `LOAD` reads them. The assembler's job is just to lay everything out and turn names into addresses.

> **WARN:** The operand is only **4 bits**, so every label must resolve to an address in `0` to `15`, and the whole program (code plus data) has to fit in the machine's 16 bytes. Labels make addresses readable, but they cannot create memory that is not there. A bigger program needs a CPU with a wider address, exactly the pressure that grows real instruction sets.

**Q (Try it):** In the assembled program above, why is the byte for `LOAD x` equal to `0x14` and not, say, `0x1x`? What did the assembler have to know first?

**A:** The assembler first had to place `x` in memory and record its address in the symbol table: `x` landed at address `4`. Only then could it resolve `LOAD x` to `LOAD 4` and pack opcode `0x1` (LOAD) with operand `0x4` into the byte `0x14`. The label is a name; the byte needs the actual address, which is why the assembler does a placing pass before it emits any bytes.

### FAQ

**Q:** What is a label in assembly language?

**A:** A label is a name for a memory address, written before an instruction or data (like x:). You then use the name as an operand (LOAD x) and the assembler substitutes the real address. Labels let you avoid hardcoding numbers that break whenever the program's layout shifts.

**Q:** What is a symbol table in an assembler?

**A:** A symbol table is the map from each label to the address it lands at, built by the assembler as it walks the program. On a first pass it assigns addresses and fills the table (x=4, y=5, z=6); on a second pass it emits bytes, replacing each label with its address.

**Q:** Why does an assembler make two passes?

**A:** A label can be used before it is defined, so the assembler cannot know an operand's address on the first read. Pass one assigns every line an address and records all labels; pass two emits the bytes with each label resolved to its now-known address.

**Q:** How do you reserve data in assembly?

**A:** With a directive such as .byte: writing x: .byte 5 tells the assembler to set aside one byte named x with the initial value 5. Directives shape memory for the assembler rather than becoming CPU opcodes, unlike LOAD or ADD which do.
