In NASM (2.14.02), the instruction add rbx, 0xffffffff
leads to
warning: signed dword value exceeds bounds [-w+number-overflow]
I'm aware that arithmetic-logic operations in 64-bit mode only accept constants with 32 bits, but 0xffffffff is still 32 bits wide.
Why does NASM emit a warning, and why does it assume a signed constant? Does it sign-extend the 32-bit -1
to 64-bit -1
(0xffffffffffffffff) and therefore see an overflow? 0x7fffffff works without a warning.
Can I somehow convince NASM that this is not a signed constant, but an unsigned one?
0x00000000FFFFFFFF can't be encoded as a 32-bit sign-extended immediate, and x86 immediates are always sign-extended when they're narrower than the operand-size.
Your theory is somewhat correct, the instruction adds the value specified to the register. There is no way to encode an instruction that adds 0xffffffff to the register, because the only available encodings for add
ing an immediate to a 64-bit register are add r/m64, sign_extended_imm32
or add r/m64, sign_extended_imm8
. Only one special encoding of mov
(with a register destination) can use a 64-bit immediate.
The obvious encoding (stuffing 0xffffffff
into an imm32
) would in fact add 0xffffffffffffffff to rbx which is not what you requested and would be the same as add rbx, -1
There is no way to encode a value into the 32 bit field that results in 0x00000000ffffffff being added to rbx. Asm source uses values, not bit-patterns for immediates.
You need to do something like this :-
mov rcx, 0xffffffff ; RCX = 0xFFFFFFFF = 0x00000000FFFFFFFF
add rbx, rcx
mov ecx, 0xffffffff
would also set RCX the same way; NASM will optimize this for you to an efficient 5-byte instruction (with implicit zero-extension to 64-bit when writing a 32-bit register) instead of needing a 10-byte instruction with a 64-bit immediate; see another Q&A for more about the different forms of MOV in machine code.