Search code examples
assemblyarm64

ARM64: LDRB fills (zeroes) the whole 64-bit register?


I'm new to ARM64 assembly (coming from x86 world). Suppose the following instructions:

adr     x1,_data
ldrb    w0, [x1]

I was expecting that the register "w0" (32-bit wide) is filled with zero and just the lowest byte is filled with the byte read from memory. I can see that the high 32-bit from X0 is also filled with ZERO! I was not expecting that! :)

So, what's the point of ldrb w0, [x1]? Isn't the same as ldrb x0, [x1]?

Thanks!


Solution

  • In general, every ARM64 instruction that writes to a 32-bit register wN also zeros the high half of the corresponding 64-bit register xN. This avoids having input dependencies on the destination register, or needing to do partial register renaming.

    In the case of ldrb w0, [x1] this means you get zero extension into x0 for free. If the byte loaded from memory was to be treated as an unsigned 8-bit integer, then the relevant pieces of x0 automatically contain the correct values to treat it as an unsigned 16, 32 or 64 bit integer. As such, there is no need for a separate ldrb x0, [x1] mnemonic, and in fact the assembler will reject it.

    If you want sign extension instead, then there is a difference. If the byte in memory is 0xa5, then ldrsb w0, [x1] will populate w0 with 0xffffffa5 and zero the high half, so that x0 contains 0x00000000ffffffa5. On the other hand, ldrsb x0, [x1] would extend into the entire 64-bit register, leaving x0 containing 0xffffffffffffffa5.