Storing all registers without scratching any
-
19-06-2021 - |
Question
I am developing a program that will bootstrap another program, so as a result I need to preserve the registers being passed to my program so that i can restore them before jumping to the program that should have loaded. It's a bare metal system, no OS, no MMU (present, but unsed at the moment).
Here is my code, I would just like to know if it is correct or not since i don't have an arm board to test on and i have to submit this soon,
also is it true that pc relative stores can use only source registers lower registers (r0-r7), i thought this was only thumb problem of not having access to high registers in certain instructions due to limited instruction width.
reset: @ entry point, mapped in reset vector
/* Store registers for bootstrapping */
STR R0, [PC, #128]
STR R1, [PC, #128]
STR R2, [PC, #128]
STR R3, [PC, #128]
STR R4, [PC, #128]
STR R5, [PC, #128]
STR R6, [PC, #128]
STR R7, [PC, #128]
/* Following registers can't be used in pc relative load/store */
MOV R0, R8
STR R0, [PC, #128]
MOV R0, R9
STR R0, [PC, #128]
MOV R0, R10
STR R0, [PC, #128]
MOV R0, R11
STR R0, [PC, #128]
MOV R0, R12
STR R0, [PC, #128]
MOV R0, SP
STR R0, [PC, #128]
MOV R0, LR
STR R0, [PC, #128]
MRS R0, CPSR
STR R0, [PC, #128]
MRS R0, SPSR
STR R0, [PC, #128]
ISB SY
B clear_regs
saved_regs:
.rept 32
.word 0x00000000
.endr
.align
clear_regs:
MOV R0, #0
MOV R1, #0
MOV R2, #0
MOV R3, #0
MOV R4, #0
MOV R5, #0
MOV R6, #0
MOV R7, #0
MOV R8, #0
MOV R9, #0
MOV R10, #0
MOV R11, #0
MOV R12, #0
MOV SP, #0
MOV LR, #0
Solution
In ARM mode (vs Thumb mode) it's fine to use the high registers in a PC relative store. Your assembler will warn you if something like that is not allowed. You might also want to consider using the STM (Store Multiple) instruction which allows you to specify a list of registers rather than doing them individually.
You should probably let the assembler do the 'hard' work of calculating the PC offsets by using symbols instead of specifying the offsets by hand.
reset: @ entry point, mapped in reset vector
/* Store registers for bootstrapping */
STR R0, saved_regs
ADR R0, saved_regs + 4
STMIA r0!, {r1,r2,r3,r4,r5,r6,r7,r8,r9,r10,r11,r12,r13,r14,r15}
MRS R1, CPSR
MRS R2, SPSR
STMIA R0, {r1, r2}
ISB SY
B clear_regs
saved_regs:
.rept 32
.word 0x00000000
.endr