3

Say I want to implement a function for summing the numbers in a given range:

int sumRange(int start, int end);

And this is the implementation I came up with: (AT&T asm syntax)

sumRange:
   cmp %edi, %esi
   jl return_zero #jump if start > end
   
   #Pre-Call:
   push %edi
   inc %edi
   # push %esi
   call sumRange
   
   #Post-Call:
   # pop %esi   
   pop %edi

   add %edi, %eax
   ret # return start + sumRange(start+1, end)

return_zero:
   xor %eax, %eax
   ret # return 0

Note that both %edi and %esi are caller-saved register. %edi changes between the frames of the different recursive levels of sumRange so it must be saved in the Pre-Call, but %esi is not changed in the recursive call - so the code will still work without saving that register.

The question is: does this code meet the System V convention?

I think that it does not:
The convention does not consider what registers the called function actually changes (as far as I have found).
Therefore we are required to assume all caller-saved registers might change after a function-call.

Also, even if we do not make use of %esi after the recursive call, I would expect %esi to have it's proper value for the entire scope of sumRange.

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
yosef
  • 124
  • 5
  • 3
    It's a recursive call to the same function so you know the implementation. Yo do not need to assume anythinig. Your function adheres to the ABI from the viewpoint of the top level external caller. For the recursive call, it does not matter (but may make maintaining the code more difficult if you later happen to change the implementation). – Jester May 28 '21 at 22:50
  • 1
    You *don't* need to save `end`, but not because it's not modified. You don't need to save it, because you pass it unmodified to the function you call, and **you don't use it beyond the recursive call**. Whether the called function modifies it or not doesn't matter, that variable is dead already. – EOF May 28 '21 at 22:54
  • @EOF I understand that it does not matter whether or not I save %esi in terms of code correctness, but I want to emphasize I'm exclusively asking about the convention. Would this mean that the convention treats recursive calls differently than regular function calls? – yosef May 28 '21 at 23:03
  • 2
    @yosef The convention is that you need to save caller-saved variables **that are still live after the call**. No more, no less. Whether the call is recursive or not does not matter for this. – EOF May 28 '21 at 23:08
  • 1
    From the point of view of compliance with the calling convention, all that matters is you preserve all the registers that are callee-saved (rbx, rbp, r12-r15). And you do - you never modify any of them at all. That is no different between recursive and non-recursive. How you manage the caller-saved registers is important for your function's correctness, but not for ABI compliance. – Nate Eldredge May 28 '21 at 23:11
  • 3
    Maybe the term "caller-saved" is confusing you? It does not mean that you absolutely *have* to save that register when making a function call - you only have to save it *if* you have a use for its value after the call returns. Some people prefer the term "call-clobbered" which simply states what happens to the register around a call - its value may be overwritten - rather than appearing to tell you what you should do about it. – Nate Eldredge May 28 '21 at 23:15
  • Related: https://stackoverflow.com/a/62719139/7509065 – Joseph Sible-Reinstate Monica May 29 '21 at 04:03

0 Answers0