This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Concept of Scratch and Preserved Registers

Hi,

I am confused in understanding the difference between scratch and preserved registers. I have read the development guide of IAR Embedded Workbench but the topic was written in such a way that I could not get the real sence of it.
Any help or if possible some example that can help me differenciating between the both will be regarded.

Thanks in advance
  • Note: This was originally posted on 5th April 2011 at http://forums.arm.com

    @ttfn thanks for your detailed reply. Actually what I am unable to understand is that we have two groups of registers r0-r3 and r4-r11. I know that r0-r3 can be used for passing parameters while the remaining cann't. I am passing 4 arguments to the function foo called by main as in your example. Inside function foo I am doing some calculations which involve r0-r6. after return I want to have the same values in all registers as they were before calling foo. Do I need to push r4-r6 on stack before calling foo and then pop them back after return to have the same register values or it will be done automatically as they are called preserved registers. I have seen in the stack window that r0-r3 are pushed to stack, when they are used as parameters.
    I hope you got my point.
  • Note: This was originally posted on 5th April 2011 at http://forums.arm.com


      r4-r11 - protected


    And r13, r14 too, of course. To the OP - AAPCS is what you need to google for.

    Note that the rules stated above are not  any sort of 'restrictions' imposed by ARM CPU, some people get confused by this.
    All registers in ARM (except for r14 (lr) and r15 (pc)) are mutually interchangeable ("equal in rights").
    But most compilers follow the AAPCS rules to avoid compatibility problems (otherwise, it would be  difficult to link together libraries produced with different compilers, for example).
  • Note: This was originally posted on 5th April 2011 at http://forums.arm.com


    @ttfn thanks for your detailed reply. Actually what I am unable to understand is that we have two groups of registers r0-r3 and r4-r11. I know that r0-r3 can be used for passing parameters while the remaining cann't. I am passing 4 arguments to the function foo called by main as in your example. Inside function foo I am doing some calculations which involve r0-r6. after return I want to have the same values in all registers as they were before calling foo. Do I need to push r4-r6 on stack before calling foo and then pop them back after return to have the same register values or it will be done automatically as they are called preserved registers. I have seen in the stack window that r0-r3 are pushed to stack, when they are used as parameters.
    I hope you got my point.


    Confusion, confusion...
    Question #1: are you programming in 'C' (or any other high level programming language)? In this case, you don't have to take care of any registers - the compiler is designed to do this all for you. You're supposed to use variables, not registers.

    Question #2: are you programming in 'C' but want to manipulate CPU registers directly. In this case - think twice. This is a very bad thing to do, very rarely necessary and it's a road to hell 
    unless you know exactly what you're doing.

    Question #3: are you using a mixture of C functions and assembly functions? This is where you have to read AAPCS and write
    your assembly code accordingly.


    Do I need to push r4-r6 on stack before calling foo and then pop them back after return to have


    The compiler must do this if the function foo() code _generated by the compiler_ happens to use these registers or the foo()
    function calls other functions which, in their turn, might use these registers.


    I have seen in the stack window that r0-r3 are pushed to stack, when they are used as parameters.


    The compiler should not be expected to save/restore r0-r3 (according to AAPCS), it might push it (temporary) if it  needs to
    but you should not rely on them being preserved. If foo() returns any value - it will be returned in r0 (or r0:r1 pair for 64 bit values).
  • Note: This was originally posted on 5th April 2011 at http://forums.arm.com

    I've not used IAR's tools, but I'm assuming it follows the AAPCS (Procedure Call Standard for the ARM Architecture).  The AAPCS can be summarized as:

      r0-r3    - parameter passing, and return value
      r4-r11 - protected
      r12  - scratch

    So what does this mean?  Well lets say you have some code like this:


    main
      ...
      BL   foo
      ...

    foo
      ...
      BX  lr


    Main() is the caller, and foo() is callee.  That is, main() is calling foo().  So the AAPCS rules say that main() must put the arguments to foo() in r0 to r3.  It can expect the return value of foo() in r0.  It can also assume that when foo() returns r4-r11 will have the same values as they did before the call.

    Foo() can assume its arguments are in r0-r3, and it knows it must put its return value in r0.  It also knows that it can corrupt r12, using it as a scratch register.  For r4-r11, foo() can use these registers - BUT ONLY IF IT RESTORES THE ORIGINAL VALUES BEFORE RETURNING.