I have cleaned out junk and simplified my main windows procedure.
There remains one point on which I am undecided: pushad at the start and popad just before returning.
The program seems to work fine without them and I can't remember why I put them in in the first place.
My question is, Should I put them back or take them out and hope no problems arise later?
Thanks, ral
If you modify ebx, edi or esi, you must preserve it (WinABI).
Other question: did you think, that you will understand your code in 2 or 3 years?
My suggestion is to use MASM's highlevel construction for WinAPI stuff, because optimization at this point is (IMO) worthless ...
Pushad/popad is a cute instruction if you don't use it inside a loop that is being called a Million times (rare case :bg)
However, remember that you often must return a value in eax. If that value is in a register, you need to move it into the stack:
include \masm32\include\masm32rt.inc
.code
start: mov eax, 12345
pushad
mov edx, 11111
mov dword ptr [esp+32-4], edx
popad
MsgBox 0, str$(eax), "returned in eax:", MB_OK
exit
end start
my only problem with POPAD is that it sets ESP to the value previous to the PUSHAD
although, it can be modified as it exists on the stack
if i were designing the microcode, i might have left ESP out of the POPAD "function"
these instructions can be sluggish
i use PUSHAD to create stack space more than i do to preserve registers :P
with a single-byte instruction, you create 32 bytes of space
i don't use it in places where the code is executed repeatedly
Quote from: dedndave on August 09, 2011, 10:12:38 PM
with a single-byte instruction, you create 32 bytes of space
i don't use it in places where the code is executed repeatedly
I would not use it in a time-critical innermost loop, and I would not use it if I was worried about portability to 64-bit code (I'm not :bg)
The problem is really often that you need some acrobacy to return a value:
mov [esp+32-4], edx
popad
Works fine but costs 4 bytes - the same as
uses esi edi ebx (2*3=2+4). You can save one byte if you use it in a proc with standard frame and less than 128 bytes of local variables:
include \masm32\include\masm32rt.inc
MyTest PROTO :DWORD, :DWORD, :DWORD, :DWORD
.code
start: invoke MyTest, 1, 2, 3, 4
print str$(eax), " returned in eax", 13, 10
exit
MyTest proc hwnd:DWORD, uMsg:DWORD, wParam:DWORD, lParam:DWORD
LOCAL rc:RECT, MyLocVar:DWORD
LOCAL LastVar[20]:BYTE ; whatever - dword, byte, a structure...
mov eax, 33333
pushad
mov eax, offset code_end
sub eax, offset code_start
print str$(eax), " bytes", 13, 10
mov edx, 11111
code_start:
if 1
mov dword ptr LastVar[-4], edx ; 3 bytes
else
mov dword ptr [esp+32-4], edx ; 4 bytes
endif
code_end:
popad
ret
MyTest endp
end start
Quote from: qWord on August 09, 2011, 09:34:33 PM
If you modify ebx, edi or esi, you must preserve it (WinABI).
I tried setting ebx=esi=edi=0 (also all 3 to = -1) just before exiting and it didn't seem to matter. But you remind me of a convention - I expect windows to return these registers unchanged and it ought to be able to expect the same. So I am going to keep the pushad and popad(s).
QuoteOther question: did you think, that you will understand your code in 2 or 3 years?
Certainly not, since I will then still be adding new stuff.
QuoteMy suggestion is to use MASM's highlevel construction for WinAPI stuff, because optimization at this point is (IMO) worthless ...
You are probably right. Also, I am coming to see the value of making my code more intelligible to others.
Thanks, ral
Quote from: raleeper on August 09, 2011, 10:54:50 PMI tried setting ebx=esi=edi=0 (also all 3 to = -1) just before exiting and it didn't seem to matter.
Your windows version seems to check, if your procedure breaks with the WinABI (this is a bug!) - previous and/or future versions may kick your program.
As said, you must only preserve edi,esi and ebx if modified by your code.
you can use EBX, ESI, EDI, and EBP as you like without preserving them in places where the return caller is not the OS
for example, in the MAIN program, you don't have to preserve them
if you have a routine that is called only from the MAIN program, you do not have to preserve them
if you use a function in WndProc, you have to preserve them
i see many programmers handle it this way.....
WndProc PROC uses ebx esi edi hWnd:HWND,uMsg:UINT,wParam:WPARAM,lParam:LPARAM
now, as long as they leave EBP alone and return the right value in EAX, they can do whatever they like
this may not be the best practice, however
if you write a function that you want to use in another program in a call-back situation, it is best to preserve all but EAX, ECX, and EDX
Quote from: raleeper on August 09, 2011, 10:54:50 PM
You are probably right. Also, I am coming to see the value of making my code more intelligible to others.
I peeked into your source, and yes it was kind of hard to understand. But don't take that personally, please. I lost two hours today chasing a bug in a source - not assembler - that I wrote about two years ago, and which I thought was self-explanatory. No, it wasn't.
Contrary to my friend Dave I believe that the high level instructions - .if, .Repeat, etc - are extremely helpful in making code more understandable
to myself, especially when coming back some months later. And they are very, very rarely less efficient than hand-coded assembler, especially if you also look at .if .Zero?, .if Sign? etc.
qword:
I assume WinABI is an official list of programming conventions. I don't think I have heard of that before.
Quote from: dedndave on August 09, 2011, 11:06:15 PM
you can use EBX, ESI, EDI, and EBP as you like without preserving them in places where the return caller is not the OS
for example, in the MAIN program, you don't have to preserve them
if you have a routine that is called only from the MAIN program, you do not have to preserve them
if you use a function in WndProc, you have to preserve them
i see many programmers handle it this way.....
WndProc PROC uses ebx esi edi hWnd:HWND,uMsg:UINT,wParam:WPARAM,lParam:LPARAM
now, as long as they leave EBP alone and return the right value in EAX, they can do whatever they like
this may not be the best practice, however
if you write a function that you want to use in another program in a call-back situation, it is best to preserve all but EAX, ECX, and EDX
I know this applies only to routines that will/might be called by the OS.
I am quite happy with pushad and popad because as compared with alternatives they are simple and easily intelligible, and the extra time (if any) is negligible.
Quote from: jj2007 on August 09, 2011, 11:13:03 PM
Quote from: raleeper on August 09, 2011, 10:54:50 PM
You are probably right. Also, I am coming to see the value of making my code more intelligible to others.
I peeked into your source, and yes it was kind of hard to understand. But don't take that personally, please. I lost two hours today chasing a bug in a source - not assembler - that I wrote about two years ago, and which I thought was self-explanatory. No, it wasn't.
Contrary to my friend Dave I believe that the high level instructions - .if, .Repeat, etc - are extremely helpful in making code more understandable to myself, especially when coming back some months later. And they are very, very rarely less efficient than hand-coded assembler, especially if you also look at .if .Zero?, .if Sign? etc.
Personally, I find the low level code far more easily understandable.
But I will work on the intelligibility.
Quote from: raleeper on August 10, 2011, 12:04:23 AM
qword:
I assume WinABI is an official list of programming conventions. I don't think I have heard of that before.
Should read up on it :bg http://en.wikipedia.org/wiki/Application_Binary_Interface
Quote from: dedndave on August 09, 2011, 10:12:38 PM
my only problem with POPAD is that it sets ESP to the value previous to the PUSHAD
although, it can be modified as it exists on the stack
if i were designing the microcode, i might have left ESP out of the POPAD "function"
According to Intel, POPAD skips ESP.
Quote from: Gunner on August 10, 2011, 12:24:38 AM
Quote from: raleeper on August 10, 2011, 12:04:23 AM
qword:
I assume WinABI is an official list of programming conventions. I don't think I have heard of that before.
Should read up on it :bg http://en.wikipedia.org/wiki/Application_Binary_Interface
Thanks for the reference. A quick google didn't come up with that.
The Intel ABI is the action, over time I have seen many foolish shortcuts that end up coming down around their ears with another Windows version. You can use PUSHAD / POPAD for the occasional debugging or testing purpose but for production code you should learn the Intel ABI and ensure your code is fully compliant.
thanks, sinsi
i had never noticed that in the quick-note references
good to know :U
i do use this little trick :P
mov edi,sizeof SomeStruct
pushad
;ESP = structure address with cbSize initialized
EDI is the last to be pushed :bg
you can, of course, use other registers to initialize up to 6 more of the first 8 structure members