The Problem with Absolute Addressing

Normally, Z80 instructions like JP 8000H or LD HL, DATA_ADDR use absolute addressing. If you compile a program to run at address 8000H but later load it at 9000H, every one of those absolute addresses will be wrong, and the program will crash.

Relocatable Code and Position-Independent Code (PIC) solve this problem.

Relocatable Code (The Assembler’s Job)

Relocatable code is written with absolute addresses, but the assembler generates a file that includes a relocation table.

The Process:

  1. Assembly: The assembler marks every instruction that uses a fixed address (JP, CALL, LD HL, address) in the relocation table.
  2. Loader: When the operating system (or a custom loader) loads the code, it reads the relocation table.
  3. Fixup: The loader calculates the difference between the intended address (e.g., 8000H) and the actual loaded address (e.g., 9000H), and then adds that offset to every address marked in the relocation table.

Advantage: Allows the use of standard, simple instructions. Requires OS support to load the code.

Position-Independent Code (The Programmer’s Job)

Position-Independent Code (PIC) is assembly code written so that it uses no absolute addresses for jumps or data access. It runs correctly no matter where it is loaded, with no ‘fixup’ required.

Technique 1: Relative Jumps Always prefer JR (Jump Relative) over JP (Jump Absolute) for local jumps. JR jumps a short distance forward or backward from the current instruction, which is always correct.

    ; JR is PIC, JP is NOT PIC
    JR   NZ, SKIP_BYTE   ; Jumps relative to the current PC value.

Technique 2: Calculating Data Address (PIC Data) To get the absolute address of local data (e.g., the address of MY_DATA), a PIC routine calculates it at runtime by leveraging the Stack or the Program Counter (PC).

  1. Push the current PC onto the stack with CALL $ + 3 (a common trick).
  2. The address of the following instruction is now on the stack.
  3. Pop this address into HL and use it as a reference point to find MY_DATA via relative offsets.

Advantage: Can be loaded and run instantly without any OS loader.