Search code examples
assemblyarmarm64

Why is the following 48bit ADDR loaded with with movk?


I am seeing this online and have seen the following in 64-bit code.

movz x0, #:abs_g2:foo         
movk x0, #:abs_g1_nc:foo        
movk x0, #:abs_g0_nc:foo

why not just do a

mov x0, foo

Is this for 32-bit machines and the reason why I see it in 64-bit code is for backwards compatibility?


Solution

  • Each AArch64 instruction is 32 bit in length. Hence, there is insufficient space to fit a 64 bit address into one. An instruction like mov x0, foo is only possible if foo is a 16 bit number (optionally left shifted by 16, 32, or 48 bit) or one of various other possible immediates.

    To load a 48 bit address, the address either has to be loaded from a literal pool (incurring extra latency from the load) or assembled into memory in three separate loads.

    If the address to be loaded is to be relocated with the binary, instead the ADRP instruction can used to load a 4 kB aligned address in a range of ±4 GB from the current location to which a 12 bit immediate can be added (forming an arbitrary address within 4 GB of the current location) either with a separate ADD instruction or in many cases with a displacement during the load or store.