We will now return to the problem we left at – why was the exit value 97 instead of 5? We now know that volatile registers don't retain their values across function calls, and when we called getchar(), the contents of r3 got overwritten. How do we overcome this? We can store the value of r3 in a non-volatile register before calling getchar. By convention, while using non-volatile registers, we use them in the order r31, r30 ... r13. Also, as we use each non-volatile register, we need to save them in the stack, and restore them when we return from the function. Hence the above program should be modified as follow:
- .set r0, 0
- .set r1, 1
- .set r3, 3
- .set r31, 31
-
- .extern .getchar # Tell the assembler that .getchar is an external symbol
-
- .csect
- .globl .main
- .main:
- # Function prolog begins
- mflr r0 # Get the link register in r0
- stw r31, -4(r1) # Save caller's r31
- stw r0, 8(r1) # Save the link register
- stwu r1, -64(r1) # Store the stack pointer, and update. Create a frame of 64 bytes.
- # Function prolog ends
-
- li r3, 5
- mr r31, r3 # Copy contents of r3 into r31 for retention
- bl .getchar
- ori r0, r0, 0 # No-op, required by compiler/loader after a branch to an external function
- mr r3, r31 # Copy contents of r31 back to r3
-
- # Function epilog begins
- addi r1, r1, 64 # Restore the stack pointer
- lwz r31, -4(r1) # Restore caller's r31
- lwz r0, 8(r1) # Read the saved link register
- mtlr r0
- # Function epilog ends
-
- blr
In line 13, we save the caller's (in this case __start's) r31 in the stack frame. In line 19, we copy the contents of r3 into r31, so that when getchar returns, although r3 would have been overwritten, we would still retain the value in r31. After getchar returns, we copy the contents of r31 to r3. We restore the caller's r31 in line 26 before returning from this function.