The answers of CesarB and Pavel provided quotes from AAPCS, but open issues remain. Does the callee save r9? What about r12? What about r14? Furthermore, the answers were very general, and not specific to the arm-eabi toolchain as requested. Here's a practical approach to find out which register are callee-saved and which are not.
The following C code contain an inline assembly block, that claims to modify registers r0-r12 and r14. The compiler will generate the code to save the registers required by the ABI.
void foo() {
asm volatile ( "nop" : : : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r14");
}
Use the command line arm-eabi-gcc-4.7 -O2 -S -o - foo.c
and add the switches for your platform (such as -mcpu=arm7tdmi
for example).
The command will print the generated assembly code on STDOUT. It may look something like this:
foo:
stmfd sp!, {r4, r5, r6, r7, r8, r9, sl, fp, lr}
nop
ldmfd sp!, {r4, r5, r6, r7, r8, r9, sl, fp, lr}
bx lr
Note, that the compiler generated code saves and restores r4-r11. The compiler does not save r0-r3, r12. That it restores r14 (alias lr) is purely accidental as I know from experience that the exit code may also load the saved lr into r0 and then do a "bx r0" instead of "bx lr". Either by adding the -mcpu=arm7tdmi -mno-thumb-interwork
or by using -mcpu=cortex-m4 -mthumb
we obtain slightly different assembly code that looks like this:
foo:
stmfd sp!, {r4, r5, r6, r7, r8, r9, sl, fp, lr}
nop
ldmfd sp!, {r4, r5, r6, r7, r8, r9, sl, fp, pc}
Again, r4-r11 are saved and restored. But r14 (alias lr) is not restored.
To summarize:
- r0-r3 are not callee-saved
- r4-r11 are callee-saved
- r12 (alias ip) is not callee-saved
- r13 (alias sp) is callee-saved
- r14 (alias lr) is not callee-saved
- r15 (alias pc) is the program counter and is set to the value of lr prior to the function call
This holds at least for arm-eabi-gcc's default's. There are command line switches (in particular the -mabi switch) that may influence the results.