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
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
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.
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.
GoAsm handles alignment automatically, you may wanna check with that.
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?
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.
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".
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.
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
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.
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.
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 ;-)
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);
}
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
Greg, the 'push rdi' aligns the stack to 16. Without it you would need 'sub rsp,28h'.
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
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...
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.
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!
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?
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.
>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.
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.
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
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).
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.
i thought the real trick was stopping the screen-saver - not starting it
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.
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.
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.
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.
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
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.