Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

64-bit mode does not support 32-bit PUSH and POP instructions [duplicate]

NASM returns an error like: "instruction not supported in 64-bit mode"
(Or with YASM, invalid size for operand 1)

The subject instructions are pop ecx and push ecx.
What can I use instead of them or is there an other way to fix this issue?

like image 735
Konko Avatar asked Apr 16 '17 09:04

Konko


People also ask

What is push & pop instructions?

The easiest and most common way to use the stack is with the dedicated "push" and "pop" instructions. "push" stores a constant or 64-bit register out onto the stack. The 64-bit registers are the ones like "rax" or "r8", not the 32-bit registers like "eax" or "r8d". "pop" retrieves the last value pushed from the stack.

How many bytes are copy by pop instruction?

pop has the same choices of size: 16, 32, or 64, except no 32-bit pop in 64-bit mode.

What is pop in assembly language?

The pop instruction removes the 4-byte data element from the top of the hardware-supported stack into the specified operand (i.e. register or memory location). It first moves the 4 bytes located at memory location [SP] into the specified register or memory location, and then increments SP by 4. Syntax. pop <reg32>

What is pop ECX?

push ecx and pop ecx are single-byte instructions, while add and sub are three byte each. The difference may not be huge, but all the saved bytes in all functions may add up to something substantial. ecx is considered to be spoiled by a function call, so it's safe to trash it with pop ecx after function calls.


1 Answers

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.

  • 16 bit registers (push ax) and memory references (push word ptr[rax]);
  • 8-bit sign-extended or 16 bit immediates. push word 123

8-bit registers can't be pushed in any mode (except as part of a wider register), and 32-bit push/pop aren't available in 64-bit mode, even with a REX.W=0 prefix.

like image 169
Matteo Italia Avatar answered Oct 12 '22 14:10

Matteo Italia