1

I know the x64 calling convention, first four arguments are in rcx, rdx, r8, r9, rest are on the stack. But my question is how push these arguments?

call_func PROC
    push rbp
    mov rbp, rsp

    mov rbx, rcx ; move C function address to rbx

    mov rcx, 1   ; some dummy value
    mov rdx, 2   ; some dummy value
    mov r8,  3   ; some dummy value
    mov r9,  4   ; some dummy value

    ; and now I want to push fifth argument, but how?

    call rbx     ; call the function

    mov rsp, rbp
    pop rbp

    ret
call_func ENDP

I have tried mov QWORD PTR [rsp + 20h], 1 but when returning form this asm function the RIP register is set to weird value, like 0x0000000000000001. I know that the RIP register is instruction pointer, but why it is modifying it?
I have tried one more thing, let the function take 6 arguments and when I pass sixth argument like mov QWORD PTR [rsp + 28h], 1 the app is fine, sixth argument is passed, fifth has weird value.

Jorengarenar
  • 2,705
  • 5
  • 23
  • 60
Vento
  • 155
  • 2
  • 8
  • You're overwriting values higher up in the stack by doing that. You should look at the `push` instruction. – Thomas Jager Sep 05 '21 at 13:02
  • 1
    You need to allocate stack including the space shadow space first. E.g. do `sub rsp, 48` then you can use your `mov QWORD PTR [rsp + 20h], 1`. – Jester Sep 05 '21 at 13:10
  • @Jester Thank you, now it is working, weird because earlier I have tried this, but maybe without ```mov QWORD PTR [rsp + 20h], 1``` – Vento Sep 05 '21 at 13:17

1 Answers1

1

As Jester said, before pushing arguments I need to allocate space for these arguments including shadow space.
Final working code:

call_func PROC
    push rbp
    mov rbp, rsp
    sub rsp, 32  ; allocate shadow space 'padding'
    sub rsp, 16  ; allocate space for fifth and sixth argument

    mov r11, rcx ; move C function address to r11

    mov rcx, 1   ; some dummy value
    mov rdx, 2   ; some dummy value
    mov r8,  3   ; some dummy value
    mov r9,  4   ; some dummy value

    mov QWORD PTR [rsp + 20h], 5  ; push fifth argument
    mov QWORD PTR [rsp + 28h], 6  ; push sixth argument

    call r11     ; call the function

    mov rsp, rbp
    pop rbp

    ret
call_func ENDP
Vento
  • 155
  • 2
  • 8
  • 2
    There is no reason to use two `sub` instructions. More importantly, `rbx` is callee-saved register you should not use that for your temporary. – Jester Sep 05 '21 at 13:31
  • I know, it is just cleaner for newbies like me. And you are right, I forgot about ```rbx```, but I guess I can just push it on stack and then pop it? – Vento Sep 05 '21 at 13:34
  • 1
    You can but then you have to worry about alignment. You do have an extra stack slot available since you only use 5 arguments. Anyway, simplest is to pick another register that does not need to be preserved. – Jester Sep 05 '21 at 13:45
  • A quick&dirty alternative: load first four arguments to their registers, align RSP and then `PUSH Sixth, Fifth, R9, R8, RDX, RCX` before `CALL`. – vitsoft Sep 05 '21 at 15:04
  • You can write `sub rsp, 32 + 16 ; shadow space + arg space` if you want. – Peter Cordes Sep 05 '21 at 20:16
  • Or if you want to write `sub rsp, 32`, use `push` *before* that to write the two args. Since you have an even number of stack args, and an odd number of pushes of call-preserved registers (just RBP), that still restores 16-byte stack alignment. – Peter Cordes Sep 05 '21 at 20:18