0
0
ARM Architectureknowledge~10 mins

Subroutine call convention (AAPCS) in ARM Architecture - Step-by-Step Execution

Choose your learning style9 modes available
Concept Flow - Subroutine call convention (AAPCS)
Caller prepares arguments in registers R0-R3
Caller pushes extra arguments on stack if >4
Caller executes BL (branch with link) to subroutine
Subroutine saves LR (R14) if needed
Subroutine uses R0-R3 for parameters
Subroutine uses R4-R11 as callee-saved registers
Subroutine executes instructions
Subroutine places return value in R0
Subroutine restores saved registers and returns with BX LR
Caller resumes, uses return value from R0
Shows the step-by-step flow of how arguments are passed, subroutine is called, registers saved/restored, and return value passed back following AAPCS.
Execution Sample
ARM Architecture
MOV R0, #5
MOV R1, #10
BL add_two_numbers
; result in R0
Caller sets two arguments in R0 and R1, calls subroutine add_two_numbers, which returns sum in R0.
Analysis Table
StepActionRegisters/Stack StateNotes
1Caller sets R0=5, R1=10R0=5, R1=10First two arguments in registers
2Caller executes BL add_two_numbersLR=return_addressLink register stores return address
3Subroutine saves LR if neededStack: push LRPreserve return address if subroutine calls others
4Subroutine uses R0=5, R1=10 as parametersR0=5, R1=10Parameters ready for use
5Subroutine computes sum: R0=R0+R1R0=15Return value placed in R0
6Subroutine restores LR from stackStack: pop LRRestore return address
7Subroutine returns with BX LRPC=LRReturn to caller
8Caller resumes, reads result from R0R0=15Result available in R0
💡 Subroutine returns to caller with result in R0, completing the call.
State Tracker
RegisterStartAfter Step 1After Step 4After Step 5After Step 8
R0undefined551515
R1undefined10101010
LRundefinedreturn_addresssaved on stacksaved on stackreturn_address restored
Key Insights - 3 Insights
Why are only registers R0 to R3 used for passing arguments initially?
Because AAPCS defines that the first four arguments go into R0-R3 for efficiency; extra arguments go on the stack (see execution_table step 1 and 2).
What happens if the subroutine calls another subroutine? How is the return address preserved?
The subroutine saves the LR (link register) on the stack before calling another subroutine (step 3), then restores it before returning (step 6).
Where is the return value placed after the subroutine finishes?
The return value is placed in R0 register (step 5 and 8), so the caller can read it immediately after return.
Visual Quiz - 3 Questions
Test your understanding
Look at the execution_table at step 5, what is the value of R0?
A15
B5
C10
Dundefined
💡 Hint
Check the 'Registers/Stack State' column at step 5 in execution_table.
At which step does the subroutine save the return address (LR) on the stack?
AStep 2
BStep 6
CStep 3
DStep 7
💡 Hint
Look for 'push LR' in the 'Registers/Stack State' column in execution_table.
If the caller had 5 arguments instead of 2, where would the 5th argument be placed?
AIn R3 register
BOn the stack
CIn R4 register
DIn LR register
💡 Hint
Recall that only R0-R3 hold first 4 arguments; extras go on stack (see key_moments question 1).
Concept Snapshot
AAPCS subroutine call:
- First 4 args in R0-R3 registers
- Extra args pushed on stack
- Caller uses BL to call subroutine
- Subroutine saves LR if calls others
- Return value in R0
- Return with BX LR
- Callee-saved registers R4-R11 preserved by subroutine
Full Transcript
This visual execution trace shows the ARM AAPCS subroutine call convention. The caller places up to four arguments in registers R0 to R3. If there are more than four arguments, the extras are pushed onto the stack. The caller then calls the subroutine using the BL instruction, which saves the return address in the link register (LR). The subroutine saves LR on the stack if it calls other subroutines to preserve the return address. The subroutine uses R0-R3 to access parameters and places the return value in R0. Before returning, it restores LR from the stack and returns using BX LR. The caller then resumes execution and reads the result from R0. This convention ensures efficient parameter passing and return value handling while preserving necessary registers.