Can anyone point me to a link indicating what is not allowed in Win32 Assembly programming? For example, CLI and STI are not allowed...
Posted on 2003-04-25 01:33:06 by V Coder
V,

Its a pretty wide question but here are a few basics, stay away from any instruction that works directly on hardware at the application level. Get the swing of privelege levels and only use instructions that are available at that privelege level. Normal applications are written in what is called ring3 privilege level.

The register preservation rules are if you use them in a procedure, preserve EBX ESI & EDI (ESP and EBP if you are writing your own proc entry) while being able to freely modify EAX ECX & EDX and remember that another procedure can do the same thing.

Where you may be used to DOS level interrupts, in win32, look up the capacity in the windows API functions as interrupts cannot be used in win32. Very early versions of win95 allowed a few but later version don't allow any at all.

Regards,

hutch@movsd.com
Posted on 2003-04-25 03:20:34 by hutch--
Be sure to keep your stack 4byte aligned

Be sure to keep structures and other things dword aligned (otherwise you might have trouble with "some" APIs)

In a dialog procedure, be sure to return 0 if you don't handle the message

Register preservation (as hutch) stated in CALLBACKS. And remember that any function you call can trash the registers (except for the regs you have to preserve).

...
more to come, probably.
Posted on 2003-04-25 03:32:58 by f0dder
f0dder,

explain something to me, I have heard you say often that callbacks require register preservation outside the normal convention of EBX ESI EDI ESP EBP with EAX ECX & EDX being modifiable.

Where did you get this from as I have never seen it in win32 documentation where the normal convention has always been observed ?

I have yet to ever find a problem with observing the normal convention without ever giving any special attention to callback apart from the normal convention and the code runs on every windows version as documented.

Regards,

hutch@movsd.com
Posted on 2003-04-25 03:44:52 by hutch--
You have either misunderstood me, or not read my posts.

I'm saying callbacks require register preservation - not register preservation outside the usual.

What do I mean by this? That callbacks are the only place where you _have_ to do register preservation. Of course it's good practice to follow the register preservation rules in your own routines, but you don't have to, as long as you know what you're doing. Furthermore, this (obviously) also implies that you don't have to do register preservation around win32 api calls (but of course must realize that any routine can trash any trashable register).

I would suggest people to follow the standard calling conventions, register preservation, and argument returning rules in their own routines, since it makes things a lot easier. You only _have_ to do the register preservation in callbacks though.
Posted on 2003-04-25 03:49:59 by f0dder
Here is the grind and why I question this assertion that you have continued to make for so long.


WndProc proc hWin:DWORD,uMsg:DWORD,wParam:DWORD,lParam:DWORD


invoke DefWindowProc,hWin,uMsg,wParam,lParam

ret

WndProc endp

This is a standard Wndproc for a CreateWindowEx() function that IS a callback. As it is it runs on every Windows version without problem and as you can see, it does not touch EBX ESI or EDI so what is the point of doing the preservations if no register is modified ?

Are you suggesting that the internal Windows code for the callback must have the registers preserved ?

I will put it to you that the only convention that exists is IF you change the EBX ESI & EDI registers within your procedure, callback or not, you must preserve them but if you don't, there is no reason to preserve them.

What you need to provide is that the registers will be modified within a callback even if you don't write any code and I suggest to you that this just does not make sense as you can easily dump a Wndproc or any other callback procedure to see what is in it.

Regards,

hutch@movsd.com
Posted on 2003-04-25 04:37:03 by hutch--
Oh, you have misunderstood me. Guess I should clarify... when I say register preservation, I of course mean if you modify them. Not much point in "preserving" registers if you don't modify them, is there now? :-)


I will put it to you that the only convention that exists is IF you change the EBX ESI & EDI registers within your procedure, callback or not, you must preserve them but if you don't, there is no reason to preserve them.

And that's a nice convention. I follow it, and people in general should. Keeps you from scratching your head about weird bugs. It is however true that you only _have_ to follow this convention in callbacks - if you have some special needs, and DOCUMENT this :), of course you're free to make individual code blocks behave differently. It often brings more problems than performance gains though, but each to his own. This is assembly, where you're in total control, is it not? ;-)

That said, you _DO_ have to do register preservation in callbacks, and assume that any function (unless otherwise documented) will trash any registers apart from ebx,esi,edi. I've seen people not do this and get away with it, but often their code breaks on the next service pack.


What you need to provide is that the registers will be modified within a callback even if you don't write any code and I suggest to you that this just does not make sense as you can easily dump a Wndproc or any other callback procedure to see what is in it.

Well, you misunderstood me - of course only preserve if you're changing stuff. But isn't that what the word preserve means?

Hope that clears any misunderstandings :)
Posted on 2003-04-25 04:45:18 by f0dder
OK,

Thats fine but what makes a callback different from any other function you write. I suggest that the conditions are identical. The normal convention applies if its a callback or not and while I agree with you about people making mistakes with register preservation, it can be fixed exclusively by observing the convention in ANY procedure, not just a callback.

Regards,

hutch@movsd.com
Posted on 2003-04-25 04:58:56 by hutch--

Thats fine but what makes a callback different from any other function you write. I suggest that the conditions are identical.

Well, the difference is that callbacks have this register preservation convention, and you thus have to follow it. Otherwise we get the wonderful "random GPFs", programs that work on one windows version but not another, etc.

For your own code, you're free to choose whatever calling + preservation convention you feel like - but (again), sticking to the default calling convention is the sanest thing to do. For special needs, it would be okay internal pieces of code that are not exposed to the public, to use another convention - as long as you document this. One could also use a custom convention for a whole library if one wishes (as long as it's documented), but again I wouldn't advice anybody to do so.


The normal convention applies if its a callback or not and while I agree with you about people making mistakes with register preservation, it can be fixed exclusively by observing the convention in ANY procedure, not just a callback.

Exactly, I agree fully with you here.

The thing I'm saying is you don't _have_ to follow the common convention in your own routines, but you _should_.
Posted on 2003-04-25 05:07:53 by f0dder
I think you have missed something here, the reason why I pasted in the code for an empty WndProc was to make the point that unless you modify EBX ESI & EDI you don't have to preserve the registers as they don't get modified in the WndProc.

There is in fact no seperate convention about callbacks apart from the same one that applies to all coded procedures. Now you are correct that you can work within your own code without handling the convention as long as you don't touch any OS functions at all.

Now what I suggest to you is that the normal convention applies to a callback as well IF you use any of those registers but if you don't, it does not, just like any other procedure that you write.

Where I am disagreeing with you is the idea that a callback is any different to any other procedure when it comes to observing the register convention. The convention covers what you are suggesting where the special treatment of callbacks does not exist.

Regards,

hutch@movsd.com
Posted on 2003-04-25 06:09:30 by hutch--
Hummm U think you're the one who's missing something. Pay a little attention.


Guess I should clarify... when I say register preservation, I of course mean if you modify them. Not much point in "preserving" registers if you don't modify them, is there now? :-)

Ie, dont push/pop or add to "uses" if you don't modify them. I really didn't think I have to explicitly state "preserve the registers (if you modify them)", the (if you modify them) ought to be implicit.

No, there's no difference between the convention of callbacks and the rest of the win32 api - callbacks are just the place where most people screw up; they might have gotten it right for wndproc, without realizing that wndproc is just a callback and all callbacks require this. Thus, my "preserve regs in callbacks" statements. Guess I should have been more explicit there.

The "normal convention" is the win32 convention. And well, in general 32bit compiler convention. Thankfully, most people follow this, whether they write in HLLs or Assembly.

Again... you ought to follow the standard convention in your own functions, but again you don't have to.

A shame you always seem to misunderstand me, even when we agree about things.
Posted on 2003-04-25 06:46:31 by f0dder
Maybe a simple way of saying it would be: If code execution is going to cross into the realm of the operating system, then you should assume Windows is going to expect EDI ESI and EBX to be the values they were the last time it saw them.

A callback, since it's called by the OS, and returns to the OS, would need to preserve them if they are modified.

A normal user proc that calls an API would need to restore them before calling the API if it trashed them beforehand.

A user proc that calls another user proc does not necessarily need to preserve them, nor does the proc it called.
Posted on 2003-04-25 07:45:47 by iblis

A normal user proc that calls an API would need to restore them before calling the API if it trashed them beforehand.

humm, what exactly do you mean by this? Only thing to keep in mind when calling API is to keep direction flag clear, and that eax,ecx,edx may be trashed.
Posted on 2003-04-25 07:50:56 by f0dder
Yeah that one is a little iffy and I only put it there because some APIs I've encountered have shown to be a little screwy sometimes. One instance I can remember was when I was copying data to the clipboard using the clipboard APIs and I didn't preserve EBX before calling it. The data I was copying ended up on my local stack, overwriting it. It was driving me insane, and then once I restored EBX it was fine. To double check I took out the EBX preservation and it did it again. It was on 98.
Posted on 2003-04-25 08:21:07 by iblis
Sounds pretty amusing. I've had fun experiences with the clipboard too, especially monitoring it. Boom, BSOD on 9x sometimes.
Posted on 2003-04-25 08:24:22 by f0dder
f0dder,

I have picked you up for a reason, have a look at what you posted here.

========================
Register preservation (as hutch) stated in CALLBACKS. And remember that any function you call can trash the registers (except for the regs you have to preserve).
========================

Now in this matter you are simply wrong, there is only one register convention in 32 bit windows and that is the one that everyone and their dog already knows. What you are doing is imposing an extra condition that simply does not exist and thats why I have picked you up on it as you were attempting to correct advice that I gave a member who had just made a posting asking a question.

Callbacks are no different to any other procedure and all procedures that use any OS function at all (APIs etc ..) must observe this convention otherwise the operation can be unreliable. Now it is reasonable for you not to post mistakes as advice to members who are asking questions and while everyone has made them, this has been a persistent one that you have continued to make by advising other members in error over and over again.

The logic is that a callback is a subset of procedures and the convention functions on all procedures, not just a subclass of procedures in callbacks. Observe this convention and ALL of your procedures will be reliable including callback procedures.

Regards,

hutch@movsd.com
Posted on 2003-04-25 09:45:01 by hutch--
I think that V Coder (unfortunate choice of names) deserves more than a "Clash of The Titans", maybe start another register preservation thread and just leave it at Register preservation may be important especially when developing across NT and 9x platforms. I had some apps that ran fine in Win2K that crashed under 9x because of register preservation issues.
Posted on 2003-04-25 10:16:11 by donkey
Well, f0dder is right. When you write your program, you know what registers your subroutines will modify (of course) and you don't have to follow a convention, since no one else will call this code. We do not live in Hitler's Germany, and we are free to do our chores however we want internally. If we know that one of our subroutines doesn't modify eax, ecx or edx, then it's silly to save them (well, unless we're paid by the number of lines we write, of course );)
Posted on 2003-04-25 12:48:16 by Sephiroth3
Originally posted by hutch--
Callbacks are no different to any other procedure and all procedures that use any OS function at all (APIs etc ..) must observe this convention otherwise the operation can be unreliable.

It's the other way around: the APIs must preserve ebx/esi/edi/ebp *for you*. They don't care about the state of these registers when they're called.

Now it is reasonable for you not to post mistakes as advice to members who are asking questions and while everyone has made them, this has been a persistent one that you have continued to make by advising other members in error over and over again.

:confused: If there's one person that advices people to do the 'right thing', it's f0dder (preserve registers, don't use undocumented functions unless for fun, don't use hacks/bugs, etc. etc.)

It's easy to prove you may trash esi/edi/ebx in your own functions:
APIs preserve ebx/esi/edi/ebp so you can use them in code that calls them without them being trashed. So this is legal code:


mov ebx, 10
_beeps:
invoke MessageBeep, MB_OK
dec ebx
jnz _beeps


The code around the API call may freely use ebx/esi/edi/ebp, no matter what it is. You're free to use call/ret in this code too. Thus you may write functions that trash ebx/esi/... Windows really doesn't care whether your code that uses those registers is inside a function or not. So if you're saying you can't trash ebx inside a function you must disagree with the validity of the above code as well. The one exception is a callback function, for obvious reasons.

Actually convention is the wrong word for saving registers in callbacks. It's a requirement. A convention is usually something that is strongly advised (like naming conventions in java), but not required. So saving ebx/esi/edi/ebp *is* a convention in win32 programming, but only a *requirement* in callbacks.

Thomas
Posted on 2003-04-25 13:06:14 by Thomas
Thomas,

You have actually described the convention the wrong way around. Try and connect this much, when you write your OWN procedure, IF you use any of EBX ESI EDI ESP EBP you either preserve it or crash the application most of the time.

When your procedure calls any API function, you can automatically assume that the API function observes the Windows convention and EBX ESI EDI will NOT be changed when it returns. When you call an API function you CAN assume the EAX ECX EDX will be changed as the convention does not require that any procedure presrve them.

How does this effect a person who is writing an application ? Simple, if they are going to use any of the registers that require preservation they do so and if they are going to call API functions, they MUST protect EAX ECX EDX if they are being used in the procedure.

Now to address WHAT a callback is under Windows, it is the starting address of a procedure which depending and the type of callback that it is is designed specifically to receive a set number of parameters.

Now to make the point that callbacks are not driven by folklore but by the same convention as the rest of Windows, here is a normal WndProc in its code and disassembled form.



WndProc proc hWin :DWORD,
uMsg :DWORD,
wParam :DWORD,
lParam :DWORD

.if uMsg == WM_COMMAND

.elseif uMsg == WM_DESTROY
invoke PostQuitMessage,NULL
return 0

.endif

invoke DefWindowProc,hWin,uMsg,wParam,lParam

ret

WndProc endp


============================================


00401636 55 push ebp
00401637 8BEC mov ebp,esp
00401639 817D0C11010000 cmp dword ptr [ebp+0Ch],111h
00401640 7502 jnz loc_00401644
00401642 EB16 jmp loc_0040165A
00401644 loc_00401644:
00401644 837D0C02 cmp dword ptr [ebp+0Ch],2
00401648 7510 jnz loc_0040165A
0040164A 6A00 push 0
0040164C E803010000 call fn_00401754
00401651 B800000000 mov eax,0
00401656 C9 leave
00401657 C21000 ret 10h
0040165A loc_0040165A:
0040165A FF7514 push dword ptr [ebp+14h]
0040165D FF7510 push dword ptr [ebp+10h]
00401660 FF750C push dword ptr [ebp+0Ch]
00401663 FF7508 push dword ptr [ebp+8]
00401666 E8B3000000 call fn_0040171E
0040166B C9 leave
0040166C C21000 ret 10h

Now as you choose to try and correct me in the advice I have given to a member, explain to anyone here why EBX ESI EDI must be preserved when they are not used here. You will notice that ESP and EBP are preserved in the normal manner for MASM.

The simple fact is that EBX ESI EDI are NOT used in this standard system callback so unless your own code uses them, extra preservation is bad code design that serves no purpose.

I will put it to you that feeding new member folklore is incorrect, the convention for register preservation under Windows is well known and not subject to personal opinion.

While I support you writing code in any manner that you like, trying to inflict a mistake on other members looking for information is not consistent with the responsibilities you have here.

Regards,

hutch@movsd.com
Posted on 2003-04-25 22:07:45 by hutch--