There is no specific stack pointer register in ARM. By convention R13
is used as the stack pointer. There is no specific push and pop style stack pointer operands either.
Pushing and popping from the stack is carried out using the STM
(store to memory) and LDM
(load from memory) operands. These operands can be modified with the post fixes IA
and DB
. IA
is increment after, and DB
is decrement before.
So STMDB
means store to memory, decrementing before the store. I.e. pushing on to a full descending stack. The inverse of this would be LDMIA
which is popping from a full descending stack.
Alternatively you can have STMIA
and LDMDB
which means pushing and popping on to and off of an empty ascending stack.
FD
is the synonym for full descending and EA
is the synonym for empty ascending. So STMDB
and STMFD
are the same. LDMIA
, LDMFD
are the same. And so on...
So a full instruction would be for example...
STMDB R13!, {R0 - R3}
Which means push R0
, then R1
, then R2
and then R3
on to a full descending stack using R13
as the stack point. The address being written too is updated for each registered pushed. The !
means write back and means that R13
is updated with the final address so it can be used again.
BL
(branch with link) does NOT affect the stack or the stack pointer. It merely copies the current PC
(R15
) in to link (R14
) before the jump. A simple...
MOV R14, R15
... will return you back to the original address. However many may pop link straight in to PC at the end of a subroutine. For example...
.my_sub_routine
STMFD R13!, {R0, R1, R14}
// Do stuff
LDMFD R13!, {R0, R1, R15} // pop link straight in to PC meaning return.