2

I have following code:

[bits 64]
%define msg db "%i\n", 0xa, 0
%define var -4
mov r8, rsp
mov [r8+(var)], WORD 0xFFFF
push WORD [r8+(var)] ; not works
; if trying to push DWORD its shows error instruction not supported in 64 bit asm
push DWORD 0xFFFF ; works
call tCtAKBWomJ
msg
tCtAKBWomJ:
call [rbx+3*8]
add rsp, 8
push 0
call [rbx]

call [rbx + x * 8]

is call to asmloader api

x = 0, exit

x = 3, printf

etc.

i want to move value to "variable" and push it to stack.

EDIT:

[bits 64]

; const
%define msg db "%i", 0xa, 0

; vars offsets
%define var 8
; vars address
mov r8, rsp

; set var to 0xFFFF
mov DWORD [r8+(var)], 0xFFFF
; push var
push QWORD [r8+(var)]
; push const string msg
call tCtAKBWomJ
msg
tCtAKBWomJ:
; call printf
call [rbx+3*8]
add rsp, 8
; exit
push 0
call [rbx]

"variable offset" should be + value, not -.

and i should use

push QWORD

idiot
  • 53
  • 6
  • 3
    You should never need the `bits 64` directive as it doesn't lead to functioning programs. Instead, select the appropriate flags to create a 64 bit object when runninig the assembler. That said, there is indeed no `PUSH DWORD` instruction in 64 bit mode. Try `PUSH QWORD` instead. But that said, you do not pass arguments to functions on the stack in 64 bit mode normally, so your code may not work correctly even with that. – fuz Aug 28 '18 at 12:58
  • thanks, push qword has helped :) – idiot Aug 28 '18 at 13:01

2 Answers2

3

Instead of

PUSH DWORD [r8+(var)]

use

PUSH QWORD [r8+(var)]

as all words pushed on the stack are qwords.

fuz
  • 88,405
  • 25
  • 200
  • 352
2

NASM syntax push DWORD 0xFFFF is a push of a dword immediate, sign-extended to qword, when assembled in 64-bit mode.

IDK why NASM and YASM accept it without warning; I'd argue they shouldn't because it's misleading, as you discovered.

Only push strict dword 1 should work, to override the encoding of the immediate (not the operand-size of the instruction). Note the strict keyword, which is used for overriding the normal selection of the shortest encoding (and in this case forcing an imm32 even if the number could be encoded in an imm8). push dword 1 does not inhibit optimization to push imm8, it only sets the operand to dword. Except it doesn't, it sets it to qword in 64-bit mode. Super confusing and arguably broken.

The only legal operand-sizes for push in 64-bit mode are 64 and 16. How many bytes does the push instruction push onto the stack when I don't specify the operand size?. 32-bit push is not encodeable in 64-bit mode.

This applies to pushes with memory and register operands, not just immediates. This is why push dword [mem] isn't encodeable; in that case NASM treats it as actually requiring a dword memory operand.


A QWORD push-immediate can use an 8-bit or 32-bit immediate, both sign extended to 64. The width of the immediate is separate from the operand-size (the width of the store to memory, and the amount subtracted from RSP). Again, see that linked question.

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847