News:

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

Worked in Win7 Beta but not in Release

Started by GregL, January 21, 2010, 02:06:32 AM

Previous topic - Next topic

GregL

The following code, which I actually use now and then, worked in Windows 7 x64 Beta, it's not working now with the final release. Does anyone have any ideas?

SendMessageW returns 0 but nothing happens.

I tried running as admin too.

StartScreensaver.asm

EXTRN GetDesktopWindow: PROC
EXTRN SendMessageW: PROC
EXTRN ExitProcess: PROC

WM_SYSCOMMAND  EQU   112h
SC_SCREENSAVE  EQU 0F140h

.CODE

    main PROC
   
        sub rsp, 40    ; changed from sub rsp, 32
       
        call GetDesktopWindow
        mov rcx, rax
        mov edx, WM_SYSCOMMAND
        mov r8d, SC_SCREENSAVE
        mov r9d, 0
        call SendMessageW
       
        xor ecx, ecx
        call ExitProcess
       
    main ENDP
   
END


BogdanOntanu

The stack is not aligned to 16 at API  procedure start?

The sub rsp,32 instruction is not correctly balancing the stack because the CALL will push an 8 bytes return address and 20h+8h = 28h and this is not aligned to 10h.

Try sub rsp,28h
Ambition is a lame excuse for the ones not brave enough to be lazy.
http://www.oby.ro

GregL

BogdanOntanu,

Thank you.

Yes, you are correct, the stack was not aligned to 16 after sub rsp,32.  I thought that as long as the value being subtracted was a multiple of 16 you were OK, but that is not the case.  For this same program VC will use sub rsp,32.  I'm confused.

I sure wish someone would write a good book on x64 assembly language programming.

Anyway, after changing it to sub rsp,40, it still returns no errors and does nothing.  If I remember correctly, it worked with the Windows 7 x64 Beta.  ...  Maybe not.


BogdanOntanu

Quote from: Greg Lyon on January 21, 2010, 06:56:25 PM
Yes, you are correct, the stack was not aligned to 16 after sub rsp,32.

No. It has to be aligned to 16 when the called procedure is entered. This means AFTER the CALL pushes the 8 bytes return address.

Quote
  I thought that as long as the value being subtracted was a multiple of 16 you were OK, but that is not the case.

Sometimes it is OK and sometimes it is not ok. It all depends on the number of parameters of the target procedure / API.

Quote
  For this same program VC will use sub rsp,32.  I'm confused.

I seriously doubt it. Maybe you are wrongly reading/interpreting VC's   generated binary code.

Quote
I sure wish someone would write a good book on x64 assembly language programming.

Hi hi ... Let us assume that I could but then would you and enough many others buy it? to make it commercially viable? :D

Quote
Anyway, after changing it to sub rsp,40,

For the sake of making code easier to read and to avoid errors I do suggest that you use hexadecimal numbers / constants with ASM examples when appropriate (ie almost always). 40 decimal is not as clear as 28h for this stack alignment purpose. One ca clearly see that adding 8h to 28h makes it 30h and this is aligned to 10h

Quote
it still returns no errors and does nothing.

Eh... maybe THEN there are still other errors in your code... for example the Win64 Calling convention states that the caller must also restore/clean up the stack after a call. It also states that there must be enough space reserved on stack for a spill of the 4 register parameters no matter what... ie. even if there is only one parameter...

Quote
  If I remember correctly, it worked with the Windows 7 x64 Beta.  ...  Maybe not.

Unles you make exhaustive and elaborate functional testing, unit testing and regression testing One can NEVER be sure that a (complex) program does not have a bug. You can only say that the bug has not yet manifested.

The only certain thing in software development is when you have a bug that can be reproduced. Hence be happy that you have a bug... otherwise you might have never known... :D

Then ... some versions/builds of the Windows 64 bits are more tolerant with alignment issue than other. Sometimes the parameters are read wrongly inside the API (aligned from ESP+xxx) and the functions are apparently behaving erratic OR silently fail when you are making calling conventions / alignment errors in your 64 bits code.

Ambition is a lame excuse for the ones not brave enough to be lazy.
http://www.oby.ro

BlackVortex

GoAsm handles alignment automatically, you may wanna check with that.

sinsi

When your program gets control, the stack is aligned to 8, not 16, because of the call that windows starts your code with.
I usually have my main procedure call only other procedures and not API calls, that way when you call another proc the stack will be aligned to 16.
One problem I sometimes have is remembering that if an API call has an odd number of parameters you need to add an extra 8 to align it, since it is the first parameter spill space that needs to be aligned (even though it's in rcx).

You can do fancy maths on rsp to align it to 16, but if you know the alignment on entry it is just a matter of counting the 8's in the API :bdg
I've said it before, but whoever designed the ABI for win64 was brain-dead. 15 registers we can use but we can only use 4?

How does 64-bit linux go? Is that also 16-byte alignment?
Light travels faster than sound, that's why some people seem bright until you hear them.

GregL

BogdanOntanu,

Thanks for the comments. I'm going to think about them for a while. I thought I had a pretty good grasp of this x64 assembly language, but now I see that I need to learn more about it.



GregL

Quote from: BlackVortexGoAsm handles alignment automatically, you may wanna check with that.

Yeah, I know. I could also just use a C compiler, but I want to know how it works "under the hood".


GregL

Quote from: sinsiWhen your program gets control, the stack is aligned to 8, not 16, because of the call that windows starts your code with.

Yeah I noticed that just today. I had thought the stack would be aligned to 16 when your program gets control.


Please post some examples of your code.

sinsi

Here is part of a 32-bit program that I tried in 64-bit. It was a while ago but I use similar conventions nowadays.
A couple of routines were experiments with the stack, but it seems to work on my box.

You will have to edit the source to get the paths right (I included my versions of include files) but no libraries.  :bg
Light travels faster than sound, that's why some people seem bright until you hear them.

BogdanOntanu

This link might also help: http://ntcore.com/files/vista_x64.htm

Quote
How does 64-bit linux go? Is that also 16-byte alignment?

Yes but the rules are slightly different. However the stack alignment is the same in Linux. In fact in guess that both Windows and Linux copied from some early (and IMHO obsolete) 64 bits RISC conventions when creating this "new" thing beacuse this was the only "prior art" and they did not wanted to think logically. And BTW MacOSX also has this stack alignment issues (again with subtle changes).

This convention is IMHO wrong but as you can see it is here to stay for a very long time hence one should get used to it no matter what.

In my programs I will try to use STDCALL as much as possible and use win64 fastcall only when needed... but this might be tricky so do not try it at home ;)

Quote
GoAsm handles alignment automatically, you may wanna check with that.

Yes, but SolAsm does this also and IMHO in better ways. You might notice that SolAsm uses PUSH and makes EAX dirty on lower occasions than the standard sequence for variable arguments:

mov eax,[my_variable]
mov [esp + arg[n]],eax


The next Sol_Asm release will handle multiple ways to adjust/align the stack in order to give the ASM programmer more options with INVOKE in 64 bits programming.

And I also guess that FASM macros and YASM (NASM)  do this automatically.

Besides GoAsm does run time calculations to align the stack and this might be considered as "bad".

IMHO it is useful in this early 64 bits stages to gather multiple simple samples from multiple assemblers and C compilers to observe how each one does handle such things.




Ambition is a lame excuse for the ones not brave enough to be lazy.
http://www.oby.ro

GregL

Sinsi,

Thanks for the example.



BogdanOntanu,

Thanks for the link you posted. I had read it before, but I really read it in detail, and I now see how the stack space and alignment works.  I didn't have it right before.

It's interesting that I have several programs where the stack alignment is not correct and they run just fine, so it makes me wonder how critical it is. Of course I will do it the correct way from now on.

The program in my first post is the only one that isn't working since switching to the final release of Windows 7 x64. I'm thinking the OS is just not allowing this to work now for whatever reason.



jj2007

Quote from: Greg Lyon on January 22, 2010, 11:00:45 PM
I'm thinking the OS is just not allowing this to work now for whatever reason.

When you call your own homebrew "API", it shouldn't matter. But probably M$ plans to use SSE2 in future versions of Windows, and then 16-byte alignment will play a big role indeed. It will be messy ;-)

GregL

#13
QuoteWhen you call your own homebrew "API", it shouldn't matter. But probably M$ plans to use SSE2 in future versions of Windows, and then 16-byte alignment will play a big role indeed. It will be messy ;-)

What I meant was the Desktop Window is no longer responding to the SC_SCREENSAVE message for whatever reason. It could be a security issue.



The problem here is not any problem with my code. The same program in C does the same thing. And this code has always worked with previous versions of Windows. It's a handy little utility that I have used for years.


#include <Windows.h>

int main(void)
{
SendMessage(GetDesktopWindow(), WM_SYSCOMMAND, SC_SCREENSAVE, 0);
ExitProcess(0);
}


GregL

Just for anyone who is interested, here is the disassembly of the C program in the above post compiled with VC 2010. Notice the sub rsp,20h (and then it fills this space with 0CCCCCCCCh).  So I'm still confused. I think I would go with how the C compiler does it.


000000013F721010  push        rdi 
000000013F721012  sub         rsp,20h 
000000013F721016  mov         rdi,rsp 
000000013F721019  mov         ecx,8 
000000013F72101E  mov         eax,0CCCCCCCCh 
000000013F721023  rep stos    dword ptr [rdi] 
000000013F721025  call        qword ptr [__imp_GetDesktopWindow (13F7283E0h)] 
000000013F72102B  xor         r9d,r9d 
000000013F72102E  mov         r8d,0F140h 
000000013F721034  mov         edx,112h 
000000013F721039  mov         rcx,rax 
000000013F72103C  call        qword ptr [__imp_SendMessageW (13F7283D8h)] 
000000013F721042  xor         ecx,ecx 
000000013F721044  call        qword ptr [__imp_ExitProcess (13F728248h)] 
000000013F72104A  add         rsp,20h 
000000013F72104E  pop         rdi 
000000013F72104F  ret