Hello. I've been trying some manual stack manipulation for local variables and all seemed to be going well. I have a problem outputting more than one of these values at a time though. I checked this by first outputting each value individually with a message box. Immediately after that, I use wsprintf to put them all in a formatted string. However, the output does not match the message box (correct) output. Here is some of the code I am using....


local format

format db "Clock Time: %.2d:%.2d:%.2d",0

; Makes the typing easier
Hours equ dword ptr [esp + 4]
Minutes equ dword ptr [esp + 8]
Seconds equ dword ptr [esp + 12]
hSeconds equ dword ptr [esp + 16]
mSeconds equ dword ptr [esp + 20]

...initialize and do stuff

invoke wsprintf, offset buffer, addr format, Hours, Minutes, Seconds

I already know for sure (well, pretty sure ;)) that the values in the stack are correct. Am I right in guessing that when the arguments are passed to wsprintf, the stack increases and my variables no longer start at ?

...Actually, I just tried to change the wsprintf call to account for the stack change, if thats what it is. It works now, but I would like to know if this is the correct solution...

invoke wsprintf, offset buffer, addr format, Hours + 8, Minutes + 4, Seconds

Any help is always appreciated. Thanks :grin:
Posted on 2001-12-07 03:50:44 by AlexEiffel
If I remember well, wsprintf is not a stdcall API but a cdecl one...
You have to correct your stack pointer after using it... it's because of the variables args...
I had the problem when i used the good ol' push and call fashion to call the api, but I think with invoke, the problem is not here...

Maybe it's not where the problem is from (sorry, i don't have the time to test further right now), but it's maybe a way to find what is going wrong...

Posted on 2001-12-07 04:18:03 by JCP
Yes Alex, the problem is that when pushing parameters for the
wsprintf call, ESP changes, and thus your variable offsets no longer
work. This is why people use the EBP frame pointer setup thingamajig,
or use a compiler that can adjust ESP references...
Posted on 2001-12-07 10:55:04 by f0dder
to have all regs incl. stack restored after the call to wsprintfA, do like this:

pushad ;store all regs (esp+20h)
invoke wsprintf, offset buffer, addr format, Hours + 8, Minutes + 4, Seconds
add esp, 10h ; fix stack
popad ; restore regs
Posted on 2001-12-07 19:42:19 by DZA
f0dder, could you please explain how
the EBP frame pointer setup thingamajig
works? EBP points to the base of the stack while ESP points to the top, right? Could you perhaps show me, if you have the time, by modifying the code I posted? Thanks to everyone that replied :)
Posted on 2001-12-08 00:33:28 by AlexEiffel
AlexEiffel, if you have the time it's in the Intel Architecture Software Developer's Manual Volume 1: Chapter 4 - nice pictures and all - it's not hard to grasp.

Intel Architecture Software Developer's Manual Volume 1

If you use locals referenced from EBP that would solve your problem. invoke pushes values on the stack, and push operation changes the value of ESP. So, it becomes harder to predict what your pushing because you have a moving target. ;) Not that it can't be done, it's just not designed into MASM and you'd have to calculate it manually.
Posted on 2001-12-08 00:39:53 by bitRAKE
Thanks for the link. I've found lost of interesting information already. Don't know why I never downloaded it before, I have the other two volumes. I looked over ch. 4 but I did not see what I needed. I'm going to look over it again as well as the other chapters. I probably just missed it. I had tried doing a few tests using ebp, but I just couldn't figure it out. I will try again after I've read through volume 1.
Posted on 2001-12-08 01:11:31 by AlexEiffel
Sorry, it's now Vol.1, Chapter 6. Just ignore most the mention of segments for now. Fig. 6-1, Section 6.5, and is power for the course.

Posted on 2001-12-08 01:19:08 by bitRAKE
Instead of manipulating the stack youself, you can get masm to do it for you, by using LOCAL varibles, which it translates into .

My view on trying to manage the stack yourself, is that if you do, you may as well as do it all, to keep things intack, which takes out using invoke, local, proc the rest of them. Cause otherwise its just not worth the effort to keep up with masm as what it is doing with ebp and esp.

Also with wsprintf, using invoke with it masm automacticly updates esp for you

invoke wsprintf ,esi,edi,eax,ebx,ecx

00401001 51 push ecx
00401002 53 push ebx
00401003 50 push eax
00401004 57 push edi
00401005 56 push esi
00401006 E83D090000 call fn_00401948
0040100B 83C418 add esp,14h

The way you could do you proc using LOCAL could be like this:

format BYTE "Clock Time: %.2d:%.2d:%.2d",0

WinMain PROC

...initialize and do stuff

invoke wsprintf, offset buffer, addr format, Hours, Minutes, Seconds
Posted on 2001-12-09 03:24:11 by huh
Thanks huh, I will keep that in mind for future coding. One of the main reasons I wanted to try to go with out local was to better understand how it actually works. And also, if for some reason I could not use local, I wanted to at least have some idea of how to go about with out it. Oh, I almost forgot. I was doing this in a marco, not a proc. Maybe I'm doing it wrong, but when I try to do hours:DWORD, it gives me an error. I think I ended up figuring it out after reading the chapters bitRAKE mentioned. Thanks again to all. :alright:
Posted on 2001-12-09 04:50:46 by AlexEiffel
AlexEiffel, locals in macros are just number or text equates - they don't have a size. Also keep in mind that they exist only during assemble-time -- nothing is created in the program for them. Whereas locals within a proc are a run-time construct effecting stack space, and the offsets to that data on the stack.
Posted on 2001-12-09 12:11:22 by bitRAKE
Hi bitRAKE. That is why I was doing the stack adjustment manually. I needed some temporary variables and since local in a macro is like a text equate I thought I had to manipulate the stack directly. I guess I could have put them in a proc, but I only use the macro once per frame so I decided I could save a call and a return by using a macro.
Posted on 2001-12-09 23:31:23 by AlexEiffel