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

Restoring Resister Values

Note: This was originally posted on 17th March 2011 at http://forums.arm.com

Hi,
I am working with Cortex M3 and I wrote a program in which I am calling a C function that is implemented in Assembly language. Four parameters are passed to the function, which are assigned to the Registers R0-R3. After performing some calculations on R0-R3 in the subroutine implemented in assembly language, when I return back to the C function the values of the R0-R3 are not the same as at the function's entry point rather R0-R3 contain results of the calculations performed in the subroutines. How can I get the same values back as they were at the starting point of the function call?
Looking forward for some useful hint.
Thanks and Regards
Parents
  • Note: This was originally posted on 17th March 2011 at http://forums.arm.com

    Muahsan,

    Function callers and their callee functions have to agree on a procedure call standard. If you are using the AAPCS (http://infocenter.ar...0042D_aapcs.pdf), then, when a caller calls a callee, it is responsible for ensuring that (at least) r0-r3 and r12 contain nothing it cares about being trashed. A callee must ensure that if it modifies any other register, that it preserves and restores it before returning back to the caller. Typically and preservation is performed by pushing register content to the stack (via SP/R13).

    From a register preservation point of view, a completely over engineered function call example is (Note that this example fails to meet the AAPCS' SP alignment requirement):

    Caller:
        .....
        PUSH {r0-r3,r12,lr} ;// preserve r0-r3, r12 and return address
        BL   Callee
        POP  {r0-r3,r12,lr} ;// restore r0-r3, r12 and return address
        ...

    Callee:
        PUSH  {r4-r11,lr}  ;// preserve r4-r11 and return address
        ...
        POP   {r4-r11,pc} ;// restore r4-r11 and return back to Caller

    In reality, this is likely completely excessive (and in the example above, prohibits useful return of any values by the Callee) . In addition to defining the responsibility of register state retention, the AAPCS also defines how functions should return values. If our two functions had been defined in C as:

    int Caller (int a) { return Callee(a + 1); }

    int Callee (int B) { return b + 2; }

    Then we might produce equivalent assembly as:


    Caller:
       PUSH  {r4,lr}  ;// Preserve return address (r4 also pushed to maintain SP alignment)
       ADD   r0,r0,#1 ;// Operand "a" was passed in R0, and "Callee" expects "b" to arrive in R0.
       BL    Callee   ;// Call "Callee", expect result to be returned in R0.
       POP   {r4,pc}  ;// Return to whoever called "Caller" (also restore r4 to maintain SP alignment)

    Callee:
       ADD  r0,r0,#3  ;// "b" arrives in R0, result should be returned in R0
       BX   lr        ;// Haven't modified anything that needed preserving, so return to "Caller"

    As long as Callee does not need more than R0-R3 and R12 to perform its function, then there is no need for it to perform an register preservation.

    hth
    s.
Reply
  • Note: This was originally posted on 17th March 2011 at http://forums.arm.com

    Muahsan,

    Function callers and their callee functions have to agree on a procedure call standard. If you are using the AAPCS (http://infocenter.ar...0042D_aapcs.pdf), then, when a caller calls a callee, it is responsible for ensuring that (at least) r0-r3 and r12 contain nothing it cares about being trashed. A callee must ensure that if it modifies any other register, that it preserves and restores it before returning back to the caller. Typically and preservation is performed by pushing register content to the stack (via SP/R13).

    From a register preservation point of view, a completely over engineered function call example is (Note that this example fails to meet the AAPCS' SP alignment requirement):

    Caller:
        .....
        PUSH {r0-r3,r12,lr} ;// preserve r0-r3, r12 and return address
        BL   Callee
        POP  {r0-r3,r12,lr} ;// restore r0-r3, r12 and return address
        ...

    Callee:
        PUSH  {r4-r11,lr}  ;// preserve r4-r11 and return address
        ...
        POP   {r4-r11,pc} ;// restore r4-r11 and return back to Caller

    In reality, this is likely completely excessive (and in the example above, prohibits useful return of any values by the Callee) . In addition to defining the responsibility of register state retention, the AAPCS also defines how functions should return values. If our two functions had been defined in C as:

    int Caller (int a) { return Callee(a + 1); }

    int Callee (int B) { return b + 2; }

    Then we might produce equivalent assembly as:


    Caller:
       PUSH  {r4,lr}  ;// Preserve return address (r4 also pushed to maintain SP alignment)
       ADD   r0,r0,#1 ;// Operand "a" was passed in R0, and "Callee" expects "b" to arrive in R0.
       BL    Callee   ;// Call "Callee", expect result to be returned in R0.
       POP   {r4,pc}  ;// Return to whoever called "Caller" (also restore r4 to maintain SP alignment)

    Callee:
       ADD  r0,r0,#3  ;// "b" arrives in R0, result should be returned in R0
       BX   lr        ;// Haven't modified anything that needed preserving, so return to "Caller"

    As long as Callee does not need more than R0-R3 and R12 to perform its function, then there is no need for it to perform an register preservation.

    hth
    s.
Children
No data