.relocate

.relocate address

Defines a block of code as relocatable. Whilst the block of code is output at the current address, all labels are calculated with an offset applied, to allow the block of code to be copied elsewhere with the correct label addresses.

Here is a stupid example. We are running on a ROM, but we have some RAM at location $C000. We have a routine that relies on self-modifying code. We need to copy it into RAM, therefore to run it. The routine is between the labels code and code_end.

ram = $C000 ; RAM is at location $C000

.org $0000 ; We're in ROM.

    ; Copy to RAM
    ld hl,code
    ld bc,code-code_end
    ld de,ram
    ldir
    
    ; Run it:
    call ram
    
    ; End the program
    di
    halt

; ---

code
.relocate ram

    ld a,10
    ld (counter+1),a

loop
    call do_something
counter
    ld a,0 ; Self-modifying
    dec a
    ld (counter+1),a
    jp nz,loop
    ret
    
.endrelocate
code_end 

; ---

do_something
    push af
    out ($CC),a
    pop af
    ret

The jump to loop will work fine, as the label is inside the relocated code block. The routine do_something is called using the absolute address, as it is defined outside of the relocated code block.

Bear in mind that the special symbol $ (current instruction pointer) is also translated.