8

I want to push a 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.

phuclv
  • 37,963
  • 15
  • 156
  • 475
RLT
  • 4,219
  • 4
  • 37
  • 91

4 Answers4

18

x86-64 has some interesting quirks, which aren't obvious even if you're familiar with 32-bit x86...

  1. 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 range 0x0 - 0x7fffffff (i.e. positive signed 32-bit values which are sign-extended with 0 bits) or 0xffffffff80000000 - 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).

  2. 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).

  3. 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 (even pushl %eax is not valid). So the best you can do is 4 16-bit pushes:

    pushw $0x1122; pushw $0x3344; pushw $0x5566; pushw $0x7788

Matthew Slattery
  • 45,290
  • 8
  • 103
  • 119
  • 7
    Comment to point #3: `subq $8, %rsp; movl $0x55667788, (%rsp); movl $11223344, 4(%rsp)` would work too. – Jester Nov 13 '12 at 01:42
  • 3
    @Jester: pushl $0x55667788; movl $11223344, 4(%rsp) ? – Aki Suihkonen Nov 15 '12 at 05:58
  • @AkiSuihkonen: No, `pushl` is [not](https://stackoverflow.com/questions/45127993/how-many-bytes-does-the-push-instruction-push-onto-the-stack-when-i-dont-specif) [encodeable](https://stackoverflow.com/questions/40305965/does-each-push-instruction-push-a-multiple-of-8-bytes-on-x64) in 64-bit mode. You want `pushq` (aka `push`) with a sign-extended 32-bit immediate, then `movl $high, 4(%rsp)` to overwrite the high half. – Peter Cordes Oct 07 '20 at 03:23
9

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.

Daniel Kamil Kozar
  • 18,476
  • 5
  • 50
  • 64
5

There is no single instruction capable of taking a 64-bit immediate value and pushing that onto the stack.

David Schwartz
  • 179,497
  • 17
  • 214
  • 278
5

from how to use rip relative addressing

pushq my_const(%rip)
...
my_const: .quad 1122334455667788
Community
  • 1
  • 1
Aki Suihkonen
  • 19,144
  • 1
  • 36
  • 57