armstackcortex-mthumb

Ordering of registers in PUSH and POP brackets


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...".


Solution

  • 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 .