I don?t know if this has been asked before. I made a little search and found nothing.

What where do you guys pass your parameters and which registers do you save in your 100% assembly coded projects ?

Some like to pass all the parameters in registers, some use the stack and others like to use a combination like fastcall.

Which registers do you save and where ? Who does the job of saving the trashed registers ? The caller or the callee ?

How big is the overhead of the callee saving every register it uses even when some of its callers never use them ?

Is there really a gain of speed if I crazily adopt the convention of passing everything through registers and let the caller save everything ? It surely depends on a lot of factors, but CAN it be worthy sometimes to do so ? In some cases is it common or worthy not to adopt a convention at all ?

I know it is safer to adopt some convetion like 'the caller saves everything but eax, ecx and edx'. I ask you guys all of this because I?ve recently started to port my Z80 Emulator Core from C to Assembly and I want it to be fast, but stilll "debuggable" :grin: . I don?t want to be pulling my hair off 3 weeks from now. But I want it to be at least faster than the C version, which is not slow.

What have all the years of experience taught you ?

PS I repeat. I refer to the assembly functions called by assembly code, insulated from other apis. e.g. inside an emulation loop.
Posted on 2003-12-19 03:55:53 by Waka
I use the stack and I tend to preserve only the register needed by the O.S.

Maybe sometimes I preserve other register but with specific functions.
:alright:
Posted on 2003-12-19 05:21:28 by Eternal Idol Birmingham
Originally posted by Waka

I know it is safer to adopt some convetion like 'the caller saves everything but eax, ecx and edx'. I ask you guys all of this because I?ve recently started to port my Z80 Emulator Core from C to Assembly and I want it to be fast, but stilll "debuggable" :grin: . I don?t want to be pulling my hair off 3 weeks from now. But I want it to be at least faster than the C version, which is not slow.


If you want the code to be maintainable, and you expect it to change over time, stay away from caller preservation. Caller preservation is great for a compiler, which can regenerate the save/restore sequence on each compile, it is not appropriate for hand-written code in most cases.

At some point in the future, if you find a "hot spot" in your code and determine that you can slightly improve the performance of a short routine by using caller preservation, then modify that one routine.

OTOH, if the routine is short enough that saving a couple of pushes and pops is going to make a difference in performance, it's usually even more effective to create a macro out of that routine and save the call/ret overhead, too.
Cheers,
Randy Hyde
Posted on 2003-12-19 10:57:26 by rhyde
Waka,
When in MSland, where the BILLionaire rules, do as the will of the Bill decrees. His Billness says you must not violate the big four (EBX,EBP,ESI,EDI). So when I write WIN32, which I do almost exclusively, my subroutines take responsibility for saving and restoring the big four, and the DF if I use it. Anything else except the SEG registers, which I never mess with, is up for grabs. If the calling program wants, for example ECX saved, it had better save it before calling one of my subroutines. Keep in mind PUSHes and POPs for a register take only one byte. A PUSH for a constant less than 255 takes two bytes. A PUSH for a large constant or memory content takes 5 bytes. So if you have several occurrences of the same parameters, it might pay to put that parameter into a register for PUSHing, then restore the register later. As in Bill's way, all my parameters go on the stack and the result returns in EAX. Ratch
Posted on 2003-12-19 11:59:51 by Ratch
It depends on the function.
Posted on 2003-12-19 12:39:36 by Vortex
EBX, ESI and EDI in WinMain and callbacks like DlgProc etc... Don't modify EBP. There are some procs that I must preserve other registers for program reasons (ie using an ecx counter in a loop to call a proc-proc preserves ecx). Use stdcall exclusively, when I don't need it the assembler spits out an error (GoAsm) and I just use a call/label. And ofcourse I break every one of these conventions as often as I possibly can because this is programming and every routine is unique and treated as a special case ;)
Posted on 2003-12-19 13:27:45 by donkey
it depends on BILLness
Posted on 2003-12-19 13:39:32 by evil__donkey
I try to remember to preserved all registers used in a function (not counting eax (and occasionally edx), else it'd be a problem with return vals ;)), with the exeption of "internall call only functions" (functions like some string operator that for instance uses ecx and e*i)
Posted on 2003-12-20 06:11:13 by scientica
In my opinion, if for example you're making a library, then use STDCALL & Win32 register preservation in all functions that you document, & intend to make visible by the lib user.

If you have a critical function, that's called in an important loop for example, & that's only for internal use (helper function), then I think you can pass parameters in registers (as DOS interrupts). But document it well for yourself, & be carefull ;) (or use MACROs).
Posted on 2003-12-22 05:34:05 by John Kiro
I tend to use STDCALL, and design my subroutines in a sensible way: making them large enough that the calling convention doesn't really matter. You can do all the micro-optimizations you want, fastcall, whatever - it's still suicide to be using ie something like a putpixel function.
Posted on 2003-12-22 06:59:27 by f0dder
I agree with Eternal Idol, I only preserve the registers that desperately need preserving in a given function. In fact I generally do it late, not in the procedure stack frame entry. This leads to much debugging and a very slightly faster and smaller exe, at the cost of some hair. Still, I have plenty of hair, and only so many cycles to go around :)
Posted on 2003-12-22 07:36:39 by Homer
If you are writing code for Windows, preserve the OS spec registers and then do whatever you like in your own code. API calls are usually STDCALL but "wsprintf" it C calling so it depends on whet you need. If you need a fixed number of parameters, use STDCALL, if you need a variable parameter count, use C.

Speed of you code will depend on how well you write it. Good C is hard to improve on, good assembler can't be improved on, its up to you to write stuff that is fast enough for what you want.

Regards,
http://www.asmcommunity.net/board/cryptmail.php?tauntspiders=in.your.face@nomail.for.you&id=2f46ed9f24413347f14439b64bdc03fd
Posted on 2003-12-22 09:04:03 by hutch--
I save to memory pointers and usually if in a subroutine I have subroutine push and pop the stack.
Posted on 2003-12-22 11:54:43 by mrgone