Search code examples
cgccarmcalling-convention

Register usage in ARM assembly function which is called by a C function


The C function call convention for ARM says:

  • Caller will pass the first 4 parameters in r0-r3.
  • Caller will pass any extra parameters on stack.
  • Caller will get the return value from r0.

I am handcrafting an assembly function called by C. The prototype is equivalent to this:

void s(void);

Suppose a C function c() calls s().

Since s() has no parameter nor return value. I believe r0-r3 will not be touched by the compiler to generate the calling sequence for c() to call s().

Suppose s() will use r0-r12 to complete its function. It is also possible that c() will use those registers.

I am not sure if I have to explicitly save and restore all the registers touched in s(), say r0-r12. Such memory operation will cost some time.

Or at least I don't have to do that for r0-r3?


Solution

  • From Procedure Call Standard for the Arm Architecture, section 6.1.1 (page 19):

    A subroutine must preserve the contents of the registers r4-r8, r10, r11 and SP (and r9 in PCS variantsthat designate r9 as v6)

    So yes, since r0-r3 are scratch registers, you do not need to save those before using them in s(), but you have to save and restore any other register.

    Assuming that the compiler is compliant with the ARM ABI, then declaring s() like this:

    extern void s(void);
    

    should suffice, and the compiler should not emit code that relies on previous values of r0-r3 in the c() function after the call to s() (i.e. c() should save r0-r3 if needed before calling s() and restore them after), since that would break the ABI compliance.