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:



