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?
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.