1. AArch64 Relocation Reference

1.1. Introduction

AArch64 relocation operators such as :abs_g0_nc:, :pg_hi21:, and :lo12: instruct the assembler and linker how to encode symbol references into instruction immediate fields.

1.2. Relocation Conventions

Symbol

Meaning

S

Runtime address of referenced symbol

A

Relocation addend

P

Address of relocation site

X

Relocation result before masking

Page(expr)

expr & ~0xFFF

GOT

Global Offset Table


1.3. Group Relocations

1.3.1. Unsigned Absolute Relocations

Operator

Relocation

Operation

Inst

Bits

Range Check

:abs_g0:

MOVW_UABS_G0

S + A

movz

[15:0]

0 <= X < 2^16

:abs_g0_nc:

MOVW_UABS_G0_NC

S + A

movk

[15:0]

none

:abs_g1:

MOVW_UABS_G1

S + A

movz

[31:16]

0 <= X < 2^32

:abs_g1_nc:

MOVW_UABS_G1_NC

S + A

movk

[31:16]

none

:abs_g2:

MOVW_UABS_G2

S + A

movz

[47:32]

0 <= X < 2^48

:abs_g2_nc:

MOVW_UABS_G2_NC

S + A

movk

[47:32]

none

:abs_g3:

MOVW_UABS_G3

S + A

movz/movk

[63:48]

none

1.3.2. Signed Absolute Relocations

Operator

Relocation

Operation

Inst

Bits

Range Check

:abs_g0_s:

MOVW_SABS_G0

S + A

movz/movn

[15:0]

-2^16 <= X < 2^16

:abs_g1_s:

MOVW_SABS_G1

S + A

movz/movn

[31:16]

-2^32 <= X < 2^32

:abs_g2_s:

MOVW_SABS_G2

S + A

movz/movn

[47:32]

-2^48 <= X < 2^48

1.3.3. Example: Building a 64-bit Constant

movz x1, #:abs_g3:u64
movk x1, #:abs_g2_nc:u64
movk x1, #:abs_g1_nc:u64
movk x1, #:abs_g0_nc:u64

1.4. PC-Relative Address Relocations

Operator

Relocation

Expression

Instruction

Encoded Bits

Range Check

Alignment

implicit

LD_PREL_LO19

S+A-P

literal ldr

[20:2]

-2^20 <= X < 2^20

X must be a multiple of 4

implicit

LD_PREL_LO21

S+A-P

adr

[20:0]

-2^20 <= X < 2^20

none

:pg_hi21:

ADR_PREL_PG_HI21

Page(S+A)-Page(P)

adrp

[31:12]

-2^32 <= X < 2^32

none

:pg_hi21_nc:

ADR_PREL_PG_HI21_NC

Page(S+A)-Page(P)

adrp

[31:12]

none

none

LD_PREL_LO19 alignment: The literal ldr instruction addresses 4-byte-aligned literals; X (S+A-P) must therefore be divisible by 4. The linker encodes X >> 2 into the 19-bit field and emits a warning if X & 3 != 0.

1.4.1. Typical ADRP + ADD Sequence

adrp x0, :pg_hi21:foo
add  x0, x0, #:lo12:foo

1.5. Low 12-bit Relocations

Operator

Relocation

Used By

Immediate Extracted

:lo12:

ADD_ABS_LO12_NC

add

X[11:0]

:lo12:

LDST8_ABS_LO12_NC

byte loads/stores

X[11:0]

:lo12:

LDST16_ABS_LO12_NC

halfword loads/stores

X[11:1]

:lo12:

LDST32_ABS_LO12_NC

word loads/stores

X[11:2]

:lo12:

LDST64_ABS_LO12_NC

doubleword loads/stores

X[11:3]

:lo12:

LDST128_ABS_LO12_NC

128-bit accesses

X[11:4]


1.6. Control Flow Relocations

Relocation

Instruction

Expression

Encoded Bits

Reach

Alignment

Out-of-range

TSTBR14

tbz, tbnz

S+A-P

[15:2]

-2^15 <= X < 2^15

X must be a multiple of 4

error

CONDBR19

b.<cond>

S+A-P

[20:2]

-2^20 <= X < 2^20

X must be a multiple of 4

error

JUMP26

b

S+A-P

[27:2]

-2^27 <= X < 2^27

X must be a multiple of 4

trampoline

CALL26

bl

S+A-P

[27:2]

-2^27 <= X < 2^27

X must be a multiple of 4

trampoline

Alignment: All four control-flow relocations encode X >> 2 into their immediate field, so X (S+A-P) must be divisible by 4. The linker emits an error if X & 3 != 0.

Out-of-range (JUMP26/CALL26): When the branch target is beyond ±128 MB the linker inserts a trampoline stub for range extension rather than reporting an overflow error. TSTBR14 and CONDBR19 have no trampoline support; exceeding their range is a hard error.


1.7. Common Prefix Cheat Sheet

Prefix

Meaning

:abs_g0:

Bits 15:0

:abs_g1:

Bits 31:16

:abs_g2:

Bits 47:32

:abs_g3:

Bits 63:48

_nc

No overflow check

_s

Signed relocation

:pg_hi21:

ADRP page-relative high 21 bits

:lo12:

Low 12 bits


1.8. Large Memory Model Relocations

The small and medium code models typically use ADRP+ADD sequences and are limited by the reach of ADRP. Large memory models use MOVZ/MOVK relocation sequences to construct arbitrary 64-bit addresses.

Relocation

Operator

Instruction

Bits Loaded

Range Check

R_AARCH64_MOVW_UABS_G0

:abs_g0:

movz

[15:0]

0 <= X < 2^16

R_AARCH64_MOVW_UABS_G0_NC

:abs_g0_nc:

movk

[15:0]

none

R_AARCH64_MOVW_UABS_G1

:abs_g1:

movz

[31:16]

0 <= X < 2^32

R_AARCH64_MOVW_UABS_G1_NC

:abs_g1_nc:

movk

[31:16]

none

R_AARCH64_MOVW_UABS_G2

:abs_g2:

movz

[47:32]

0 <= X < 2^48

R_AARCH64_MOVW_UABS_G2_NC

:abs_g2_nc:

movk

[47:32]

none

R_AARCH64_MOVW_UABS_G3

:abs_g3:

movz/movk

[63:48]

none

1.8.1. Example

movz x0, #:abs_g3:foo
movk x0, #:abs_g2_nc:foo
movk x0, #:abs_g1_nc:foo
movk x0, #:abs_g0_nc:foo

Resulting relocation sequence:

R_AARCH64_MOVW_UABS_G3
R_AARCH64_MOVW_UABS_G2_NC
R_AARCH64_MOVW_UABS_G1_NC
R_AARCH64_MOVW_UABS_G0_NC

1.8.2. GOT-Based Large Model Relocations

Relocation

Purpose

R_AARCH64_ADR_GOT_PAGE

Compute GOT page address

R_AARCH64_LD64_GOT_LO12_NC

Load GOT entry offset

R_AARCH64_GLOB_DAT

Dynamic linker fills GOT entry

R_AARCH64_JUMP_SLOT

PLT/GOT function resolution

1.8.3. Reach Comparison

Scheme

Reach

ADR

Approximately ±1 MB

ADRP + ADD

Approximately ±4 GB

MOVZ/MOVK + MOVW_UABS_G*

Full 64-bit address space

GOT-based sequence

Full 64-bit address space


1.9. AArch64 Code Models

1.9.1. Small Code Model

Assumptions:

  • Code and static data are reachable using PC-relative addressing.

  • Symbols are typically accessed using ADRP + ADD or ADRP + LDR/STR.

Common relocations:

Relocation

Purpose

R_AARCH64_ADR_PREL_PG_HI21

ADRP page calculation

R_AARCH64_ADD_ABS_LO12_NC

ADD low 12 bits

R_AARCH64_LDST8_ABS_LO12_NC

8-bit load/store offset

R_AARCH64_LDST16_ABS_LO12_NC

16-bit load/store offset

R_AARCH64_LDST32_ABS_LO12_NC

32-bit load/store offset

R_AARCH64_LDST64_ABS_LO12_NC

64-bit load/store offset

Example:

adrp x0, :pg_hi21:global
add  x0, x0, #:lo12:global

1.9.2. Medium Code Model

Assumptions:

  • Code remains reachable through branch relocations.

  • Data may reside outside the ADRP reach window.

  • Large objects are frequently accessed through the GOT.

Common relocations:

Relocation

Purpose

R_AARCH64_ADR_GOT_PAGE

Compute GOT page

R_AARCH64_LD64_GOT_LO12_NC

Access GOT entry

R_AARCH64_GLOB_DAT

Dynamic linker fills GOT

R_AARCH64_JUMP_SLOT

Function resolution via PLT/GOT

Example:

adrp x0, :got:symbol
ldr  x0, [x0, #:got_lo12:symbol]

1.9.3. Large Code Model

Assumptions:

  • Code and data may be located anywhere in the 64-bit address space.

  • Full-width addresses are materialized using MOVZ/MOVK relocation sequences.

Common relocations:

Relocation

R_AARCH64_MOVW_UABS_G0

R_AARCH64_MOVW_UABS_G0_NC

R_AARCH64_MOVW_UABS_G1

R_AARCH64_MOVW_UABS_G1_NC

R_AARCH64_MOVW_UABS_G2

R_AARCH64_MOVW_UABS_G2_NC

R_AARCH64_MOVW_UABS_G3

Example:

movz x0, #:abs_g3:symbol
movk x0, #:abs_g2_nc:symbol
movk x0, #:abs_g1_nc:symbol
movk x0, #:abs_g0_nc:symbol

1.10. References

1.10.1. Official AArch64 ELF ABI Specification

1.10.1.1. Current Source (GitHub)

  • ELF for the Arm® 64-bit Architecture (AArch64)

    • https://github.com/ARM-software/abi-aa/blob/main/aaelf64/aaelf64.rst

1.10.1.2. AAELF64 Repository Directory

  • https://github.com/ARM-software/abi-aa/tree/main/aaelf64