File: patching_relocation_at_source.asm

package info (click to toggle)
64tass 1.60.3243-1
  • links: PTS
  • area: main
  • in suites: forky, sid
  • size: 3,432 kB
  • sloc: ansic: 48,995; xml: 647; asm: 333; makefile: 250
file content (85 lines) | stat: -rw-r--r-- 2,810 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85

                *= $1000

; Static relocation is easy, just use .logical/.here and copy the code to the
; already know destination for execution.

                ldx #0
_lp
                lda inram,x
                sta reloc,x
                inx
                cpx #size(reloc)
                bcc _lp

; Patching it at the destination is simple as well. As all labels point to
; destination memory it can be directly overwritten.

                sta reloc.patchme + 1

; But what if the code has to be transmitted in some way to somewhere else for
; execution? Then the only way is to patch it before the transmission in RAM.
; But all the available labels contain the "wrong" addresses for that and can't
; be used as-is.

; Normally one calculates the in memory address by adjusting it with the
; difference:

                sta inram + reloc.patchme - reloc + 1

; When patching many locations it's less error prone to move the calculation to
; a function:

                sta patch(reloc.patchme) + 1
                rts

; Function to calculate in memory address. May be a good idea to put it inside
; the "reloc" scope but that's not done now.

patch           .sfunction _adr, inram + _adr - reloc

; Example relocated routine, compiled here but needs to execute at $2000

inram           .logical $2000
reloc           .block                  ; in separate scope as a reminder
patchme         lda #0                  ; that labels inside are relocated
                inc patchme+1
                .bend
                .here

;-----------------------
; Not recommended at all but if one is careful it's possible to put all
; relocated code into a macro and compile it twice just to get direct labels
; which carry the in memory address:

                sta virt.patchme + 1

; For the virtual double compile hack the code in the macro must be written so
; that it compiles the same way every time!
; And it's really easy to get this wrong. For example when relocating to zero
; page the second in memory address compile might use absolute addressing while
; the first did use zero page for an opcode. These are different size and so
; the second compile will have useless shifted addresses from there on. You
; have been warned.

drvcode         .macro
patchme         lda #0
                inc patchme+1
                .endm

; Actual in memory code relocated to $0300.

inram2          .logical $300
                #drvcode
                .here

; Virtual compile a second time to have the right labels for patching

                .virtual inram2
virt            #drvcode
                .endv

; Sanity check, not perfect but better than nothing. Change the relocation from
; $300 to $30 see it triggered

                .cerror size(virt) != size(reloc), "Different size, how?!"