NASM returns an error like: "instruction not supported in 64-bit mode" and I couldn't figure out what to do.
The subject instruction is pop ecx
and push ecx
instructions. What can I use instead of them or is there an other way to fix this issue?
The general idea is that you normally push and pop full registers, i.e. 64-bit registers in 64-bit mode. push
's default operand-size is 64-bit, and 32-bit operand-size is not available. Does each PUSH instruction push a multiple of 8 bytes on x64? (yes, unless you specifically use a 16-bit push, but 32-bit isn't available).
You cannot push a 32 bit register in 64 bit mode; instead, you can push and pop the whole 64 bit register that contains a 32-bit value you want, so that's push rax
instead of push eax
. The same holds for memory references - you can push qword ptr[rax]
, but not push dword ptr[rax]
.
But: even in 64 bit mode you can still push:
8 or 32 bit immediates sign extended to 64; this is generally handled automatically by your assembler as an optimization (if you do push 1
it will encode it with the most compact encoding, which will be 6A01
, i.e. with an imm8 operand). It's always a 64-bit push unless you explicitly specify push word 1
, regardless of what width of immediate the assembler picks.
the fs
and gs
segment registers but not the cs
, ds
, es
, ss
registers (which aren't important in 64-bit mode, and can only be read with mov
, not push
, freeing up those push/pop opcode for potential future use).
As an exception, segment registers are either zero-extended or pushed on the stack with a 16-bit move (i.e. the other 48 bit on the stack are left unmodified); this isn't really much of a problem, since pop fs
and pop gs
just discard these extra bits.
You can emulate a push imm64
with push low32
/ mov dword [rsp+4], high32
. Or with mov r64, imm64
/ push r64
; mov
to register (not memory) is the only x86-64 instruction that can take a 64-bit immediate.
With 16-bit operand-size (a 66h
prefix), you can do a 16-bit push which adjusts RSP by 2 instead of 8. But normally don't do this because it will misalign the stack until you do a 16-bit pop or otherwise correct it.
push ax
) and memory references (push word ptr[rax]
);8-bit registers can't be pushed in any mode (except as part of a wider register), and 32-bit isn't available in 64-bit mode, even with a REX.W=0
prefix.