Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Push and Pop in arm

Tags:

assembly

arm

I don't really understand how stack commands or how stacks in general work.

Say if I had

PUSH R3
POP R3

Line 1 : Does this mean that the content of R3 would be put onto the top of the stack? Would the contents of the stack then change if R3 changed?

Line 2: On the second line, would the contents at the top of the stack be moved from the stack into R3 OR is the contents of R3 that was pushed onto the stack popped off the stack?

Also what does pop/push do when a register is surrounded in brackets like so

POP {LR}
like image 439
Nick Bishop Avatar asked Nov 23 '14 22:11

Nick Bishop


People also ask

What does Pop do in ARM?

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.

What does push and pop do in assembly?

The easiest and most common way to use the stack is with the dedicated "push" and "pop" instructions. "push" stores a constant or 64-bit register out onto the stack. The 64-bit registers are the ones like "rax" or "r8", not the 32-bit registers like "eax" or "r8d". "pop" retrieves the last value pushed from the stack.

What is push instruction in ARM?

Push registers onto a full descending stack.

What is BX in ARM?

The BX instruction causes a branch to the address contained in Rm and exchanges the instruction set, if required: BX Rm derives the target instruction set from bit[0] of Rm : If bit[0] of Rm is 0, the processor changes to, or remains in, ARM state.


2 Answers

The mentioned stack operations are only shortcuts for memory operations using sp in the address part. E.g.

PUSH {r3}
POP {r3}

are aliases for

str r3, [sp, #-4]!
ldr r3, [sp], #4

First operation says "store content of r3 into [sp - #4] and decrement sp by 4". Last one "load r3 from [sp] and increment sp by 4".

Instead of {r3} you can use any other register or register sets (e.g. {r1,r2,r3,lr}. Register sets are specified in a bitmask in the machine code so you can not influence the order in which the registers are stored/loaded.

like image 156
ensc Avatar answered Oct 21 '22 00:10

ensc


Minimal armv7 example

The best way to learn is to write minimal examples, run them on emulators, and observe what is going on all registers with GDB:

/* Save sp before push. */
mov r0, sp

/* Push. */
mov r1, #1
mov r2, #2
push {r1, r2}

/* Save sp after push. */
mov r1, sp

/* Restore. */
mov r3, #0
mov r4, #0
pop {r3, r4}
cmp r3, #1
bne fail
cmp r4, #2
bne fail

/* Check that stack pointer moved down by 8 bytes
 * (2 registers x 4 bytes each). */
sub r0, r1
cmp r0, #8
bne fail

Boilerplate to run the example on Ubuntu 18.04: https://github.com/cirosantilli/arm-assembly-cheat/blob/f8d78775bd052e9ead579a408c0a2a1651adb9f0/v7/push.S

The brackets are called "register lists" in the arm assembly notation. GNU GAS 2.26.1 does not accept push and pop instructions without the braces, even for single register pushes {} as in push r1.

Also note that:

  • according to the armv7 calling convention, the stack must be aligned by multiples of 8, so pushing 2, 4, ... registers at a time is way more common than just 1: ARM: Why do I need to push/pop two registers at function calls?
  • armv8 dropped push and pop, compilers often use stp and ldp instead. Example at: https://github.com/cirosantilli/arm-assembly-cheat/blob/f8d78775bd052e9ead579a408c0a2a1651adb9f0/v8/common_arch.h#L20