Source Equates and Scoped Replacements - HoraceAndTheSpider/Bloodwych-68k GitHub Wiki
Source equates and scoped replacements
Reverse-engineered source sometimes gives an immediate constant the appearance of an address. This happens when the original instruction contains a long numeric value which coincides with an address in the program. The distinction matters: a pointer identifies where something is stored, whereas a count remains the same number even if the program is moved.
The SPS 439 disassembly provides a confirmed example:
move.l #adrL_0186A0,d1 ;223C000186A0
In this disk-reading routine, $000186A0 is a countdown value used while
waiting for disk DMA completion. It is not a pointer to the data later labelled
adrL_0186A0. The clearer representation is:
DiskReadTimeoutCount: equ $000186A0
move.l #DiskReadTimeoutCount,d1 ;223C000186A0
The opcode remains 223C000186A0, so the correction improves the source
without changing the executable.
Why replacements must be scoped
Many small constants have several unrelated meanings. For example, #$40
might represent character form $40 (Zendik) in a character-selection routine,
but the same literal can be a count, flag, colour or size elsewhere.
A constant must therefore never be replaced globally merely because its value matches. Its meaning comes from the instructions which use it. In the disk example, the value is counted down while waiting; it is not used to read from memory at that address.
The relevant routine labels, complete instruction and encoded bytes provide a way to check each use. The instruction using the named constant should assemble to exactly the same bytes as the original.
Constants and addresses
An EQU can also give a name to a real address within a larger block:
PictureOffsets: equ PictureData+$20
This illustrative alias moves with PictureData. By contrast,
DiskReadTimeoutCount is a fixed count and must not change when source or
data moves. Both are written with EQU, but they express different things.
This is particularly important when a block is represented by INCBIN.
Code may still need to refer to a table inside that block. A base label plus
a named offset keeps that reference meaningful without inserting a label
inside the included file.