assembly - AArch64 relocation prefixes -


i noticed gnu asm relocation syntax arm 64-bit assembly. pieces #:abs_g0_nc: , :pg_hi21:? explained? there pattern them or made on go? can learn more?

introduction

elf64 defines 2 types of relocation entries, called rel , rela:

typedef struct {     elf64_addr r_offset;    /* address of reference */     elf64_xword r_info;     /* symbol index , type of relocation */ } elf64_rel;  typedef struct {     elf64_addr r_offset;    /* address of reference */     elf64_xword r_info;     /* symbol index , type of relocation */     elf64_sxword r_addend;  /* constant part of expression */ } elf64_rela; 

the scope of each relocation entry give loader (static or dynamic) 4 pieces of information:

  • the virtual address or offset of instruction patch.
    given r_offset.

  • the runtime address of symbol accessed.
    given higher part of r_info.

  • a custom value called addend
    value, eventually, operand in expression used calculate value written patch instruction.
    rela entries have value in r_addend, rel entries extract relocation site.

  • the relocation type determines type of expression uses calculate value patch instruction. encoded in lower part of r_info.

relocating

during relocation phase loader goes through relocation entries , write location specified each r_offset, using formula chosen lower part of r_info compute value stored addend (r_addend rela) , symbol address (obtainable upper part of r_info).

actually write part has been simplified, contrary other architecture immediate field of instruction occupy entirely separate byes ones used encode operation, in arm, immediate value mixed other encoding information.
loader should know kind of instruction trying relocate, if instruction @ all1, instead of letting disassemble site of relocation, assembler set relocation type according instruction.

each relocation symbol can relocate 1 or two, encoding-equivalent, instructions.
in specific case relocation change type of instruction.

the value compute computed during relocation implicitly extended 64 bits, signed or unsigned based on relocation type chosen.

aarch64 relocation

being arm risc architecture fixed instruction size, loading full width, i.e. 64 bits, immediate register non trivial no instruction can have full width immediate field.

relocation in aarch64 has address issue too, 2 fold problem: first, find real value programmer intended use (this pure relocation part of problem); second, find way put register, since no instruction has 64 bits immediate field.

the second issue addressed using group relocation, each relocation type in group used compute 16 bits part of 64 bits value, therefore there can 4 relocation type in group (ranging g0 g3).

this slicing 16 bits comes fit movk (move keeping), movz (move zeroing) , movn (move negating logically).
other instructions, b, bl, adrp, adr , on, have relocation type specially suited them.

whenever there one, unambiguous, possible relocation type given instruction reference symbol, assembler can generate corresponding entry without need, programmer, specify explicitly.

group relocation doesn't fit category, exist allow programmer flexibility, explicitly stated. in group, relocation type can specify if assembler must perform overflow check or not.
g0 relocation, used load lower 16 bits of value, unless explicitly suppressed, check value can fit 16 bits (signed or unsigned, depending on specific type used). same true g1, loading bits 31-16 check values can fits 32 bits.
consequence g3 non checking every value fits 64 bits.

finally, relocation can used load integer values register. in fact, address of symbol nothing more arbitrary integer constant.
note r_addend 64 bits wide.


1 if r_offset points site in data section computed value written 64 bits word @ location indicated.

relocation operators

first of all, references:

  • the arm document describes relocation types elf64 format here, section 4.6

  • a test aarch64 assembly file that, presumably, contains relocation operators available gas here

conventions

following arm document convention have:

s runtime address of symbol being relocated.
a addend relocation.
p address of relocation site (derived r_offset).
x result of relocation operation, before masking or bit-selection operation applied.
page(expr) page address of expression expr, defined expr & ~0xfff, i.e. expr lower 12 bits cleared. got address of global offset table.
gdat(s+a) represents 64-bit entry in got address s+a. entry relocated @ run time relocation r_aarch64_glob_dat(s+a).
g(expr) address of got entry expression expr.
delta(s) resolves difference between static link address of s , execution address of s. if s null symbol (elf symbol index 0), resolves difference between static link address of p , execution address of p.
indirect(expr) represents result of calling expr function.
[msb:lsb] bit-mask operation representing selection of bits in value, bounds inclusive.

operators

the relocation name missing prefix r_aarch64_ sake of compactness.

expressions of kind |x|≤2^16 intended -2^16 ≤ x < 2^16, note strict inequality on right.
abuse of notation, called constrains of formatting table.

group relocations

operator    | relocation name | operation | inst | immediate | check ------------+-----------------+-----------+------+-----------+---------- :abs_g0:    | movw_uabs_g0    | s +     | movz | x[15:0]   | 0≤x≤2^16 ------------+-----------------+-----------+------+-----------+---------- :abs_g0_nc: | movw_uabs_g0_nc | s +     | movk | x[15:0]   |  ------------+-----------------+-----------+------+-----------+---------- :abs_g1:    | movw_uabs_g1    | s +     | movz | x[31:16]  | 0≤x≤2^32 ------------+-----------------+-----------+------+-----------+---------- :abs_g1_nc: | movw_uabs_g1_nc | s +     | movk | x[31:16]  |  ------------+-----------------+-----------+------+-----------+---------- :abs_g2:    | movw_uabs_g2    | s +     | movz | x[47:32]  | 0≤x≤2^48 ------------+-----------------+-----------+------+-----------+---------- :abs_g2_nc: | movw_uabs_g2_nc | s +     | movk | x[47:32]  |  ------------+-----------------+-----------+------+-----------+---------- :abs_g3:    | movw_uabs_g3    | s +     | movk | x[64:48]  |              |                 |           | movz |           | ------------+-----------------+-----------+------+-----------+---------- :abs_g0_s:  | movw_sabs_g0    | s +     | movz | x[15:0]   | |x|≤2^16             |                 |           | movn |           | ------------+-----------------+-----------+------+-----------+---------- :abs_g1_s:  | movw_sabs_g1    | s +     | movz | x[31:16]  | |x|≤2^32             |                 |           | movn |           | ------------+-----------------+-----------+------+-----------+---------- :abs_g2_s:  | movw_sabs_g2    | s +     | movz | x[47:32]  | |x|≤2^48             |                 |           | movn |           | ------------+-----------------+-----------+------+-----------+---------- 

in table abs version showed, assembler can pickup prel (pc relative) or gotoff (got relative) version depending on symbol referenced , type of output format.

a typical use of relocation operators is

unsigned 64 bits                      signed 64 bits    movz    x1,#:abs_g3:u64               movz  x1,#:abs_g3_s:u64 movk    x1,#:abs_g2_nc:u64            movk  x1,#:abs_g2_nc:u64 movk    x1,#:abs_g1_nc:u64            movk  x1,#:abs_g1_nc:u64 movk    x1,#:abs_g0_nc:u64            movk  x1,#:abs_g0_nc:u64 

usually 1 one checking operator used, 1 set highest part.
that's why checking version relocates movz only, while non checking version relocates movk (which partially set register).
g3 relocated both because intrinsically non checking no value can exceed 64 bits.

the signed versions ends _s , checking.
there no g3 version because if 64 bits value used sign if sully specified in value itself.
used set highest part, sign relevant there.
checking overflow in signed value make value meaning less.
these relocations change type of instruction movn or movz based on sign of value, sign extend value.

group relocations, available

pc-relative, 19, 21, 33 bits addresses

operator    | relocation name | operation | inst | immediate | check ------------+-----------------+-----------+------+-----------+---------- [implicit]  | ld_prel_lo19    | s + - p | ldr  | x[20:2]   | |x|≤2^20 ------------+-----------------+-----------+------+-----------+---------- [implicit]  | ld_prel_lo21    | s + - p | adr  | x[20:0]   | |x|≤2^20 ------------+-----------------+-----------+------+-----------+---------- [implicit]  | ld_prel_lo21    | s + - p | adr  | x[20:0]   | |x|≤2^20 ------------+-----------------+-----------+------+-----------+---------- :pg_hi21:   | adr_prel_pg     | page(s+a) | adrp | x[31:12]  | |x|≤2^32             | _hi21           | - page(p) |      |           | ------------+-----------------+-----------+------+-----------+---------- :pg_hi21_nc:| adr_prel_pg     | page(s+a) | adrp | x[31:12]  |              | _hi21_nc        | - page(p) |      |           | ------------+-----------------+-----------+------+-----------+---------- :lo12:      | add_abs_lo12_nc | s +     | add  | x[11:0]   |  ------------+-----------------+-----------+------+-----------+---------- :lo12:      | ldst8_abs_lo12  | s +     | ld   | x[11:0]   |              | _nc             |           | st   |           | ------------+-----------------+-----------+------+-----------+---------- :lo12:      | ldst16_abs_lo12 | s +     | ld   | x[11:1]   |              | _nc             |           | st   |           | ------------+-----------------+-----------+------+-----------+---------- :lo12:      | ldst32_abs_lo12 | s +     | ld   | x[11:2]   |              | _nc             |           | st   |           | ------------+-----------------+-----------+------+-----------+---------- :lo12:      | ldst64_abs_lo12 | s +     | prfm | x[11:3]   |              | _nc             |           |      |           | ------------+-----------------+-----------+------+-----------+---------- :lo12:      | ldst128_abs     | s +     | ?    | x[11:4]   |              | _lo12_nc        |           |      |           | 

the :lo12: change meaning depending on size of data instruction handling (e.g. ldrb uses ldst8_abs_lo12_nc, ldrh uses ldst16_abs_lo12_nc).

a got relative version of these relocations exists, assembler pickup right one.

control flow relocations

operator    | relocation name | operation | inst | immediate | check ------------+-----------------+-----------+------+-----------+---------- [implicit]  | tstbr14         | s + - p | tbz  | x[15:2]   | |x|≤2^15             |                 |           | tbnz |           |   ------------+-----------------+-----------+------+-----------+---------- [implicit]  | condbr19        | s + - p | b.*  | x[20:2]   | |x|≤2^20 ------------+-----------------+-----------+------+-----------+---------- [implicit]  | jump26          | s + - p | b    | x[27:2]   | |x|≤2^27 ------------+-----------------+-----------+------+-----------+---------- [implicit]  | call26          | s + - p | bl   | x[27:2]   | |x|≤2^27 ------------+-----------------+-----------+------+-----------+---------- 

epilogue

i couldn't find official documentation.
tables above have been reconstructed gas test case , arm document explaining type of relocations available aarch64 compliant elfs.

the tables doesn't show relocations present in arm document, of them complementary versions, picked assembler automatically.

a section examples great, don't have arm gas.
in future may extend answer include examples of assembly listings , relocations dumps.


Comments

Popular posts from this blog

jOOQ update returning clause with Oracle -

java - Warning equals/hashCode on @Data annotation lombok with inheritance -

java - BasicPathUsageException: Cannot join to attribute of basic type -