News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

stack problem

Started by mstrcool, January 05, 2010, 09:29:03 PM

Previous topic - Next topic

mstrcool

Hi, I can't push values before calling any API, the application crash, I really need to solve this problem because I will store values that I can't keep safe in registers (even if now there are more regs).

push rax
sub rsp, 28h
xor r9, r9
lea r8, msg
lea rdx, msg
xor rcx, rcx
call MessageBoxA
add rsp, 28h
pop rax

I fixed the push adding to 28h + 8, the app didn't crash, but if I push 2 times, then crash.
So, how to solve it?

BogdanOntanu

You can push BUT as per the Win64 ABI (application binary interface) you MUST keep the stack aligned to 16 at start of function (the return address is/adds an extra 8bytes on stack when the CALL is made)

In consequence you must compensate for odd / even number of pushes in such a way as to keep the stack aligned. It is relatively simple.
Ambition is a lame excuse for the ones not brave enough to be lazy.
http://www.oby.ro

mstrcool

I'm sorry for this stup*d question but how do I align it?

I am aware that I must allocate 20h of space + 8 for the API thing, I did, then why it fails?

jj2007

Since Bogdan is offline, and you are waiting for an answer, I'll try my luck:
20h of space + 8 = 32+8=40, not divisible by 16. Add one push maybe?

mstrcool

I said that to solve the problem of 1 push I added to 28h + 8, then if I want to push twice I need to add 8 again?

push rax
sub rsp, 28h + 8
xor r9, r9
lea r8, msg
lea rdx, msg
xor rcx, rcx
call MessageBoxA
add rsp, 28h + 8
pop rax

twice:
push rax
sub rsp, 28h + 8 + 8
xor r9, r9
lea r8, msg
lea rdx, msg
xor rcx, rcx
call MessageBoxA
add rsp, 28h + 8 + 8
pop rax

jj2007

Quotepush rax
sub rsp, 28h + 8 + 8

= 8+40+8+8=64, OK

mstrcool

I think I understand now, for every push (8) one more add (8). So this works:

push rax
sub rsp, 28h + 8 + 8

I want to push 9 values (9 * 8 = 81 bytes), instead I must then push 12 values (12 * 8 = 96) so the stack will be aligned to 16, right?


jj2007

Quote from: mstrcool on January 05, 2010, 11:37:20 PM
I think I understand now, for every push (8) one more add (8). So this works:

push rax
sub rsp, 28h + 8 + 8

I want to push 9 values (9 * 8 = 81 bytes), instead I must then push 12 values (12 * 8 = 96) so the stack will be aligned to 16, right?


I have no idea of 64-bit assembler, but I assume you just must ensure that the total is divisible by 16. So if you have 9 values, you need an extra 8 bytes: 9*8=72, 72+8=80 (80/16=5, OK). Test it...

mstrcool

I made the wrong calc you are correct.

Astro

If the stack isn't aligned in 64-bit, it crashes?

O/T: even if passing via registers, do you still need to assign the space on the stack?

Best regards,
Robin.

sinsi

QuoteIf the stack isn't aligned in 64-bit, it crashes?
It can crash with an error, it can work, it can just disappear silently.

Quoteeven if passing via registers, do you still need to assign the space on the stack?
Yes, the called API uses 4 qwords as spill space. Your own procs can do what they want but windows API calls expect the space to be there.
Light travels faster than sound, that's why some people seem bright until you hear them.

Astro

Interesting. Have they tightened coding standards so errors are less tolerated then or is it some side-effect of something else?

I'm intrigued about a few things I've read so far - mov in 64-bit can only move up to 4 bytes to memory for example, and to move 8 requires use of a register.

Best regards,
Robin.

tofu-sensei

Quote from: Astro on January 31, 2010, 01:07:24 AM
Interesting. Have they tightened coding standards so errors are less tolerated then or is it some side-effect of something else?
a misaligned stack would already cause problems on 32-bit versions of windows. i'd suggest you get some more information about x64 calling conventions :)

GregL

This is what I have come up with.


  • Required spill area, 4 registers (rcx, rdx, r8, r9) = 32 (20h)
  • For each additional parameter (that is pushed on the stack) add 8.
  • Align this (up) to 16.
  • Add 8 for the return address.

Total without any additional parameters = 40 (28h)   <-- Note: This is not divisible by 16. This works because the stack is not aligned to 16 at procedure start, it is off by 8.

Do this for each procedure.


Proc1 PROC

    sub rsp, 40

    ...

    add rsp, 40
    ret
Proc1 ENDP



GregL

This is a good article about it, the x64 Assembly section.

Raymond Chen's blog entry The history of calling conventions, part 5: amd64 is good too.