News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

Windows Procedure; pushad and popad

Started by raleeper, August 09, 2011, 09:28:06 PM

Previous topic - Next topic

raleeper

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

qWord

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 ...
FPU in a trice: SmplMath
It's that simple!

jj2007

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

dedndave

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

jj2007

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

raleeper

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

qWord

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.
FPU in a trice: SmplMath
It's that simple!

dedndave

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

jj2007

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.

raleeper

qword:
I assume WinABI is an official list of programming conventions.  I don't think I have heard of that before.

raleeper

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.

raleeper

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.

Gunner

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
~Rob (Gunner)
- IE Zone Editor
- Gunners File Type Editor
http://www.gunnerinc.com

sinsi

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.
Light travels faster than sound, that's why some people seem bright until you hear them.

raleeper

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.