SoC
  • Home
  • Arm
  • Arm Cortex M0/M0+
  • Arm Cortex M4
  • Arm Cortex M3
  • Contact
Reading: What is the ARM Calling Convention?
SUBSCRIBE
SoCSoC
Font ResizerAa
  • Home
  • Arm
  • Arm Cortex M0/M0+
  • Arm Cortex M4
Search
  • Home
  • Arm
  • Arm Cortex M0/M0+
  • Arm Cortex M4
Have an existing account? Sign In
Follow US
  • Looking for Something?
  • Privacy Policy
  • About Us
  • Sitemap
  • Contact Us
© S-O-C.ORG, All Rights Reserved.
Arm

What is the ARM Calling Convention?

Graham Kruk
Last updated: September 10, 2023 12:27 pm
Graham Kruk 9 Min Read
Share
SHARE

The ARM calling convention refers to the standard procedure used on ARM architectures for function calls between software modules. It defines the way arguments are passed to functions and the way return values are passed back. Understanding the ARM calling convention is important for writing compliant and interoperable code for ARM processors.

Contents
Function Argument PassingReturn ValuesCaller and Callee ResponsibilitiesStack MaintenanceParameter Passing MethodsHandling Large DataVarargs FunctionsInteroperabilityCaller Saved vs Callee Saved RegistersPreserving RegistersAlignmentPrivate InterfacesContext SwitchingRegister Usage OptimizationCompatibilityNon-Compliant CodeNested CallsDebuggingFunction PointersLeaf FunctionsReentrancyDynamic LinkingEmbedded SystemsOperating System InterfacesPerformance

Function Argument Passing

On ARM, the first 4 integer or pointer arguments are passed in registers R0-R3. Any remaining arguments are passed on the stack. Floating point and SIMD arguments are passed in S0-S15 and D0-D7 registers. The caller function is responsible for pushing arguments to the stack before the call instruction and popping them after the call returns.

For varargs functions, R0-R3 are used for the first 4 arguments as normal. Additional arguments are pushed onto the stack. The total number of arguments is passed to the callee in R12. Floating point varargs are passed in S0-S15 and D0-D7 as usual.

Return Values

Integer return values up to 64 bits are returned in R0. Larger integer values are returned in R0-R1. Floating point return values are returned in S0 for floats, D0 for doubles, and S0-S1 for long doubles.

For structure returns, the caller passes a pointer to the return structure in R0 and the callee populates the return value directly into the passed structure. This avoids copying the return structure.

Caller and Callee Responsibilities

The caller function is responsible for:

  • Pushing arguments to the stack if more than 4
  • Allocating stack space for any spill registers it needs to use
  • Making the call preserving link register LR
  • Cleaning up the stack after the call

The callee function is responsible for:

  • Preserving R4-R11 if needed
  • Allocating stack space for any spill registers it needs
  • Restoring R4-R11 before returning
  • Returning values in the correct registers
  • Ensuring the stack is aligned to 8 bytes on public interfaces

Stack Maintenance

The ARM EABI requires the stack to be 8-byte aligned on any public interface. This ensures efficient memory access. The caller is responsible for aligning the stack before a call. The callee must maintain 8 byte alignment on its own stack frame. Stack pointers should be restored before returning from a function call.

Parameter Passing Methods

Arguments can be passed to functions in ARM using different methods:

  • Registers – Up to 4 arguments passed in R0-R3.
  • Stack – Remaining arguments passed on the stack.
  • Registers + Stack – First arguments in R0-R3, remaining on stack.

Different data types like integers, floats, pointers, structures, etc. can be passed using these methods. The ARM calling convention standardized which registers and stack positions are used for each argument.

Handling Large Data

For large data structures that don’t fit in registers, a pointer is passed instead. The callee can then access the data directly through the pointer. For returning large values, a pointer to a return structure is passed in R0.

Varargs Functions

Varargs functions have a variable number of arguments. The total number of arguments is passed in R12. Varargs are still passed in registers R0-R3 first if there are 4 or fewer. Extra arguments are pushed onto the stack. Floating point varargs are passed in S and D registers.

Interoperability

Following the standard ARM calling convention enables object code from different compilers and languages to interoperate. Code compliant to the ARM EABI can easily be linked together. This is critical for reusable libraries and combining code from different modules.

Caller Saved vs Callee Saved Registers

Registers are designated as either caller-saved or callee-saved:

  • Caller-saved – R0-R3, R12. The caller must preserve these if needed.
  • Callee-saved – R4-R11, LR. The callee must preserve these if modified.

This convention determines which function is responsible for saving and restoring a register’s value during a call.

Preserving Registers

To preserve a register’s value across a function call, it can be pushed onto the stack in the function prologue and popped back in the epilogue. Alternatively, a callee can save registers in its own stack frame if needed.

Alignment

The ARM EABI requires 8-byte stack alignment at public interfaces. This enables efficient access to 8-byte data like doubles. Stack pointers must be realigned after pushing arguments.

Private Interfaces

The standard calling convention only applies to public interfaces. Private code doesn’t need to maintain stack alignment or use the standard register assignments. However, following the convention also for private code improves interoperability and compatibility.

Context Switching

During context switches, the kernel must save any registers modified by a process before switching to another process. This is done by pushing callee-saved registers to the process stack or storing them elsewhere.

Register Usage Optimization

Registers can be used more flexibly within a function body than at the interface:

  • Arguments in R0-R3 can be overwritten right after use
  • R4-R11 scratch registers are available for local variables
  • Unneeded FP arguments can be reused earlier

This optimization reduces unnecessary save/restore of registers internally.

Compatibility

Older ARM dialects had different conventions regarding register assignments and stack alignment. Code needs to be recompiled sometimes to conform to the newer EABI standard for compatibility.

Non-Compliant Code

Code that doesn’t follow the standard calling convention may still work correctly in some cases. But it can lead to crashes or undefined behavior when interfacing with other code. Strict compliance is needed for compatibility.

Nested Calls

With nested function calls, each caller must preserve LR to return to the right address. Callee-saved registers should only be modified in the outermost call. Stack parameters and spill slots must be readjusted on each level.

Debugging

When debugging code, understanding the calling convention is critical for setting breakpoints, examining stack frames, and tracing function arguments. The convention determines the inner workings of a function call in assembly.

Function Pointers

Function pointers must point to functions with the standard calling convention. Otherwise, a called function will crash or behave incorrectly when passed arguments in the wrong registers or stack positions.

Leaf Functions

A leaf function only calls other leaf functions, not public ones. This means callee-saved registers don’t need preservation. Parameters and return values still follow the standard convention.

Reentrancy

Reentrant functions can have multiple activations on the stack during recursion or reentrant calls. The stack pointers must be adjusted separately for each activation to access local variables.

Dynamic Linking

Dynamically linked code must adhere to the standard calling convention for compatibility. Position-independent code relies on standard register roles and stack usage to work correctly.

Embedded Systems

Embedded ARM processors often have custom calling conventions optimized for the target system. However, compliance with the EABI convention enables integration with standard compilers and libraries.

Operating System Interfaces

The OS kernel interface follows its own custom convention optimized for low-level operations. But OS services called from userspace applications typically follow the standard EABI convention.

Performance

Efficient register usage and optimized stack management provides maximum performance for ARM code. But improper handling of registers and stack according to convention can significantly degrade performance.

In summary, adhering to the standard ARM calling convention ensures efficient, portable, and interoperable code for ARM platforms. Though some low-level or system code may deviate, compliance allows seamless interfacing with high-level languages, compilers, libraries, and applications built on ARM.

Newsletter Form (#3)

More ARM insights right in your inbox

 


Share This Article
Facebook Twitter Email Copy Link Print
Previous Article What registers to save in the ARM C calling convention?
Next Article ARM Cortex M Cache
Leave a comment Leave a comment

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

2k Followers Like
3k Followers Follow
10.1k Followers Pin
- Sponsored-
Ad image

You Might Also Like

Soft Float vs Hardware Floating Point Tradeoffs on Microcontrollers

When designing a microcontroller system that requires floating point math,…

14 Min Read

What is watchdog in microcontroller?

A watchdog timer (WDT) is a hardware circuit that is…

8 Min Read

How fast is Cortex-A76?

The Cortex-A76 CPU core from ARM offers a significant performance…

16 Min Read

Software debuggers and configuring for CoreSight components (Arm Cortex-M)

Debugging software on Arm Cortex-M devices requires configuring the CoreSight…

20 Min Read
SoCSoC
  • Looking for Something?
  • Privacy Policy
  • About Us
  • Sitemap
  • Contact Us
Welcome Back!

Sign in to your account