The MASM Forum Archive 2004 to 2012

Project Support Forums => 64 Bit Assembler => Topic started by: GregL on January 21, 2010, 02:06:32 AM

Title: Worked in Win7 Beta but not in Release
Post by: GregL on January 21, 2010, 02:06:32 AM
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

Title: Re: Worked in Win7 Beta but not in Release
Post by: BogdanOntanu on January 21, 2010, 07:52:34 AM
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
Title: Re: Worked in Win7 Beta but not in Release
Post by: GregL on January 21, 2010, 06:56:25 PM
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.

Title: Re: Worked in Win7 Beta but not in Release
Post by: BogdanOntanu on January 21, 2010, 08:10:49 PM
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.

Title: Re: Worked in Win7 Beta but not in Release
Post by: BlackVortex on January 22, 2010, 04:46:02 AM
GoAsm handles alignment automatically, you may wanna check with that.
Title: Re: Worked in Win7 Beta but not in Release
Post by: sinsi on January 22, 2010, 05:04:25 AM
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?
Title: Re: Worked in Win7 Beta but not in Release
Post by: GregL on January 22, 2010, 05:54:05 AM
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.


Title: Re: Worked in Win7 Beta but not in Release
Post by: GregL on January 22, 2010, 05:58:08 AM
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".

Title: Re: Worked in Win7 Beta but not in Release
Post by: GregL on January 22, 2010, 06:11:57 AM
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.
Title: Re: Worked in Win7 Beta but not in Release
Post by: sinsi on January 22, 2010, 06:50:36 AM
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
Title: Re: Worked in Win7 Beta but not in Release
Post by: BogdanOntanu on January 22, 2010, 10:57:31 AM
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.




Title: Re: Worked in Win7 Beta but not in Release
Post by: GregL on January 22, 2010, 11:00:45 PM
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.


Title: Re: Worked in Win7 Beta but not in Release
Post by: jj2007 on January 23, 2010, 03:18:57 AM
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 ;-)
Title: Re: Worked in Win7 Beta but not in Release
Post by: GregL on January 23, 2010, 04:55:04 AM
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);
}

Title: Re: Worked in Win7 Beta but not in Release
Post by: GregL on January 23, 2010, 08:19:48 PM
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 



Title: Re: Worked in Win7 Beta but not in Release
Post by: sinsi on January 23, 2010, 10:17:26 PM
Greg, the 'push rdi' aligns the stack to 16. Without it you would need 'sub rsp,28h'.
Title: Re: Worked in Win7 Beta but not in Release
Post by: BogdanOntanu on January 23, 2010, 10:25:46 PM
After japeth's strong response in favor of aligning stack to 16 BEFORE the call is made ... I am also slightly confused :D
see this thread: http://www.masm32.com/board/index.php?topic=13202.0

I am in the process of re-reading the ABI documents and re-testing.

However in your example I see a push rdi in the prologue this PUSH performs an implicit sub rsp,8h.

This fixes the extra 8h from the return address and because of this a sub rsp,20h can be done by the compiler. And this is not against my statement that the stack should be aligned AFTER the call is made. At least this is how I see it now :D
Title: Re: Worked in Win7 Beta but not in Release
Post by: BogdanOntanu on January 23, 2010, 11:16:23 PM
Well, after re-tinking and re-considering ...

see here: http://msdn.microsoft.com/en-us/library/ew5tede7(VS.80).aspx

The relevant paragraph is this:

Quote
The stack will always be maintained 16-byte aligned, except within the prolog (for example, after the return address is pushed), and except where indicated in Function Types for a certain class of frame functions.

This "clearly" suggests that it is OK to have RSP not aligned immediately after the CALL is made.

And in this article:
http://blogs.msdn.com/oldnewthing/archive/2004/01/14/58579.aspx

It is said that:
Quote
Here's a sample:

void SomeFunction(int a, int b, int c, int d, int e);
void CallThatFunction()
{
    SomeFunction(1, 2, 3, 4, 5);
    SomeFunction(6, 7, 8, 9, 10);
}

On entry to CallThatFunction, the stack looks like this:
xxxxxxx0    .. rest of stack ..    
xxxxxxx8    return address    <- RSP

Due to the presence of the return address, the stack is misaligned. CallThatFunction sets up its stack frame, which might go like this:

    sub    rsp, 0x28

Notice that the local stack frame size is 16n+8, so that the result is a realigned stack.
xxxxxxx0    .. rest of stack ..    
xxxxxxx8    return address    
xxxxxxx0         (arg5)
xxxxxxx8         (arg4 spill)
xxxxxxx0         (arg3 spill)
xxxxxxx8         (arg2 spill)
xxxxxxx0         (arg1 spill) <- RSP

Now we can set up for the first call:

        mov     dword ptr [rsp+0x20], 5     ; output parameter 5
        mov     r9d, 4                      ; output parameter 4
        mov     r8d, 3                      ; output parameter 3
        mov     edx, 2                      ; output parameter 2
        mov     ecx, 1                      ; output parameter 1
        call    SomeFunction                ; Go Speed Racer!

This shows that the sub rsp,28h is done in the PROLOGUE of the function in order to keep the stack aligned to 16 in the function body and  compensate for the missaligned stack beacuse of the return address pushed by the CALL ABOVE and not for the CALL that will be made...

Hence the truth is in the middle: you must compensate for the return address... but in the prologue for the enclosing PROC and not at each INVOKE.

And the same rule apply for the Entry point of your program ... if written in ASM... then (normally) you will not be inside an enclosing PROC and you will need an sub rsp,8 or more if you use invoke there.


The rest of RAYMOND CHEN's article is also interesting showing how a compiler/assembler can avoid balancing the stack after each invoke inside a PROC...

Title: Re: Worked in Win7 Beta but not in Release
Post by: GregL on January 23, 2010, 11:53:37 PM
Quote from: sinsiGreg, the 'push rdi' aligns the stack to 16.

Quote from: BogdanOntanuHowever in your example I see a push rdi in the prologue this PUSH performs an implicit sub rsp,8h.

Yeah, I totally missed that.  :red  You guys are right.

Title: Re: Worked in Win7 Beta but not in Release
Post by: sinsi on January 24, 2010, 03:27:32 AM
The only time the stack needs to be aligned is if you are calling a windows API. In your own procs it doesn't matter.
It is easier to stick to one way though, and I think that if you ensure the stack is aligned before the call you know
that in the called proc it is not aligned, so you need a 'sub rsp,x8h' if you call an API.

edit: that code doesn't work in the RC either.
    woohoo 100,000 posts!
Title: Re: Worked in Win7 Beta but not in Release
Post by: GregL on January 24, 2010, 05:58:19 AM
sinsi,

You mean the StartScreensaver.asm (or .c) code doesn't work on Win7 x64 RC?  Maybe it never worked on x64  ::).

Then the question, why doesn't the program work on x64?
Title: Re: Worked in Win7 Beta but not in Release
Post by: GregL on January 24, 2010, 06:06:28 AM
Quote from: BogdanOntanuHence the truth is in the middle: you must compensate for the return address... but in the prologue for the enclosing PROC and not at each INVOKE.

And the same rule apply for the Entry point of your program ... if written in ASM... then (normally) you will not be inside an enclosing PROC and you will need an sub rsp,8 or more if you use invoke there.

From everything I have read, I think that is right. That's what I'm going to do.

Title: Re: Worked in Win7 Beta but not in Release
Post by: sinsi on January 24, 2010, 06:19:41 AM
>You mean the StartScreensaver.asm (or .c) code doesn't work on Win7 x64 RC?
I assembled (and fixed) the asm code but not the c code (yuk!), tried SendMessageA instead of 'W' and, nope - win7 RC x64.

From windbg, a few things - GetCurrentThreadDesktopHwnd instead of GetDesktopWindow and the following error after SendMessage with !gle
Quote
LastErrorValue: (Win32) 0x36b7 (14007) - The requested lookup key was not found in any active activation context.
LastStatusValue: (NTSTATUS) 0xc0150008 - The requested lookup key was not found in any active activation context.
Title: Re: Worked in Win7 Beta but not in Release
Post by: GregL on January 25, 2010, 07:08:29 PM
Thanks sinsi.  I would be curious to see whether or not the code works on 32-bit Vista or Win7.

The workaround is to make a shortcut to C:\Windows\System32\PhotoScreensaver.scr /s (or whatever screensaver you are using). Not as versatile but it does the job.

Title: Re: Worked in Win7 Beta but not in Release
Post by: ChillyWilly on January 25, 2010, 07:15:30 PM
im having a problem with reading a registry key in win7 64bit  :'(
can someone give me some insight on how to fix my code there?

http://www.masm32.com/board/index.php?topic=13194

Title: Re: Worked in Win7 Beta but not in Release
Post by: GregL on January 29, 2010, 01:53:35 AM
Quote from: Greg LyonI would be curious to see whether or not the code works on 32-bit Vista and/or Win7.

Attached is the code and the.exe (32-bit).

Title: Re: Worked in Win7 Beta but not in Release
Post by: sinsi on January 29, 2010, 02:04:29 AM
OK, I have a confession to make...I didn't actually have a screensaver selected so of course your code didn't work.
Now that I have one, both 64- and 32-bit programs work as expected.
Excuse me while I curl up and die of embarassment.
Title: Re: Worked in Win7 Beta but not in Release
Post by: dedndave on January 29, 2010, 02:11:48 AM
i thought the real trick was stopping the screen-saver - not starting it
Title: Re: Worked in Win7 Beta but not in Release
Post by: GregL on January 29, 2010, 03:34:19 AM
sinsi,

OK, so I am not going senile, I thought it worked on Win7 RC.  So, I am back to the original question.


Quote from: dedndavei thought the real trick was stopping the screen-saver - not starting it

I never had a need to do that.
Title: Re: Worked in Win7 Beta but not in Release
Post by: sinsi on January 29, 2010, 04:28:15 AM
Could another program/service be stopping the message? Returning -1 for the message will stop the screensaver from kicking in.
If you set it to require a password on resume, apparently the return from the message is ignored, so no program can stop it starting.

me senile, not you.
Title: Re: Worked in Win7 Beta but not in Release
Post by: GregL on January 29, 2010, 09:25:00 PM
sinsi,

I don't have it set it to require a password on resume, so that's not the problem.  SendMessage returns 0 and GetLastError after SendMessage returns 0.  I'll have to dig into it some more. I think I remember reading something about changes being made to how the Desktop works.

It's good to know I haven't completely lost my faculties.  :bg

Thanks for your help.
Title: Re: Worked in Win7 Beta but not in Release
Post by: GregL on January 29, 2010, 10:42:50 PM
Well, it's working now.

I went into Screensaver Settings and changed from Photos to Windows Live Photo Gallery.  I tried my program and it worked!  I then changed it back to Photos and it worked.  Apparently something had gotten messed up.  God computers can drive you nuts sometimes.  Geez!  ::)

Well, we had a good discussion about x64 stack alignment anyway.



Title: Re: Worked in Win7 Beta but not in Release
Post by: dedndave on January 29, 2010, 11:05:55 PM
lol - fricken gremlin
now, you have to go back and re-trace everything (start with the original code) until you find out what was messed up
i hate it when something is fixed and i don't know the reason
i would rather it be broken again
Title: Re: Worked in Win7 Beta but not in Release
Post by: GregL on January 30, 2010, 12:42:37 AM
Quote from: dedndavenow, you have to go back and re-trace everything (start with the original code) until you find out what was messed up

I'm not going to worry about it, the code works, the problem was with Windows. I'm done with it.

I just assumed since the screensaver was working, with the timeout value, all was OK with it. Not so.

Quote from: dedndavei hate it when something is fixed and i don't know the reason

Yeah, I hate it too.  But I'm going to chalk this one up to a Windows glitch.


Oh well, it was a good discussion on x64 stack alignment, and I learned something new about that.
Note: I corrected the code in the first post for correct alignment.