Hi, Andy:
Assuming you are using assembler, then it is not that hard. The main thing to keep in mind is that only the branch instructions are relative, all other instructions are not. So the following rules apply:
The addresses of your data will not relocate. The data that your routine accesses will access at the addresses defined when you compile. (More on this later).
JMP instructions use absolute addressing, so they cannot occur in a relocatable routine. Use BRA instead.
The call to the routine has to use a re-mapped address. You can re-map it using an EQU directive. To allow the routine "Groan", somewhere in the 0xF400 block of flash to be executed at the address "moved_Groan" in the 0x500 block of ram, you can define it this way:
moved_Groan: equ Groan-$F400+$500
You would then call the subroutine by using the new address:
jsr moved_Groan
I personally would use equates instead of hard-coded addresses:
RamBase: equ $500
FlashBase: equ $F400
moved_Groan: equ Groan-FlashBase+RamBase
Likewise, you can use that approach if you need to access data that has also been relocated. Simply use the offsets to calculate the real address of the moved data.
Another way to make the data relocatable would be to access it through the index register, H:X.
If you are trying to do this in C, . . . never mind.