.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.