4.2.2 How a Two-Pass Assembler Works
Assembly source often contains symbolic labels whose final addresses are not known when they first appear. A two-pass assembler solves this by reading the source twice: the first pass establishes where labels are located, and the second pass uses that information to generate machine-code output.
By the end of this section, you should be able to:
- Explain why a two-pass assembler is needed.
- Describe the purpose of a location counter and a symbol table.
- Apply pass one to assign addresses and record labels.
- Explain how forward references are resolved.
- Apply pass two using a symbol table and opcode table.
- Produce illustrative machine-code output for a simple assembly program.
- Recognise errors such as duplicate labels, undefined symbols and invalid mnemonics.
Why Is One Reading Not Always Enough?
Consider this instruction:
STO COUNT
The assembler can recognise STO immediately, but it cannot encode
COUNT until it knows the address associated with that label. If the label is
defined later in the source program, the instruction contains a
forward reference.
Before the Two Main Passes
An assembler may prepare the source before or during its main passes. Exact implementations vary, but a teaching model can include the following actions:
| Source feature | Assembler action | Why it matters |
|---|---|---|
| Comments | Ignore them for machine-code generation. | They are written for human readers. |
| Macros | Replace a macro call with its stored sequence of instructions. | The expanded instructions must be included when addresses are assigned. |
| Directives | Interpret instructions intended for the assembler. | A directive may influence memory allocation or output organisation. |
| Source format | Separate labels, mnemonics, operands and comments. | Each field must be processed correctly. |
Original Example Source Program
The following fictional program starts at address 520. For this learning model, every instruction and data declaration occupies one memory word.
; Count down from 3 to 0
LDM #3
STO COUNT
LOOP: LDD COUNT
SUB #1
STO COUNT
CMP #0
JPN LOOP
END
COUNT: 0
The instruction STO COUNT refers to COUNT before the label is
defined. The jump to LOOP is a backward reference because the label has
already appeared by that point.
Pass One: Assign Addresses
During pass one, the assembler scans the source and advances the location counter. When it reaches a label definition, it records the label and the current address. Machine-code output is not the main purpose of this pass.
| Assigned address | Source line | Pass-one action |
|---|---|---|
| 520 | LDM #3 |
Assign address 520; advance the location counter. |
| 521 | STO COUNT |
Record that COUNT is referenced; its address is not yet known. |
| 522 | LOOP: LDD COUNT |
Add LOOP β 522 to the symbol table. |
| 523 | SUB #1 |
Assign address 523. |
| 524 | STO COUNT |
COUNT remains unresolved at this point. |
| 525 | CMP #0 |
Assign address 525. |
| 526 | JPN LOOP |
LOOP is already known as address 522. |
| 527 | END |
Assign address 527. |
| 528 | COUNT: 0 |
Add COUNT β 528 to the symbol table. |
The Symbol Table
At the end of pass one, the example symbol table contains:
| Symbol | Assigned address | Used by |
|---|---|---|
LOOP |
522 | JPN LOOP |
COUNT |
528 | STO COUNT and LDD COUNT |
Labels do not become text stored inside the final machine instruction. During pass two, symbolic operands are replaced by the appropriate encoded addresses.
COUNT β 528. It does not store the changing runtime value held at address 528.
Resolving Forward References
During pass one, the assembler sees STO COUNT at address 521 before it sees
COUNT: 0 at address 528. It can note the symbol, but it cannot finish encoding
the operand yet.
STO COUNT
COUNT not defined yet
COUNT: 0
Symbol table gains COUNT β 528
STO 528
The symbolic operand can now be encoded
This is the key reason the second pass is useful: by then, the assembler has already scanned the complete source and knows the addresses of valid labels.
Pass Two: Translate the Program
The assembler scans the source again. It uses two main lookup structures:
| Lookup structure | What it provides | Example |
|---|---|---|
| Opcode table | The binary code associated with each mnemonic. | STO β 00111 |
| Symbol table | The address associated with each label. | COUNT β 528 |
Literal values such as #3 are encoded directly. Symbolic operands such as
COUNT and LOOP are replaced using the completed symbol table.
Comments and label definitions do not become processor opcodes.
Complete Worked Assembly
To continue the fictional 16-bit teaching processor introduced in 4.2.1, each instruction uses a 5-bit opcode and an 11-bit operand field. The binary codes below are original teaching values and are not a real processor specification.
| Mnemonic | Illustrative opcode |
|---|---|
LDM | 00101 |
STO | 00111 |
LDD | 00011 |
SUB | 01011 |
CMP | 10010 |
JPN | 10101 |
END | 11111 |
| Address | Assembly source | Operand resolution | Illustrative output |
|---|---|---|---|
| 520 | LDM #3 |
Immediate value 3 | 00101 00000000011 |
| 521 | STO COUNT |
COUNT β 528 | 00111 01000010000 |
| 522 | LOOP: LDD COUNT |
COUNT β 528 | 00011 01000010000 |
| 523 | SUB #1 |
Immediate value 1 | 01011 00000000001 |
| 524 | STO COUNT |
COUNT β 528 | 00111 01000010000 |
| 525 | CMP #0 |
Immediate value 0 | 10010 00000000000 |
| 526 | JPN LOOP |
LOOP β 522 | 10101 01000001010 |
| 527 | END |
No explicit operand | 11111 00000000000 |
| 528 | COUNT: 0 |
Data declaration | 0000000000000000 |
Errors an Assembler May Detect
The exact pass in which an error is reported depends on the assembler design. The important point is that invalid source prevents correct output.
| Error | Example | Why translation fails |
|---|---|---|
| Duplicate label | LOOP: defined twice |
The symbol would have more than one possible address. |
| Undefined symbol | JPN AGAIN when AGAIN is never defined |
No address can be substituted during pass two. |
| Invalid mnemonic | MUL #2 when MUL is not in the instruction set |
No matching opcode exists in the opcode table. |
| Invalid operand form | An address supplied where a register is required | The source does not match the instruction format. |
Interactive: Two-Pass Assembler Simulator
Choose a valid program or an error scenario. Step through source preparation, pass one, symbol-table construction, pass two and output generation.
Common Mistakes and Misconceptions
- Pass one mainly assigns addresses and builds the symbol table; it does not execute the program.
- A forward reference is not automatically an error if the label is defined later.
- The location counter tracks source addresses; it is not the runtime Program Counter.
- The symbol table stores label-to-address mappings, not current values used while the program runs.
- Pass two uses both the opcode table and the completed symbol table.
- A label definition does not become an opcode in the final machine-code program.
- An undefined label remains an error because no address can be substituted.
Exam Tips
Strong description of pass one
State that the assembler scans the source, uses a location counter to assign addresses, and records labels with their addresses in a symbol table.
Strong description of pass two
State that the assembler scans the program again, converts mnemonics using an opcode table, replaces symbolic operands using the symbol table, and produces machine-code or object-code output.
Practice
Core questions
- Explain why a forward reference creates a problem for a one-pass translation.
- State the purpose of the location counter.
- Describe what is stored in a symbol table.
- Describe the main tasks performed during pass one.
- Describe the main tasks performed during pass two.
- Explain how an opcode table differs from a symbol table.
- Explain why an undefined label prevents complete translation.
Apply pass one
Assume the first line is stored at address 700 and every line occupies one word. Assign addresses and build the symbol table.
LDM #2
STO ITEMS
AGAIN: LDD ITEMS
SUB #1
STO ITEMS
JPN AGAIN
END
ITEMS: 0
Spot the source error
Explain the problem and state which table would reveal it:
LDM #5
JPN RETRY
END
Review
| Stage or structure | Essential role |
|---|---|
| Preparation | Handle comments, macros, directives and source fields as required. |
| Location counter | Tracks the address assigned to each instruction or data word. |
| Pass one | Assign addresses and build the symbol table. |
| Symbol table | Maps labels to assigned addresses. |
| Opcode table | Maps mnemonics to binary opcodes. |
| Pass two | Translate mnemonics, resolve operands and produce output. |
| Forward reference | A symbol used before its later definition. |