AICollection Help

Arm64 Calling convention

The Arm64 calling convention is a set of rules that dictate how functions receive parameters and return values, how the stack is managed, and how registers are used. This ensures that code generated by different compilers can interoperate.

Key Points of the Arm64 Calling Convention

  1. Registers:

    • General-purpose registers: x0 to x30.

    • Stack pointer: sp.

    • Link register: x30 (also known as lr).

    • Frame pointer: x29 (also known as fp).

  2. Parameter Passing:

    • The first eight integer or pointer arguments are passed in registers x0 to x7.

    • Additional arguments are passed on the stack.

    • Floating-point arguments are passed in registers v0 to v7.

  3. Return Values:

    • The primary return value is placed in x0.

    • If a function returns a structure or a union, the address of the return value is passed in x8.

  4. Stack Management:

    • The stack must be 16-byte aligned at the point of a function call.

    • The caller is responsible for allocating space for the return address and any arguments that do not fit in registers.

  5. Callee-saved Registers:

    • Registers x19 to x28, x29 (fp), and x30 (lr) must be preserved by the callee.

    • The callee must save and restore these registers if it uses them.

Example

Here is an example of a simple function in Arm64 assembly that adds two integers:

.global add add: add x0, x0, x1 // x0 = x0 + x1 ret // return

Explanation (1)

  • The function add takes two integer arguments in registers x0 and x1.

  • It adds the values in x0 and x1, storing the result in x0.

  • The ret instruction returns to the caller, with the result in x0.

Example with Stack Usage

Here is an example of a function that uses the stack to store local variables:

.global sum_array sum_array: stp x29, x30, [sp, -16]! // Save frame pointer and link register mov x29, sp // Set frame pointer sub sp, sp, #16 // Allocate space for local variables mov x2, #0 // Initialize sum to 0 mov x3, #0 // Initialize index to 0 loop: ldr w4, [x0, x3, lsl #2] // Load array element add x2, x2, x4 // Add to sum add x3, x3, #1 // Increment index cmp x3, x1 // Compare index with array length b.lt loop // If index < length, repeat loop add sp, sp, #16 // Deallocate local variables ldp x29, x30, [sp], 16 // Restore frame pointer and link register mov x0, x2 // Move sum to return register ret // Return

Explanation (2)

  • The function sum_array takes two arguments: a pointer to an array in x0 and the array length in x1.

  • It saves the frame pointer (x29) and link register (x30) on the stack.

  • It sets up the frame pointer and allocates space for local variables.

  • It initializes the sum (x2) and index (x3) to 0.

  • It enters a loop to iterate over the array, loading each element, adding it to the sum, and incrementing the index.

  • After the loop, it deallocates the local variables and restores the frame pointer and link register.

  • It moves the sum to the return register (x0) and returns.

These examples illustrate the basic principles of the Arm64 calling convention, including register usage, parameter passing, and stack management.

Last modified: 14 December 2024