System Practice Learning ARMv8 Assembly – Course 3

Course 3: Stage 2 – Core Instructions and Programming

Topic:Function Calls and Stack Operations, ARMv8 Calling Conventions, Bare-Metal Programming Practice

3.1 Basics of Function Calls

Core Concepts

  1. BL Instruction

  • <span>BL label</span>:Jump to<span>label</span> to execute, while saving the return address (the address of the next instruction) to<span>LR</span> (X30).

  • After the function call, return using<span>RET</span> (<span>RET</span> is equivalent to<span>MOV PC, LR</span>).

  • Calling Convention

    • Parameter Passing:The first 8 parameters are passed through<span>X0-X7</span>, additional parameters are passed via the stack SP.

    • Return Value:Returned through<span>X0</span>.

    • Caller-Saved Registers<span>X19-X28</span> (must be saved and restored in the function).

    3.2 Detailed Stack Operations

    Stack Instructions

    • Stack Pointer (SP):ARMv8 requires SP to be 16-byte aligned, refer to the official manual.

    • Pushing and Popping

      // Push (save X0 and X1 to stack, SP automatically decrements)  
      stp x0, x1, [sp, #-16]!  // ! indicates update SP to SP-16  
      
      // Pop (restore X0 and X1, SP automatically increments)  
      ldp x0, x1, [sp], #16  

    Stack Frame

    When entering a function, save<span>FP</span> (X29) and<span>LR</span> (X30), build the stack frame:

    my_function:  
        stp x29, x30, [sp, #-16]!  // Save FP and LR  
        mov x29, sp                 // Set new FP to current SP  
        // Function body  
        ldp x29, x30, [sp], #16     // Restore FP and LR  
        ret  

    3.3 Practical Project: String Reversal Function

    Objective:Write a function<span>reverse_string</span> that reverses the input string and outputs it via UART.

    Code Example<span>reverse.s</span>):

    .equ UART0_BASE, 0x9000000  
    .equ UARTFR_TXFF, (1 &lt;&lt; 5)  
    
    .section .text  
    .global _start  
    _start:  
        ldr x0, =string          // Input string address  
        bl reverse_string        // Call reverse function  
        bl uart_print_string     // Call print function  
        b halt  
    
    //--- Reverse Function ---  
    reverse_string:  
        stp x29, x30, [sp, #-16]!  // Save FP and LR  
        mov x29, sp  
    
        // Calculate string length  
        mov x1, x0                 // x1 = string start address  
    1:  ldrb w2, [x1], #1         // Read character and increment address  
        cbnz w2, 1b               // Loop until 0 encountered  
        sub x1, x1, x0            // x1 = length + 1  
        sub x1, x1, #1            // x1 = actual length  
    
        // Reverse string (two-pointer method)  
        add x2, x0, x1            // x2 = end address  
        mov x3, x0                // x3 = start address  
    2:  cmp x3, x2  
        b.ge 3f                   // If start &gt;= end, finish  
        ldrb w4, [x3]             // Swap characters  
        ldrb w5, [x2]  
        strb w5, [x3], #1         // Write and increment start address  
        strb w4, [x2], #-1        // Write and decrement end address  
        b 2b  
    3:  
        ldp x29, x30, [sp], #16   // Restore FP and LR  
        ret  
    
    //--- UART Print Function ---  
    uart_print_string:  
        stp x29, x30, [sp, #-16]!  
        mov x29, sp  
        mov x1, x0                // x1 = string address  
    4:  ldrb w2, [x1], #1  
        cbz w2, 5f  
        bl uart_putc  
        b 4b  
    5:  
        ldp x29, x30, [sp], #16  
        ret  
    
    //--- UART Send Function (same as above) ---  
    uart_putc:  
        ldr x3, =UART0_BASE  
        ldr w4, [x3, #0x18]  
        tst w4, #(1 &lt;&lt; 5)  
        b.ne uart_putc  
        str w2, [x3, #0x0]  
        ret  
    
    halt:  
        b halt  
    
    .section .data  
    string:  
        .asciz "Hello, ARMv8!"  
    .align 12  
    stack_bottom:  
        .space 1024  
    stack_top:  

    Compilation and Execution

    aarch64-linux-gnu-as reverse.s -o reverse.o  
    aarch64-linux-gnu-ld -nostdlib -o reverse.elf reverse.o -Ttext=0x80000  
    qemu-system-aarch64 -M virt -cpu cortex-a53 -nographic -kernel reverse.elf

    Expected Output

    !8MvRA ,olleH  

    3.4 Hands-On Experiment

    1. Modify String Content:Change<span>string</span> to other text (e.g.,<span>ABCDE</span>), observe if the output is<span>EDCBA</span>.

    2. Debug Function Calls:Step through<span>reverse_string</span> in GDB, observe stack changes:

      qemu-system-aarch64 -M virt -cpu cortex-a53 -nographic -kernel reverse.elf -S -s 
    3. Set breakpoints in GDB:

      (gdb) b reverse_string  
      (gdb) c  
    4. Extend Functionality:Modify the function to support dynamic length calculation (no hardcoding).

    Leave a Comment