This is a problem typical to RISC processors. The entire design is based on a word size, which is also the instruction size and register size. Additionally, ALL instructions are that word size, and there is no instructions that (directly) uses multiple words. As such, it is impossible to have a "load immediate into register" instruction, because this immediate already takes the whole word (in this case, 32-bit).
The only solution is to have a two-word instruction, but this is also impossible because RISC philosophy says all instructions should be 1 word long, supporting variable length instruction would make it much harder to pipeline the processor.
The solution used by ARM is to have the "second word of the instructions" (in this case, your pointer) stored not in the code, but right after the code. (this was an arbitrary decision, it could go before and work just as well). This turned out to be very practical for romhacking, as there is a pool of parameters used in a function right to eachother, which often makes you able to change things without even disassemble the routine
Note that RISC was never made to save memory (on the other hand, it wastes a lot of ROM as programs are stored very inefficiently - except for THUMB mode in ARM where it gets decent). It was made to simplify instruction decoding within the processor in order to get them to run faster.
Also note that there is NO pointer to your pointer. It is just an instruction relative to the program counter (r15). ARM assembly uses many pseudom-instructions, which acually are compiled to different instructions. Google "arm pseudo instruction" to get more details.
In this case
is probably equivalent to something like
Code: Select all
here:
lda r0, [r15], #something-here-8
The PC is always 2 words (8 bytes) ahead because of the pipeline.