Search code examples
linkerarmarm64bare-metal

What is the purpose of ADR instructions in ARM?


I know that both adr and ldr pseudo instructions loads addr of a label. The difference between them is that ldr is absolute but adr is PC-relative.

But when should I use which?

I always use ldr to get the address when writing a bare-metal assembly progress. Can you give an explanation and example of using the adr instruction? Is it related to PIC(Position-Independent-Code)?


Solution

  • adr generates a PC-relative address. It takes the address of the instruction itself and adds a signed offset that is encoded in the instruction to it.

    The ldr pseudo-instruction (that is, ldr x0, =label) loads a pre-generated absolute address from a PC-relative position. At compile time, the absolute address of label is generated and embedded somewhere in the binary, and the (actual PC-relative) ldr instruction then loads that value from that place.

    If we take a sample program (_main because I'm on macOS):

    .globl _main
    .p2align 2
    _main:
        adr x1, label
        ldr x2, =label
        mov w0, 0
        ret
    
    label:
        mov w0, 0x1234
        ret
    

    Compiling this and looking at it in a disassembler yields:

    ;-- _main:
    0x100003f98      81000010       adr x1, sym.func.100003fa8
    0x100003f9c      a2000058       ldr x2, 0x100003fb0
    0x100003fa0      00008052       mov w0, 0
    0x100003fa4      c0035fd6       ret
    ;-- func.100003fa8:
    0x100003fa8      80468252       mov w0, 0x1234
    0x100003fac      c0035fd6       ret
    0x100003fb0      a83f0000       invalid
    0x100003fb4      01000000       invalid
    

    Thus, the above program is equivalent to:

    .globl _main
    .p2align 2
    _main:
        adr x1, label
        ldr x2, addressof_label
        mov w0, 0
        ret
    
    label:
        mov w0, 0x1234
        ret
    
    .p2align 3
    addressof_label:
        .8byte label
    

    This adds one level of indirection, and means that in an environment with ASLR, the dynamic linker must add the ASLR slide to addressof_label.