ARM documentation says the following for PUSH and POP
PUSH stores registers on the stack, with the lowest numbered register using the lowest memory address and the highest numbered register using the highest memory address.
POP loads registers from the stack, with the lowest numbered register using the lowest memory address and the highest numbered register using the highest memory address.
And a tutorial I found says this
...the registers in the {} can be specified in any order, but the order in which they appear on the stack is fixed...
So according to the above explanations, the ordering of registers in one PUSH bracket doesn't matter. I.e. PUSH {R0,R1,R2}
, PUSH {R2,R1,R0}
, and PUSH {R1,R2,R0}
all would result in the some ordering in the stack because "...the lowest/highest numbered register (R0/R2) uses the lowest/highest (stack) memory address...".
Does that mean if a single PUSH instruction has multiple registers in
the bracket, the assembler automatically sorts the pushing actions
out in the object code, where PUSH R2
goes first into the stack to
take the highest address, followed by PUSH R1
and ended with PUSH R0
taking the lowest address?
So if I want to guarantee R2 get pushed last and popped first in a LIFO stack (i.e.
SP pointing R2 or for R2 to take the lowest stack address), I cannot
do so in one PUSH bracket statement but only separately with PUSH R0; PUSH R1; PUSH R2
?
You are close, you need to always get the TRM (technical reference manual for the core, cortex-m3, cortex-m0, etc) and the ARM (architectural reference manual for the architecture specified by that core armv6-m, armv7-m, armv8-m)
.thumb
push {r0,r1,r2}
push {r2,r1,r0}
push {r0}
push {r1}
push {r2}
Disassembly of section .text:
00000000 <.text>:
0: b407 push {r0, r1, r2}
2: b407 push {r0, r1, r2}
4: b401 push {r0}
6: b402 push {r1}
8: b404 push {r2}
from the ARM ARM you can see in the push instruction the lower 8 bits are a register list/mask. So r0 is bit 0, r1 is bit 1 and so on. So the 7 in b407 indicates the three registers r0,r1,r2. The logic operates on machine code not assembly language, the machine code goes from bit 7 to bit 0 if set then push that register. All the assembler does is create the machine code it doesn't create extra instructions or anything like that.
If you want these in a different order then you have to write them in separate instructions in the assembly language.
The registers are stored in sequence, the lowest-numbered register to the lowest memory address (start_address), through to the highest-numbered register to the highest memory address (end_address)
The start_address is the value of the SP minus 4 times the number of registers to be stored.
Subsequent addresses are formed by incrementing the previous address by four. One address is produced for each register that is specified in .
The end_address value is four less than the original value of SP. The SP register is decremented by four times the numbers of registers in .