Project 5.01 Section 5 ⚡ Embedded Relevance: Critical Prototypes AAPCS Stack Frames Calling Convention Registers R0-R3

5.01 Function Signatures, Header Prototypes & ARM Register Passing (R0–R3)

Executive Summary: Exploring function prototypes, definitions, and execution flow. We analyze the ARM Architecture Procedure Call Standard (AAPCS), demonstrating how the first 4 function arguments are passed in CPU registers (R0-R3) with zero memory latency, while additional arguments spill onto the stack.

💻 1. Annotated Source Code

#include <iostream>

using namespace std;

void printSomething();
void printMyName();

int main() {

	printSomething(); //call or invocation
	printMyName();
	return 0;
}

void printSomething() {
	cout << "Hey!  Look, I'm here!" << endl;
}

void printMyName() {
	cout << "My name is John Baugh!" << endl;
}

📐 2. Architecture & UML Class Model

📐 ARM AAPCS Register Calling Convention Model (R0-R3)
+ Public - Private # Protected
<<compilation-unit>> AAPCSCallingUnit Register Passing Engine
-R0 : uint32_t (Param 1 / Return Value)
-R1 : uint32_t (Param 2)
-R2 : uint32_t (Param 3)
-R3 : uint32_t (Param 4)
-R14_LR : uint32_t (Link Register - Return Addr)
+printHello() : void
+doWork() : void

📚 3. Core C++ Concepts Deep-Dive

1. Forward Declarations & Prototypes

A function prototype informs the compiler of a function's name, return type, and parameter types before its definition, allowing the compiler to perform type verification and code generation across translation units.

2. Function Call Overhead

A standard function call executes a branch with link (BL) instruction, saving the return address into the Link Register (LR) and pushing caller-saved registers onto the stack.

⚡ 4. Embedded Systems & Hardware Reality

1. The ARM AAPCS Calling Convention

Under the standard ARM 32-bit calling convention (AAPCS):

  • The first 4 integer/pointer arguments are passed directly in CPU hardware registers: R0, R1, R2, R3 (zero stack latency!).
  • Return values are passed back in R0 (or R0-R1 for 64-bit integers).
  • Arguments beyond the 4th are pushed onto the CPU stack, adding memory store and load instructions.

💡 Embedded Optimization Tip: 4-Parameter Rule

Design performance-critical functions to accept $\le 4$ parameters so all inputs reside entirely in CPU hardware registers.

💡 5. Production-Ready Embedded Refactoring

Register-friendly driver API design:

💡 Production-Ready Refactor
#include <cstdint>

// Fits perfectly in R0, R1, R2 (Zero stack memory traffic)
void configureTimer(uint8_t timer_id, uint32_t prescaler, uint32_t auto_reload) noexcept {
    // Direct MMIO writes using hardware registers...
}

📝 Knowledge Verification Quiz

Test your understanding of the C++ concepts and embedded microcontroller trade-offs covered in this guide. Click any option for instant feedback.

Q1. Under the ARM AAPCS calling convention, which CPU registers hold the first 4 integer arguments?
A R0, R1, R2, and R3
B R4, R5, R6, and R7
C Stack Pointer (SP) and Link Register (LR)
D Program Counter (PC) and Status Register (PSR)
Detailed Explanation: AAPCS assigns registers R0 through R3 for passing the first four 32-bit arguments, executing function calls with zero stack memory overhead.
Q2. What happens when a function accepts 6 integer parameters on an ARM Cortex-M processor?
A The first 4 are passed in R0-R3, and the remaining 2 are pushed onto the stack frame
B All 6 parameters are rejected by the compiler
C Parameters 5 and 6 are passed in floating point registers
D The CPU enters sleep mode
Detailed Explanation: Arguments exceeding the four register slots spill onto the stack, requiring extra STR (store) and LDR (load) memory operations.
Q3. Which CPU register stores the return address during a standard function call on ARM Cortex-M?
A Link Register (LR / R14)
B Stack Pointer (SP / R13)
C Program Counter (PC / R15)
D Frame Pointer (R11)
Detailed Explanation: The BL (Branch with Link) instruction automatically loads the return address into the Link Register (LR / R14).
Q4. Why are forward declarations (prototypes) placed in .h header files in C++?
A To allow multiple .cpp translation units to call functions with compile-time type verification without duplicating function bodies
B To reduce the clock frequency of the processor
C To compress function code in flash
D To enable dynamic casting
Detailed Explanation: Header prototypes let other source files verify parameter types and return types during compilation before the linker connects definitions.