Hi, i am making a program that has numerous procs, each of this procs receives the parameters through registers, but i want to know if it's secure to push ESI,EDI,EBP and EBX at the beginning of the program to use them all along the program (with the benefit of not having to preserve them entering any function ), and before calling ExitProcess restoring them (cuz as far as i know, Windows uses them) ...

Actually my program's doing this and running perfectly, it uses various API's, but i want to know if there's an API that requires that registers to be like windows left them before entering the program..., that brings mi another question:

Wich is the state of the registers and/or flags when a new process is executed ?, i think windows manages itself of preserving the registers...
Posted on 2005-10-25 22:17:30 by Punky
Most API will work this way, but the enumeration API (that need a specified callback)  use ESI or EDI. EBX is also noted by Microsoft to take such a role in next OSes.
"EnumWindows", "FindFirstFile" and "FindNextFile" are examples of API that use ESI between calls.
If you modify ESI's value after FindFirsttFile and the next call to FindNextFile, you could have problems. Experiment with this on Win2k and WinXP to understand further.

Also, search the board for this issue - "register preservation" or "ebx esi edi", f0dder (a respected member here) gives full info about the current and future state of this problem.


Before calling ExitProcess, you can have EAX, EBX, ECX, EDX, ESI and EDI garbled. The OS won't need these registers' values anymore - the OS won't care about them anymore after process deletion.
Posted on 2005-10-25 23:17:40 by Ultrano

EnumWindows", "FindFirstFile" and "FindNextFile" are examples of API that use ESI between calls.
If you modify ESI's value after FindFirsttFile and the next call to FindNextFile, you could have problems. Experiment with this on Win2k and WinXP to understand further.

Hmmmm?!

That sounds very weird!
Posted on 2005-10-26 06:03:01 by f0dder
Hmm I guess I'm wrong. Anyway, since I myself doubted my statement - had blurry memory about this case, I tested such funcs again, they don't garble EBX, ESI and EDI.
Then I tried to remember where I had seen garbled EBX, ESI and EDI.

I found those registers garbled inside CALLBACK procs.  The interesting stuff is that if you modify the three registers there, your app either crashes, or behaves strangely. A modified ESI has the highest chance of crashing your app, while EBX-the lowest.
But outside the WndProc (a CALLBACK proc), EBX, ESI and EDI always have the same values:
ebx = 7FFDF000
esi = 00000004
edi = 00300036

So far, I haven't managed to make my testapp crash when I change these values _outside_  WndProc and the like.

In my style, I searched for a way to remove the necessity to preserve these registers in WndProc's. Can't be done in the messagepump, thus my conclusion is: preserve the 3 registers in every "CALLBACK" proc. Nothing new ^^' . But being able to modify the registers (without preserving them) outside WndProc, and not crashing/misbehaving, is also something nice.
Posted on 2005-10-26 08:05:15 by Ultrano
Ah and I saw I was right about EBX, ESI and EDI being used internally in such callbacks to hold data on the enumeration process. Test this code:

exa proc hwnd,extra1
print ebx
print esi
print edi
mov eax,1
ret
exa endp

main proc
invoke EnumWindows,exa,0
ret
main endp

See the obvious pattern ;) ? Change any of the two registers, and watch the fireworks.
Btw, I'm testing all this on Win2k, I don't have XP to test the code on.
Posted on 2005-10-26 08:22:40 by Ultrano
Ah phew, this is expected behaviour because of the intel ABI - as I've always said, register preservation is necessary in callbacks (and only there, really). For a second, I was afraid unexpected weirdness had been introduced :)

Posted on 2005-10-26 08:35:22 by f0dder
Punky,

You can usually only use EBP if you write a procedure without a stack frame as in a normal stack frame procedure, EBP holds the address of your procedure arguments and LOCAL variables. Without a stack frame you access ESP directly but you must know what you are doing writing procedure without a stack frame.

Over time I have never seen code written according to the windows convention fail where I have seen enough code that works on one OS version crash on another reasonably regularly yet this is fully avoidable by observing the convention properly.

In a stack frame procedure, if you modify any of EBX ESI and EDI, you push them at the start and pop them at the end of the procedure. In a procedure without a stack frame, you also push EBP if you use it and POP it back on exit from the procedure.

There is a reciprocal in that when you preserve EBX ESI and EDI, you can assume that any procedure you call does the same thing but can also modify EAX ECX and EDX so you cannot expect a called procedure to preserve any of these 3.
Posted on 2005-10-26 09:31:59 by hutch--
Ultrano, i dont understand why are you suprised that callbacks expect windows convention
to be used and consider this a problem.

32 bit Windows:
SCRATCH REGISTERS      : EAX, ECX, EDX, ST(0)-ST(7), XMM0-XMM7
CALLEE-SAVE REGISTERS  : EBX, ESI, EDI, EBP
STACK CLEANUP BY
CDECL              : CALLER
STDCALL            : FUNCTION
REGISTERS FOR RETURN  : EAX, EDX, ST(0)

++ ESP must be aligned at 4 at all times

register preservation is necessary in callbacks (and only there, really).

try modifying esp to non dword alignment then, before calling some api. ;)
Posted on 2005-10-26 12:57:05 by drizz

try modifying esp to non dword alignment then, before calling some api.

Heh, true :) - I only really considered the general-purpose registers...

btw, is everything a dword on 64bit machines? ;)
Posted on 2005-10-26 13:23:10 by f0dder
drizz, I started studying asm on win98se, made a 100,000+ line professional project where I didn't preserve these 3 regs, and that project worked _perfectly_ on win98se. But Win2k/XP customers started complaining about misbehaviour/crashes. No win32asm tute mentioned this problem/standard/requirement, and I didn't encounter it myself, so I kind of grew up without it. After I got a copy of win2k (my job required it...), I could see this newly-introduced problem ^^". Fortunately, it's an easily fixed problem - by just adding "uses ebx esi edi" on callback procs, which are usually very few in projects.

Lol modifying esp to non-dword is interesting. Reminds me of unaligned memory access from ARM cpus (the whole device crashes)
Posted on 2005-10-26 13:49:13 by Ultrano

btw, is everything a dword on 64bit machines? ;)

:) you don't have to rubb it on my nose  :)  Mister AMD64x2 4400+  :P

Ultrano, yes generally your procs can have any convention you like, but since you usually end up
calling some api....i prefer that all my procs also stick to the win convention... ;)
Posted on 2005-10-26 14:44:58 by drizz
I think the windows (or rather, intel) convention is pretty decent... the split of scratch/persistant registers works out well in most cases.
Posted on 2005-10-26 14:55:15 by f0dder
btw, is everything a dword on 64bit machines?


On AMD64 machines using XP64:-

  • Windows handles and some other data types are now qwords

  • Pointers that use RIP-relative addressing are fitted into a dword

  • Absolute pointers are qwords

  • Pointers sent by Windows are qwords

  • All parameters sent to APIs and received in callbacks are qwords

  • The stack pointer moves 8 bytes at a time on PUSH and POP instructions



For details see writing 64-bit programs.

Posted on 2005-10-27 12:32:13 by jorgon
thanks everybody, but i'm a little confused...

if
Ultrano: Before calling ExitProcess, you can have EAX, EBX, ECX, EDX, ESI and EDI garbled. The OS won't need these registers' values anymore - the OS won't care about them anymore after process deletion.


then that means that i don't have to preserve registers at the program start ?.

well, i know i can't use ebp with a stack frame, but i dont understand this:

Hutch: In a procedure without a stack frame, you also push EBP if you use it and POP it back on exit from the procedure.


why do i have to preserve EBP even if i don't use it ??? maybe of the parameters passed to WinMain and/or WndProc ??

i forgot to tell i don't have WinMain PROC in the program, and for local variables i prefer to use:


 local_var db SIZEOF WNDCLASSEX (?)

 mov ,CS_HREDRAW
 
    OR for multiple operations.

  mov eax,OFFSET local_var
  mov ,CS_HREDRAW
  mov ,SIZEOF WNDCLASSEX



Posted on 2005-10-27 21:09:29 by Punky
hmmmm,

> why do i have to preserve EBP even if i don't use it ???

You don't. usual rule is IF you need to CHANGE it PRESERVE it, if you DON'T, don't.

The Windows convention is very clear unless it is confused by many people. When interacting with the OS, ensure that EBX ESI EDI ESP and EBP have the SAME value when you return back to the OS.

In practice this means in a stack frame IF YOU USE EBX, preserve it and restore it, same with ESI and EDI.

With a proc that does NOT use a stack frame, ensure that EBP and ESP are the same value on return as theye were at start.

There are no short cuts, write your code according to the convention and it will be reliable, don't and it won't be.
Posted on 2005-10-27 23:30:37 by hutch--
The rule of thumb is that if you call a function (usually it's the w32api), do expect the value in eax, ecx, edx to be destroyed, while the values in edi, esi and ebx to be preserved. Similiarly, if windows call your function (callback functions), they expect the values in edi, esi and ebx to be preserved because they might storing data in it.

So, who said anything about needing to perserve edi, esi and ebx at the start of your program?

If you don't need to use ebp, and do not touch ebp, then there is no need to preserve it. I mean it is the same for the rest of the registers right? If you don't touch the values in them, there is no need to preserve them.

Btw, no one said you can't use ebp in function with stack frame. You can use it if you want you are doing, but beware since local variable and parameters are accessed relative to ebp.
Posted on 2005-10-27 23:33:47 by roticv
The rule is simply to keep the values of EBP, EBX, ESI and EDI plus the direction flag intact on function return. There is a common confusion with the expression "preserve a register", which to many means "to push and pop a register's value in the stack" and to others it means "to preserve a register's value".
Posted on 2005-10-28 14:03:02 by QvasiModo


local_var db SIZEOF WNDCLASSEX (?)

  mov ,CS_HREDRAW
 
    OR for multiple operations.

  mov eax,OFFSET local_var
  mov ,CS_HREDRAW
  mov ,SIZEOF WNDCLASSEX



...it is misleading to call that a "local variable" - those go on the stack.
Posted on 2005-10-29 02:22:38 by f0dder
Ok, to give a conclusion to this post i preserve esi,edi,ebp and ebx at the program start so i can use them all along the program (so do not have to worry about how using all gpr's) and restoring them at program end (but then Ultrano said Windows won't need the value in these registers anymore) but i don't know if that's true (like with the FindFirtstFile() thing).

One thing i noticed is if i mess with EBP on a PROC that has LOCAL vars my program exits or crashes. with that said i can assume that if i change EBP inside WndProc (it has LOCAL vars) (or a proc inside WndProc that doesn't have frame stack ) then the program will crash or exit.

Well, with ESI, EDI and EBX i don't have any problems, maybe i should forget about EBP or make my program doesn't use LOCAL vars, anyway, thanks everybody  :)
Posted on 2005-10-29 16:53:25 by Punky

Ok, to give a conclusion to this post i preserve esi,edi,ebp and ebx at the program start so i can use them all along the program (so do not have to worry about how using all gpr's) and restoring them at program end

There's no need to do this.

Your preserve EBX, ESI, EDI, EBP in callbacks - things like wndproc, dlgproc, enumeration callbacks etc. "preserve" doesn't mean "blindly push/pop", it means "make sure the registers contents haven't changed in the callback". Thus if you don't modify a register, you don't have to do anything.

Rather than doing push/pop yourself, you can add a USES list to your callback procs - like


wndProc proc uses ebx, hwnd:dword, msg:dword, wp:dword, lp:dword


The "flip side" of register preservation is that you can modify EAX, ECX, EDX all you want. This is ALSO true for windows and other code external to your app. Thus every time you call an API, you should assume that EAX, ECX, EDX are destroyed - even if they aren't on your particular windows version.

Stack has to be 4-aligned.

Anyway, drizz already summed it up: http://www.asmcommunity.net/board/index.php?topic=22249.msg167245#msg167245
Posted on 2005-10-29 17:41:12 by f0dder