ARM-Cortex-M架构:1、STM32函数参数传递

文章目录

  • 参数传递概览
  • 堆栈传递参数具体过程

参数传递概览

  • 在调用子函数时,ARM Cortex-M3 处理器可以使用 寄存器 和 堆栈 来传递参数。具体使用哪种方式取决于传递的参数数量和调用约定(calling convention)。

  • 参数传递方式
    ARM Cortex-M3 处理器使用 ARM EABI (Embedded Application Binary Interface) 标准来定义参数传递的约定。根据这个约定:

  • 1、寄存器传递:

    当函数调用时,前四个参数会优先使用寄存器 R0 到 R3 进行传递。这是因为使用寄存器传递参数比使用堆栈更快,访问寄存器的速度比访问内存(堆栈)要快。
    如果参数的数量小于或等于 4,那么这些参数都会通过 R0 到 R3 传递。
    如果参数的数量大于 4,则超过的参数将通过堆栈传递。

  • 2、堆栈传递:

    如果函数的参数超过 4 个,或者参数很大(如结构体或数组等),无法完全放入寄存器中,那么超过部分的参数会被压入堆栈。堆栈传递参数时,参数按照从右到左的顺序压入堆栈。也就是说,第一个参数(如果超出寄存器的部分)会先被压入堆栈。

堆栈传递参数具体过程

  • 寄存器传递参数很好立即,寄存器传递参数不好理解,具体过程如下。
  • 首先我们知道有堆栈指针SP。堆栈指针不像操作系统中每个任务有每个任务自己的堆栈,而是所有函数公有一个堆栈指针。
  • 我们看汇编语言中,通过堆栈传递参数给子函数的过程:
    main proc
        ; 将参数压入堆栈
        mov ax, 5          ; 第一个参数
        push ax
        mov ax, 3          ; 第二个参数
        push ax
        
        ; 调用 add 函数
        call add
        
        ; 清理堆栈(返回值从堆栈中弹出)
        add sp, 4          ; 每个参数占4个字节,这里加4
    
        ; 将结果存储在 result 中
        mov result, al     ; 假设 add 函数返回结果在 AL 寄存器中
        
        ; 退出程序
        mov ax, 4C00h
        int 21h
    
    main endp
    
    add proc
        ; 从堆栈中弹出参数
        pop ax             ; ax = 第二个参数
        pop bx             ; bx = 第一个参数
        
        ; 执行加法操作
        add ax, bx         ; ax = 第一个参数 + 第二个参数
        
        ; 将结果返回(假设返回值在 AL 寄存器中)
        mov al, ah         ; 结果存储在 AL 寄存器中
        
        ; 返回到调用者
        ret
    add endp
    
  • 通过上述过程,我们在直接用汇编语言写代码时,很自然地使用堆栈进行参数传递。
  • 那么在C语言中,如main函数,要调用下面的函数:
    void example_function(int a, int b, int c, int d, int e) {
        int local_var1;
        int local_var2;
        // 函数体
    }
    
  • 在调用函数前,我们首先要把当前main函数下,R0-R15寄存器信息保存到堆栈中。
  • 然后将前4个参数通过R0-R3寄存器进行传递,第5个参数e通过堆栈进行传递。
  • 此时,堆栈指针会向下直接调整而不是通过PUSH,来为局部变量和保存的寄存器状态分配空间。调整的总量是所有参数、保存寄存器和局部变量所需空间的总和。
  • 这里我们需要存储的参数e,4个字节;假设需要保存的寄存器有4个,16个字节;函数内局部变量2个,8个字节,因此堆栈需要调整的总量是28个字节。
  • 在子函数内,通过调整后的堆栈指针,加上偏移量来访问局部变量和我们传递的参数。
  • 执行完子函数,要返回时,需要将堆栈向上调整回去,然后回复main函数的寄存器内容。
  • 整个流程汇编语言如下:
; 函数调用前的代码
push {r4-r11, lr}     ; 保存寄存器和返回地址
sub sp, sp, #28       ; 为局部变量分配 28 字节的空间

; 将额外参数压入堆栈
str r5, [sp, #20]     ; 存储参数 e 到 SP + 20
str r6, [sp, #24]     ; 存储参数 f 到 SP + 24

; 子函数体中的代码
ldr r4, [sp, #20]     ; 从堆栈读取参数 e 到 r4
ldr r5, [sp, #24]     ; 从堆栈读取参数 f 到 r5

; 函数返回前的代码
add sp, sp, #28       ; 恢复堆栈指针
pop {r4-r11, lr}      ; 恢复main函数寄存器和返回地址

你可能感兴趣的:(嵌入式软件开发,arm开发,stm32,汇编,C语言)