push on 64bit intel osx
I want to push 64 bit address on stack as below,
__asm("pushq $0x1122334455667788");
But I get compilation error and I can only push in following way,
__asm("pushq $0x11223344");
Can someone help me understand my mistake?
I am new to assembly, so please excuse me if my question sounds stupid.
x86-64 has some interesting quirks, which aren't obvious even if you're familiar with 32-bit x86...
-
Most instructions can only take a 32-bit immediate value, which is sign-extended to 64 bits if used in a 64-bit context. (The instruction encoding stores only 32 bits.)
This means that you can use
pushq
for immedate values in the range0x0
-0x7fffffff
(i.e. positive signed 32-bit values which are sign-extended with 0 bits) or0xffffffff80000000
-0xffffffffffffffff
) (i.e. negative signed 32-bit values which are sign-extended with 1 bits). But you cannot use values outside this range (as they cannot be represented in the instruction encoding). mov
is a special case: there is an encoding which takes a full 64-bit immediate operand. Hence Daniel's answer (which is probably your best bet).-
If you really don't want to corrupt a register, you could use multiple pushes of smaller values. However, the obvious thing of pushing two 32-bit values won't work. In the 64-bit world,
push
will work with a 64 bit operand (subject to point 1 above, if it's an immediate constant), or a 16 bit operand, but not a 32 bit operand (evenpushl %eax
is not valid). So the best you can do is 4 16-bit pushes:pushw $0x1122; pushw $0x3344; pushw $0x5566; pushw $0x7788
Your best bet would be to do something like this.
movq $0x1122334455667788, %rax
pushq %rax
Replace %rax
with any other 64-bit register you find appropriate.
There is no single instruction capable of taking a 64-bit immediate value and pushing that onto the stack.
from how to use rip relative addressing
pushq my_const(%rip)
...
my_const: .quad 1122334455667788