Patrick S
Patrick S

Reputation: 245

nasm 64 bit push qword?

I seem to have an interesting issue, though I am probably doing something blatantly wrong.

My issue is that I am attempting to push AAAABBBBCCCC onto the stack, then print them through stdout. However it seems that in my x86_64 environment the push 0x41414141 pushes 4141414100000000.

So the following code block:

    global _start
    section .text
    _start:
    push 0x43434343  ; CCCC
    push 0x42424242  ; BBBB
    push 0x41414141  ; AAAA
    xor rax,rax      ; Zero RAX
    mov byte al,0x1  ; 1 for sys_write
    mov rdi,rax      ; 1 for stdout
    mov rsi,rsp      ; RSP for source
    mov byte dl,0xC  ; 12
    syscall          

    xor rax,rax      ; Zero RAX
    mov al, 0x3C     ; 60 for sys_edxit
    cdq              ; 0 for clean exit.
    syscall

Outputs AAAABBBB, of what I thought was only 8 bytes, was actually the 12 I asked for. When piped to an output file and looked at in hexedit, I noticed it was displaying 414141410000000042424242.

I figure the push instruction pushes a dword value. onto a qword sized stack? Am I correct in thinking this?

This can be cheeply avoided by taking into account the extra bytes, and changing my length to 20. But that would cause issues with things like sys_open.

So my question is, what am I doing wrong?

Upvotes: 4

Views: 9399

Answers (1)

Brendan
Brendan

Reputation: 37214

For 64-bit code the stack (RSP) is always aligned on an 8 byte boundary. There's also no "push qword imm64" instruction (see note).

My advice would be to store the string "AAAABBBBCCCC" in your data section (or ".rodata") where it belongs instead of messing with the stack. Or in shellcode,

push   'CCCC'                  ; push qword, including 4 bytes of zeros
mov    rax, 'AAAABBBB'         ; mov reg, imm64; pick any register
push   rax                     ; push qword

An alternative that preserves your perversion might be:

sub rsp,16
mov dword [rsp],'AAAA'
mov dword [rsp+4],'BBBB'
mov dword [rsp+8],'CCCC'
....
add rsp,16

Note: AMD's manual says there is a "push imm64" instruction. AMD's manual is wrong - this instruction actually pushes a 32-bit immediate (with sign extension to 64-bits).

Intel's manual doesn't have that problem: https://www.felixcloutier.com/x86/push
Also related: How many bytes does the push instruction push onto the stack when I don't specify the operand size? - you definitely can't do a dword push in 64-bit mode.

Upvotes: 12

Related Questions