views:

80

answers:

1

Hi geeks~

I am developing some functions in assembly language, at the beginning, my functions passing the parameters in the following 3 manners:

  • registers
  • global data in .data section
  • through stack

Now I found that the mix of the above 3 manners is making things complicated. And I always fall into the situation where I have to scratch my head to make sure whether certain register is polluted. So I decide to pass the parameters only through stack. And use the following function template as a lazy once-for-all solution:

  pushl %ebp
  movl %esp, %ebp
  pushal          <--- save all the registers, this is kind of a lazy solution
  subl xxx, %esp  <--- allocate space for local variables
  ....      
  popal           <--- restore all the registers
  movl %ebp, %esp
  popl %ebp
  (addl yyy, %esp)<--- if it is __stdcall convention, the callee will clear the stack
  ret

(xxx is the size of local variables, yyy is the size of paramters pushed by caller.)

The caller is responsible for push parameters and clear the stack (like the C call convention). Of course, if the number of parameters is fixed, I can make the callee to clear the stack (like the __stdcall convention on Windows).

I am hoping this template could relieve me from the confusions of registers usage. Could it achieve that? If it is low efficiency, is there some better approach? I'd like to hear your comment.

Many thanks.

Update 1

Hi again, my code has bugs, so I corrected it like this:

  pushl %ebp
  movl %esp, %ebp
  pushal          <--- save all the registers, this is kind of a lazy solution
  subl xxx, %esp  <--- allocate space for local variables
  ....    
  addl xxx, %esp  <--- reclaim the space for local variables
  popal           <--- restore all the registers
  movl %ebp, %esp
  popl %ebp
  ret yyy     <--- for __stdcall convention, the callee will clear the parameters pushed on stack by caller
+1  A: 

Usually the ABI for a particular platform will define a calling convention that states what to do with each register. A simple convention might be that any function you call can trash eax, ebx, and edx, but ecx, esi, and edi will be preserved by the called function.

This way you can have a tradeoff, of having simple function step on a few registers if they need to without having to save them, but more complex functions can use all the registers they want, as long as they save the preserved ones first.

Greg Hewgill
Thanks Greg. Your convention seems to be a compromised version of mine. My convention claims that any function can trash **all** registers.
smwikipedia
As you mentioned, that's not very efficient because then you *must* save and restore all of them all the time.
Greg Hewgill
Thanks Greg. Yes, that's quite not efficient. It takes more cycles and more stack space. I just consider it as a lazy but simple solution once-for-all. I will only use it in some complex functions so that I can focus more on the function logic. ;)
smwikipedia