Every way to get a constant into a register
A small immediate, a zeroing idiom, movabs or movz/movk or lui/addi for a big number, a PC-relative address, a GOT load, or a load from read-only data. The size of the value and what it is decide.
Ask what the constant is and how big it is.
- Zero → the zeroing idiom:
xor eax, eaxon x86-64 (it changes the flags, so do it before acmp, never between acmpand its branch),mov x0, xzr/mov w0, #0on ARM64,li a0, 0on RISC-V. - A number that fits the instruction's immediate field (x86-64: 32
bits, sign-extended; ARM64
mov: one 16-bit slot; RISC-Vaddi: −2048 to 2047) → onemov/li. - A wider integer → x86-64
movabs(one 10-byte instruction); ARM64 onemovzplus up to threemovk; RISC-Vlui+addi(and more for 64 bits). Let the assembler'sli/movpick when you can. - The address of a global or a string → never a fixed number:
PC-relative,
lea rax, [rip + x],adrp+add :lo12:, orauipc+addi. - The address of something in another shared library → load it from the global offset table (GOT).
- A floating-point constant → there is no FP immediate worth relying on: the compiler puts it in read-only data and loads it PC-relative.
Small numbers, in the instruction itself
mov eax, 42, mov w0, #42, li a0, 42: where the number sits inside the instruction, and how big it may be.
Example
mov eax, 1000 the 1000 is stored in the instruction's own bytes; no memory is read.Why a 4-byte instruction can only spare 12 or 16 bits for a constant.
Zero, the special case
Example
xor eax, eax is 2 bytes against mov eax, 0's 5, because mov carries a 4-byte immediate.Section
Compiler arithmetic idioms
Why compilers zero with xor, and when they can't (between a compare and its branch).
Example
mov x0, xzr and RISC-V mv a0, zero copy a register that always reads 0.Big numbers, built in pieces
Section
Large constants and addresses
movabs on x86-64, movz then movk on ARM64, lui then addi on RISC-V.
Term
movabs
Term
movk
Example
movz x0, #0x7788 then movk x0, #0x5566, lsl #16 builds 0x55667788 in two instructions.Term
lui
Example
lui a0, 244 then addi a0, a0, 576 builds 0xF4240 = 1,000,000.li and ARM64's mov with a big number are written as one line and expanded by the assembler.
Addresses, relative to the code
Example
lea rax, [rip + msg] stores the distance from the next instruction to msg, so the code works wherever it is loaded.Term
adrp
Example
adrp x0, msg finds the 4 KiB block holding msg; add x0, x0, :lo12:msg adds the low 12 bits.Section
Position-independent code
Why addresses are PC-relative everywhere today, and the GOT load for a symbol that lives in another module.
Constants that live in memory
A double constant such as 2.5 is stored in read-only data and loaded PC-relative.