Every now and then you end up to situation where you need to make relocatable code. Normally the best thing to do is to generate relocate tables and apply them on top of code. This is the method that is used for example in SymbOS. Unfortunately assemblers very rarely support making these relocate tables. Here is anyway one example how to make them your self:
http://www.msx.fi/nyyrikki/files/freepos.lzh
Sometimes it would be anyway nice to have some small code that you can for example drop from memorymapper to any RAM area and call immediately. Here is example of one way, how you can do that. Bad thing in this method is that it slows down the execution and therefore it should be used only in cases when code is not speed critical. On the good side is that you can skip the time taking task messing up with tables.
Macro implementations may differ a bit from assembler to another, but this example has been tested with sjasm v0.42b8
If you place the "R" (relative) in front of wrong command, the program will still work, but it will cause more useless delay. (In sjasm v0.42b8 you can detect this kind of failure from weird note in output: "from macro R line xx")
I hope this example helps some of you...
ORG #100 ; You can use any address here LD DE,#C000 ; Move code to DE and start it. PUSH DE LD HL,Relative_code_start LD BC,Relative_code_end - Relative_code_start LDIR RET ;------------------------------------------------------------ ; Macro to keep readibility in rest of the source MACRO R CMD+ CALL Next_is_relative3 - ((.end-.beg)>3)*(Next_is_relative4-Next_is_relative3)+((.end-.beg)<3 or (.end-.beg)>4) .beg: CMD -$-2 .end: ENDMACRO ; Macro support routines (must be in fixed address) RET ; This is here in case you put 'R' in front of wrong command. Next_is_relative3: EX (SP),HL PUSH DE PUSH AF INC HL LD E,(HL) INC HL LD D,(HL) EX DE,HL ADD HL,DE EX DE,HL LD (HL),D DEC HL LD (HL),E DEC HL POP AF POP DE EX (SP),HL RET Next_is_relative4: EX (SP),HL PUSH DE PUSH AF INC HL INC HL LD E,(HL) INC HL LD D,(HL) EX DE,HL ADD HL,DE EX DE,HL LD (HL),D DEC HL LD (HL),E DEC HL DEC HL POP AF POP DE EX (SP),HL RET ;--------------------------------------------------------------------------- ; Put your code here and add 'R' in front of commands with absolute pointers Relative_code_start: R LD DE,TXT1 R CALL PRINT LD A,(#82) CP #60 JR C,.SKIP SUB #20 .SKIP: CP "@" R LD DE,TXT2 R CALL Z,PRINT R LD DE,TXT3 R JP C,PRINT CP "H"+1 R JP NC,PRINT R LD DE,TXT4 R JP PRINT TXT1: DB "This is stupid example program:",10,13,0 TXT2: DB "This is used in email addresses, it is not ",0 TXT3: DB "unknown...",0 TXT4: DB "drive letter",0 PRINT: PUSH AF .LOOP: LD A,(DE) INC DE AND A JR Z,.EXIT RST #30 DB #80 DW #A2 JR .LOOP .EXIT: POP AF RET Relative_code_end: