assemblyarmprogram-counterrelative-addressing

Understanding the ADR instruction in ARM, and adding an offset to that


I was looking at the assembler output of my code and need help with below instructions.

    0x00000fe8:    e28fc000    ....    ADR      r12,{pc}+8 ; 0xff0

    0x00000fec:    e28cca08    ....    ADD      r12,r12,#8, 20 ; #0x8000

From my understanding the 1st instruction causes r12 to be loaded with {pc value} + 8 that is
"{Address of current instruction in execution (0xfe8) plus 2 instructions ahead (8)} + 8"

so is r12 after 1st instruction execution loaded with 0xff8 (0xfe8+8+8)

Also regarding the 2nd instruction -
How to calculate the value being added and stored to r12? (the comment says its 0x8000, though i am not able to understand how it got this)


Solution

  • The first instruction (really a pseudo-instruction) loads a PC-relative address into R12. Since the instruction is at address 0xFE8, the expression {pc}+8 evaluates to 0xFF0. So the result of the first instruction is to load the value 0xFF0 into R12. The comment actually indicates this.

    (Note that ADR isn't a real ARM instruction, the assembler replaces it with an instruction such as ADD. Also note that this expression's value is calculated at assembly time. During program execution, the PC points ahead of the current instruction, due to the processor's pipeline. How much ahead depends on the architecture (e.g. ARM7, etc.) and the operating mode (Thumb/ARM). ) I'm risking giving "too much information" here about ADR & PC-relative expressions/addressing, but it's easy to get bitten if you don't understand what's going on behind the scenes.)

    The second instruction (actually reading from right to left) effectively says "take the constant 0x8, rotate it right by 20 bits (which is the same as a left shift by 12 bits, 32-20 = 12), ADD it to R12 (which currently holds 0xFF0), and store it in R12." 0x8 << 12 = 0x8000, so the 2nd instruction results in R12 holding 0x8000 + 0xFF0 = 0x8FF0.

    Note: In your explanation, when you said "2 instructions ahead", don't fall into that habit, think of it as 8 bytes, not 2 instructions. The instruction says add 8 bytes, it doesn't say anything about instructions. Instructions aren't necessarily 4 bytes long (for example, in Thumb, they are 2 bytes; in Thumb2, they are 2 bytes or 4 bytes, depending on the instruction).