risc-v 有通用寄存器, 也有一些特殊的寄存器(csr)
下表方便查阅吧,一般都是用别名多一些

截屏2024-06-27 21.09.35.png

点评:因为是16字节对齐, 所有sp空间-16,不考虑这个情况, 用不了这么多

c 代码

#include <stdio.h>

void my_function(int a, int b, int c, int d, int e, int f, int g, int h) {
    printf("a=%d, b=%d, c=%d, d=%d, e=%d, f=%d, g=%d, h=%d\n", a, b, c, d, e, f, g, h);
}

int main() {
    my_function(1, 2, 3, 4, 5, 6, 7, 8);
    return 0;
}

编译:riscv64-elf-gcc -S main.c -o main.s

risc-v 代码

    .file    "main.c"
    .option nopic
    .text
    .align    1
    .globl    my_function
    .type    my_function, @function
my_function:
    addi    sp, sp, -16
    sd    ra, 8(sp)
    sd    s0, 0(sp)
    addi    s0, sp, 16
    # 参数传递
    mv    a0, a0
    mv    a1, a1
    mv    a2, a2
    mv    a3, a3
    mv    a4, a4
    mv    a5, a5
    mv    a6, a6
    mv    a7, a7
    # 函数体
    ...
    ld    ra, 8(sp)
    ld    s0, 0(sp)
    addi    sp, sp, 16
    ret
    .size    my_function, .-my_function
    .globl    main
    .type    main, @function
main:
    addi    sp, sp, -32
    sd    ra, 24(sp)
    sd    s0, 16(sp)
    addi    s0, sp, 32
    # 调用 my_function
    li    a0, 1
    li    a1, 2
    li    a2, 3
    li    a3, 4
    li    a4, 5
    li    a5, 6
    li    a6, 7
    li    a7, 8
    call    my_function
    # 函数体
    ...
    ld    ra, 24(sp)
    ld    s0, 16(sp)
    addi    sp, sp, 32
    li    a0, 0
    ret
    .size    main, .-main
    .ident    "GCC: (GNU) 10.2.0"
  1. 寄存器使用约定
    RISC-V 共有32个通用寄存器,每个寄存器都有特定的用途。以下是一些常用寄存器的约定:
    x0 (zero):恒为零。
    x1 (ra):返回地址寄存器。
    x2 (sp):堆栈指针寄存器。
    x3 (gp):全局指针寄存器。
    x4 (tp):线程指针寄存器。
    x5 到 x7 (t0到t2):临时寄存器,不需要在函数调用前保存。
    x8 (s0/fp) 和 x9 (s1)、x18-x27 (s2-s11)):保存寄存器,需要在函数调用前保存。
    x10 到 x17 (a0到a7):函数参数和返回值寄存器。
    x28 到 x31 (t3到t6):临时寄存器,不需要在函数调用前保存。
  2. 参数传递
    前8个整数参数通过寄存器 a0 到 a7 传递。
    超过8个参数时,通过栈传递。
  3. 返回值
    函数返回值通过寄存器 a0 和 a1 传递。如果返回值超过两个寄存器的大小,则通过栈传递。
  4. 栈布局
    栈在内存中向低地址方向增长。
    函数调用时,栈帧需要对齐到16字节边界。
    被调用函数负责保存调用者的 ra、s0 到 s11 等寄存器。

putao
8 声望3 粉丝

推动世界向前发展,改善民生。