PUSH and POP order in ARM
Asked Answered
U

3

5

I'm trying to understand the start and end of functions in ARM assembly:

PUSH {R0-R2, LR}
POP {R0-R2, PC}

Looking at this piece of code in IDA here's what I understood (Lets assume SP is 0x100):

PUSH R0 ; sp = 0xFC
PUSH R1 ; sp = 0xF8
PUSH R2 ; sp = 0xF4
PUSH LR ; sp = 0xF0
POP R0 ; sp = 0xF4
POP R1 ; sp = 0xF8
POP R2 ; sp = 0xFC
POP PC ; sp = 0x100

It seems like PC gets the value of R0, when it should get the value of LR.
Shouldn't PC get the value of LR?

Ulrick answered 4/11, 2017 at 10:31 Comment(0)
G
9

When you PUSH or POP a bunch of registers, they always go into memory in the same relative positions, regardless of direction. The lowest-numberd register is stored at and loaded from the lowest address. So in this example everything will go back to the original register, except LR->PC.

To put that another way, imagine the PUSH as if it was storing {LR,R2,R1,R0}.

See the User Guide / Instruction Set reference for your favourite Arm 32-bit processor series; LDM and STM.

Graaf answered 4/11, 2017 at 11:1 Comment(3)
So, lowest numbered register will be at the lowest address, but what about the POP? at what order will that happen?Ulrick
The POP will load them in ascending order of register numbers, to match up with the PUSH which stored them in descending order as it decremented SP. [Now I don't know what order the transfers actually happen on the bus, and usually it doesn't matter. They do the right thing.] Of course with the standard function-calling convention you don't normally need to save R0-R3.Graaf
So to sum things up, pop will pop into the lowest numbered register first and PC last, and push will push the highest numbered register first and LR first. Right?Ulrick
R
1

A POP instruction with PC in its register list is a branch instruction to the value being popped out of the stack. So for

POP {R0, PC} ~= MOV PC,R0 ; Except that R0 is on the stack

Radley answered 19/1, 2020 at 19:52 Comment(0)
E
0

I also had the same question. Seems like if you push a bunch of registers at the same time, e.g. PUSH {R1-R4}, the lowest-number register always goes to the lowest-number destination register when you do POP (e.g. POP {R2-R5} loads R1 to R2, R2 to R3, etc.) The order of the destination registers inside the curly brackets does not matter. (Even with POP {R2,R5,R3,R4} R1 still goes to R2, R2 to R3, etc.)

Elicia answered 15/2, 2024 at 3:48 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.