A-Level Computer Science / Unit 4: CPU Operation and Low-Level Processing

4.2.2 How a Two-Pass Assembler Works

πŸ”’ Lesson slides are available to signed-in users. Sign in

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.

Forward reference: a use of a label before the line that defines the label has been reached.
Pass one Assign addresses and build the symbol table.
Pass two Translate mnemonics and replace symbols with addresses.
Output Produce machine code or object code when no blocking error remains.
Common misconception: β€œTwo-pass” does not mean that each instruction is executed twice. The assembler reads and translates source code; the processor executes the resulting machine code later.

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.
Exam tip: The central two-pass idea is still: build the symbol table first, then translate using it. Do not let optional preparation details hide that sequence.

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.

Location counter: a value maintained by the assembler to represent the address being assigned to the current source line.

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

Symbol table: a data structure that links each label or symbol to the address assigned to it.

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.

Common mistake: The symbol table stores a relationship such as 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.

Address 521 STO COUNT COUNT not defined yet
Address 528 COUNT: 0 Symbol table gains COUNT β†’ 528
Pass two 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.

Opcode table: a lookup table associating assembly mnemonics with their machine-code opcode patterns.

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
LDM00101
STO00111
LDD00011
SUB01011
CMP10010
JPN10101
END11111
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
Important: The syllabus assesses the process, not memorisation of these invented binary opcodes.

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.

Current source line LDM #3 Assembly source
Assembler action Prepare the source Current pass or check
Output state No machine code yet Output or diagnostic
Location counter Starts at 520.
Symbol table Empty before pass one.
Assembler status Source loaded and ready.

Source program

LDM #3
STO COUNT
LOOP: LDD COUNT
SUB #1
STO COUNT
CMP #0
JPN LOOP
END
COUNT: 0

Machine-code output

Output will be generated during pass two.

Symbol table

Symbol Address
No symbols recorded yet.

Step 1 of 7

Load and prepare the source

The assembler reads the source, ignores comments and identifies labels, mnemonics and operands.

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.

For application questions: Write the address beside every source line before creating the symbol table. This reduces mistakes when labels and data declarations are mixed.

Practice

Core questions

  1. Explain why a forward reference creates a problem for a one-pass translation.
  2. State the purpose of the location counter.
  3. Describe what is stored in a symbol table.
  4. Describe the main tasks performed during pass one.
  5. Describe the main tasks performed during pass two.
  6. Explain how an opcode table differs from a symbol table.
  7. 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.
Final check: Can you apply this complete sequence: prepare β†’ assign addresses β†’ build symbol table β†’ rescan β†’ look up opcodes β†’ replace symbols β†’ generate output?