RV64函数调用流程分析

[RV64 程序调用标准]

1 RV64 函数调用实例

下图是介绍一个简单函数调用的示例,在该示例中简单介绍了栈的使用。
在这里插入图片描述

2 对应代码的分析

2.1 main函数及其对应的汇编程序

2.1.1 main的C代码实现

int main(void)
{
    
    
        long a = 1;                                                                             
        long b = 2;

        printf("The current function is %s a:%ld b:%ld\r\n", __func__, a, b); 

        test_fun_a(a, b, 0, 1); 

        a = a + b;
        b = a + b;

        return 0;
}

2.1.2 main函数对应汇编及其分析

  • 000000000000071e <main>:
  • 71e: 1101 addi sp,sp,-32为函数分配32字节的栈空间。
  • 720: ec06 sd ra,24(sp)将寄存器 ra 的值存储到当前sp + 24的栈位置。
  • 722: e822 sd s0,16(sp)将寄存器 s0(栈帧指针寄存器) 的值存储到sp+ 16的栈位置。
  • 724: 1000 addi s0,sp,32将栈指针的值加上32,并将结果存储在寄存器 s0 中,即将s0指向当前函数的栈底。
  • 726: 4785 li a5,1将局部变量a的值加载到a5寄存器中
  • 728: fef43023 sd a5,-32(s0)将局部变量a的值保存到sp偏移0的位置,(fp - 32)的栈位置
  • 72c: 4789 li a5,2将局部变量b的值加载到a5寄存器中
  • 72e: fef43423 sd a5,-24(s0)将局部变量b的值保存到sp + 8,即(fp - 24)的栈位置处。
  • 732: fe843683 ld a3,-24(s0)从栈中取出局部变量b的值,放到a3寄存器中
  • 736: fe043603 ld a2,-32(s0)从栈中取出局部变量a的值,放到a2寄存器中
  • 73a: 00000597 auipc a1,0x0
  • 73e: 15658593 addi a1,a1,342 # 890 <__func__.2104>
  • 742: 00000517 auipc a0,0x0
  • 746: 0fe50513 addi a0,a0,254 # 840 <__libc_csu_fini+0x62>这些指令用于设置 a1 和 a0 寄存器的值。通过使用 auipc 指令和相对偏移量,将一个值加载到寄存器中。
  • 74a: e07ff0ef jal ra,550 <printf@plt>跳转并链接到地址为550的函数(这里是 printf)。 jal 指令将返回地址(保存在 ra 寄存器中)。
  • 74e: 4685 li a3,1将立即数1加载到a3寄存器中,作为调用test_fun_a函数的第4个参数
  • 750: 4601 li a2,0将立即数0保存到a2寄存器中,作为调用test_fun_a函数的第3个参数
  • 752: fe843583 ld a1,-24(s0)从栈中取出局部变量b的值放到a1寄存器中,作为调用test_fun_a函数的第2个参数
  • 756: fe043503 ld a0,-32(s0)从栈中取出局部变量a的值存放到a0寄存器中,作为调用test_fun_a函数的第1个参数
  • 75a: f43ff0ef jal ra,69c <test_fun_a>将返回值保存到ra寄存器中,调用test_fun_a函数,a0 ~ a4是调用test_fun_a函数的四个参数。
  • 75e: fe043703 ld a4,-32(s0)从栈中加载局部变量b的值到a4寄存器中
  • 762: fe843783 ld a5,-24(s0)从栈中加载局部变量a的值到a5寄存器中
  • 766: 97ba add a5,a5,a4a = a + b,将计算的值保存到a5寄存器中
  • 768: fef43023 sd a5,-32(s0)将a5寄存器的值保存到局部变量a的栈位置处,即更新局部变量a的值
  • 76c: fe843703 ld a4,-24(s0)从栈中加载局部变量b的值到a4寄存器中
  • 770: fe043783 ld a5,-32(s0)从栈中加载局部变量a的值到a5寄存器中
  • 774: 97ba add a5,a5,a4将a + b的值放到a5寄存器中
  • 776: fef43423 sd a5,-24(s0)将a + b的值存储在局部变量b的栈内存中,即更新局部变量a的值
  • 77a: 4781 li a5,0加载立即数0到a5寄存器中
  • 77c: 853e mv a0,a5将a5寄存器的值复制给a0寄存器,即给a0寄存器赋值为0,a0用来保存函数的返回值
  • 77e: 60e2 ld ra,24(sp)恢复ra寄存器的值
  • 780: 6442 ld s0,16(sp)恢复s0(FP)寄存器的值
  • 782: 6105 addi sp,sp,32恢复栈
  • 784: 8082 ret返回调用main的函数中
000000000000071e <main>:
 71e:   1101                    addi    sp,sp,-32
 720:   ec06                    sd      ra,24(sp)
 722:   e822                    sd      s0,16(sp)
 724:   1000                    addi    s0,sp,32
 726:   4785                    li      a5,1
 728:   fef43023                sd      a5,-32(s0)
 72c:   4789                    li      a5,2
 72e:   fef43423                sd      a5,-24(s0)
 732:   fe843683                ld      a3,-24(s0)
 736:   fe043603                ld      a2,-32(s0)
 73a:   00000597                auipc   a1,0x0
 73e:   15658593                addi    a1,a1,342 # 890 <__func__.2104>                                                                                                                                    
 742:   00000517                auipc   a0,0x0
 746:   0fe50513                addi    a0,a0,254 # 840 <__libc_csu_fini+0x62>
 74a:   e07ff0ef                jal     ra,550 <printf@plt>
 74e:   4685                    li      a3,1
 750:   4601                    li      a2,0
 752:   fe843583                ld      a1,-24(s0)
 756:   fe043503                ld      a0,-32(s0)
 75a:   f43ff0ef                jal     ra,69c <test_fun_a>
 75e:   fe043703                ld      a4,-32(s0)
 762:   fe843783                ld      a5,-24(s0)
 766:   97ba                    add     a5,a5,a4
 768:   fef43023                sd      a5,-32(s0)
 76c:   fe843703                ld      a4,-24(s0)
 770:   fe043783                ld      a5,-32(s0)
 774:   97ba                    add     a5,a5,a4
 776:   fef43423                sd      a5,-24(s0)
 77a:   4781                    li      a5,0
 77c:   853e                    mv      a0,a5
 77e:   60e2                    ld      ra,24(sp)
 780:   6442                    ld      s0,16(sp)
 782:   6105                    addi    sp,sp,32
 784:   8082                    ret

2.1.3 执行完成之后栈的存放情况

在这里插入图片描述

2.2 test_fun_a函数及其对应的汇编程序

2.2.1 test_fun_a函数的C实现

void test_fun_a(long m, long n, long x, long y)
{
    
    
        long b = 2;
        long c = 3;

        printf("The current function is %s b:%ld c:%ld\r\n", __func__, b, c); 

        test_fun_b(b, c, 0, 2); 

        b = b + c + m;
        c = b + c + n;
}

2.2.2 test_fun_a函数对应汇编及其分析

  • 000000000000069c <test_fun_a>:
  • 69c: 7139 addi sp,sp,-64为test_fun_a函数开辟一块64Byte的栈空间
  • 69e: fc06 sd ra,56(sp)将ra加载到sp + 56的栈内存中
  • 6a0: f822 sd s0,48(sp)将s0加载到sp + 48的栈内存中
  • 6a2: 0080 addi s0,sp,64将栈底保存到s0(FP)寄存器中
  • 6a4: fca43c23 sd a0,-40(s0)将第一个参数加载到fp - 40的栈内存中,即sp + 24的栈中,
  • 6a8: fcb43823 sd a1,-48(s0)将第二个参数加载到fp - 48的栈内存中,即sp + 16的栈中,
  • 6ac: fcc43423 sd a2,-56(s0)将第三个参数加载到fp - 56的栈内存中,即sp + 8的栈中,
  • 6b0: fcd43023 sd a3,-64(s0)将第四个参数加载到fp - 64的栈内存中,即sp + 0的栈中,
  • 6b4: 4789 li a5,2将局部变量b的值2加载到a5寄存器中
  • 6b6: fef43023 sd a5,-32(s0)将局部变量b的值存储到fp - 32的栈内存中,即sp + 32的栈中
  • 6ba: 478d li a5,3将局部变量c的值加载到a5寄存器中
  • 6bc: fef43423 sd a5,-24(s0)将局部变量c的值存储到fp - 24的栈内存中,即sp + 40的栈中
  • 6c0: fe843683 ld a3,-24(s0)从栈中取出局部变量c的值取出放到a3寄存器中
  • 6c4: fe043603 ld a2,-32(s0)从栈中取出局部变量b的值取出放到局部变量a2中
  • 6c8: 00000597 auipc a1,0x0
  • 6cc: 1b858593 addi a1,a1,440 # 880 <__func__.2098>
  • 6d0: 00000517 auipc a0,0x0
  • 6d4: 14050513 addi a0,a0,320 # 810 <__libc_csu_fini+0x32>
  • 6d8: e79ff0ef jal ra,550 <printf@plt>将返回值保存到ra寄存器中,调用printf
  • 6dc: 4689 li a3,2加载立即数2到a3中
  • 6de: 4601 li a2,0加载立即数0到a2中
  • 6e0: fe843583 ld a1,-24(s0)从栈fp - 24的栈中取出局部变量c的值到a1寄存器中
  • 6e4: fe043503 ld a0,-32(s0)从栈fp - 32的栈内存取出局部变量b的值到a0寄存器中
  • 6e8: f43ff0ef jal ra,62a <test_fun_b>将返回值保存到ra寄存器中,调用test_fun_b函数
  • 6ec: fe043703 ld a4,-32(s0)从fp - 32栈内存中取出局部变量b的值到a4寄存器中
  • 6f0: fe843783 ld a5,-24(s0)从fp - 24栈内存中取出局部变量c的值到a5寄存器中
  • 6f4: 97ba add a5,a5,a4 b + c将计算的值更到到a5寄存器中
  • 6f6: fd843703 ld a4,-40(s0)从fp - 40的栈中取出第一个参数m的值到a4寄存器中
  • 6fa: 97ba add a5,a5,a4 b + c + m的值保存到a5寄存器中
  • 6fc: fef43023 sd a5,-32(s0)存储b + c + m的值到局部变量b的栈内存中
  • 700: fe043703 ld a4,-32(s0)从栈中取出局部变量b的值到a4寄存器中
  • 704: fe843783 ld a5,-24(s0)从栈中取出局部变量c的值到a5寄存器中
  • 708: 97ba add a5,a5,a4b + c的值保存到a5寄存器中
  • 70a: fd043703 ld a4,-48(s0)从栈中取出第二个参数n的值到a4寄存器中
  • 70e: 97ba add a5,a5,a4 b + c + n 的值保存到a5寄存器中
  • 710: fef43423 sd a5,-24(s0)将b + c + n的值保存到局部变量c的栈内存中
  • 714: 0001 nop
  • 716: 70e2 ld ra,56(sp)从栈中恢复ra的值
  • 718: 7442 ld s0,48(sp)从栈中恢复s0(FP)的值
  • 71a: 6121 addi sp,sp,64恢复sp寄存器
  • 71c: 8082 ret返回main函数调用test_fun_a的下一条指令处。
000000000000069c <test_fun_a>:
 69c:   7139                    addi    sp,sp,-64
 69e:   fc06                    sd      ra,56(sp)
 6a0:   f822                    sd      s0,48(sp)
 6a2:   0080                    addi    s0,sp,64
 6a4:   fca43c23                sd      a0,-40(s0)
 6a8:   fcb43823                sd      a1,-48(s0)
 6ac:   fcc43423                sd      a2,-56(s0)
 6b0:   fcd43023                sd      a3,-64(s0)
 6b4:   4789                    li      a5,2
 6b6:   fef43023                sd      a5,-32(s0)
 6ba:   478d                    li      a5,3
 6bc:   fef43423                sd      a5,-24(s0)
 6c0:   fe843683                ld      a3,-24(s0)
 6c4:   fe043603                ld      a2,-32(s0)
 6c8:   00000597                auipc   a1,0x0
 6cc:   1b858593                addi    a1,a1,440 # 880 <__func__.2098>
 6d0:   00000517                auipc   a0,0x0
 6d4:   14050513                addi    a0,a0,320 # 810 <__libc_csu_fini+0x32>
 6d8:   e79ff0ef                jal     ra,550 <printf@plt>
 6dc:   4689                    li      a3,2
 6de:   4601                    li      a2,0
 6e0:   fe843583                ld      a1,-24(s0)
 6e4:   fe043503                ld      a0,-32(s0)
 6e8:   f43ff0ef                jal     ra,62a <test_fun_b>
 6ec:   fe043703                ld      a4,-32(s0)
 6f0:   fe843783                ld      a5,-24(s0)
 6f4:   97ba                    add     a5,a5,a4
 6f6:   fd843703                ld      a4,-40(s0)                                                                                                                                                         
 6fa:   97ba                    add     a5,a5,a4
 6fc:   fef43023                sd      a5,-32(s0)
 700:   fe043703                ld      a4,-32(s0)
 704:   fe843783                ld      a5,-24(s0)
 708:   97ba                    add     a5,a5,a4
 70a:   fd043703                ld      a4,-48(s0)
 70e:   97ba                    add     a5,a5,a4
 710:   fef43423                sd      a5,-24(s0)
 714:   0001                    nop
 716:   70e2                    ld      ra,56(sp)
 718:   7442                    ld      s0,48(sp)
 71a:   6121                    addi    sp,sp,64
 71c:   8082                    ret

2.2.3 执行完成之后栈帧的使用情况

在这里插入图片描述

2.3 test_fun_b函数及其对应的汇编程序

2.3.1 test_func_b函数的C实现

void test_fun_b(long m, long n, long x, long y)
{
    
    
        long c = 3;
        long d = 4;

        printf("The current function is %s c:%ld d:%ld\r\n", __func__, c, d); 

        c = c + d + m;
        d = c + d + n;
}

2.3.2 test_fun_b函数对应汇编及其分析

  • 000000000000062a <test_fun_b>:
  • 62a: 7139 addi sp,sp,-64为test_func_b开辟64Byte的栈空间
  • 62c: fc06 sd ra,56(sp)将ra保存到sp + 56栈内存中
  • 62e: f822 sd s0,48(sp)将s0(FP)保存到sp + 48栈内存中
  • 630: 0080 addi s0,sp,64将栈底的值保存到s0(FP)寄存器中
  • 632: fca43c23 sd a0,-40(s0)存储第一个参数到fp - 40栈内存中
  • 636: fcb43823 sd a1,-48(s0)存储第二个参数到fp - 48栈内存中
  • 63a: fcc43423 sd a2,-56(s0)存储第三个参数到fp - 56栈内存中
  • 63e: fcd43023 sd a3,-64(s0)存储第四个参数到fp - 64栈内存中
  • 642: 478d li a5,3加载局部变量c的值到a5寄存器中
  • 644: fef43023 sd a5,-32(s0)将局部变量c的值存储到fp - 32栈内存中
  • 648: 4791 li a5,4加载局部变量d的值到a5寄存器中
  • 64a: fef43423 sd a5,-24(s0)存储局部变量d的值到fp - 24栈内存中
  • 64e: fe843683 ld a3,-24(s0)从fp - 24的栈内存中取出局部变量d的值到a3寄存器中
  • 652: fe043603 ld a2,-32(s0)从fp - 32的栈内存中取出局部变量c的值到a2寄存器中
  • 656: 00000597 auipc a1,0x0
  • 65a: 21a58593 addi a1,a1,538 # 870 <__func__.2089>
  • 65e: 00000517 auipc a0,0x0
  • 662: 18250513 addi a0,a0,386 # 7e0 <__libc_csu_fini+0x2>
  • 666: eebff0ef jal ra,550 <printf@plt> 将返回值保存到ra寄存中其,调用printf函数
  • 66a: fe043703 ld a4,-32(s0)从栈fp - 32中取出局部变量c的值到a4寄存器中
  • 66e: fe843783 ld a5,-24(s0)从栈fp - 24中取出局部变量d的值到a5寄存器中
  • 672: 97ba add a5,a5,a4将b + c值保存到a5Jicunqi zhong
  • 674: fd843703 ld a4,-40(s0)从栈中取出第一个参数m的值到a4寄存器中
  • 678: 97ba add a5,a5,a4将b + c + m的值保存到a5寄存器中
  • 67a: fef43023 sd a5,-32(s0)存储b + c + m 的值到栈fp - 32栈内存中,即局部变量c的栈内存位置处
  • 67e: fe043703 ld a4,-32(s0)从栈中取出局部变量c的值到a4寄存器中
  • 682: fe843783 ld a5,-24(s0)从栈中取出局部变量d的值到a5寄存器中
  • 686: 97ba add a5,a5,a4
  • 688: fd043703 ld a4,-48(s0)从栈中取出第二个参数n的值到a4寄存器中
  • 68c: 97ba add a5,a5,a4将c + d + n的值到a5寄存器中
  • 68e: fef43423 sd a5,-24(s0)将c + d + n的值存储到fp - 24的栈内存中
  • 692: 0001 nop
  • 694: 70e2 ld ra,56(sp)恢复ra寄存器的值
  • 696: 7442 ld s0,48(sp)恢复s0(FP)寄存器的值
  • 698: 6121 addi sp,sp,64恢复sp寄存器的值
  • 69a: 8082 ret返回ra寄存器的地址
000000000000062a <test_fun_b>:
 62a:   7139                    addi    sp,sp,-64
 62c:   fc06                    sd      ra,56(sp)
 62e:   f822                    sd      s0,48(sp)
 630:   0080                    addi    s0,sp,64
 632:   fca43c23                sd      a0,-40(s0)
 636:   fcb43823                sd      a1,-48(s0)
 63a:   fcc43423                sd      a2,-56(s0)
 63e:   fcd43023                sd      a3,-64(s0)
 642:   478d                    li      a5,3
 644:   fef43023                sd      a5,-32(s0)
 648:   4791                    li      a5,4
 64a:   fef43423                sd      a5,-24(s0)
 64e:   fe843683                ld      a3,-24(s0)                                                                                                                                                         
 652:   fe043603                ld      a2,-32(s0)
 656:   00000597                auipc   a1,0x0
 65a:   21a58593                addi    a1,a1,538 # 870 <__func__.2089>
 65e:   00000517                auipc   a0,0x0
 662:   18250513                addi    a0,a0,386 # 7e0 <__libc_csu_fini+0x2>
 666:   eebff0ef                jal     ra,550 <printf@plt>
 66a:   fe043703                ld      a4,-32(s0)
 66e:   fe843783                ld      a5,-24(s0)
 672:   97ba                    add     a5,a5,a4
 674:   fd843703                ld      a4,-40(s0)
 678:   97ba                    add     a5,a5,a4
 67a:   fef43023                sd      a5,-32(s0)
 67e:   fe043703                ld      a4,-32(s0)
 682:   fe843783                ld      a5,-24(s0)
 686:   97ba                    add     a5,a5,a4
 688:   fd043703                ld      a4,-48(s0)
 68c:   97ba                    add     a5,a5,a4
 68e:   fef43423                sd      a5,-24(s0)
 692:   0001                    nop
 694:   70e2                    ld      ra,56(sp)
 696:   7442                    ld      s0,48(sp)
 698:   6121                    addi    sp,sp,64
 69a:   8082                    ret

2.3.3 执行完成之后栈帧的使用情况

在这里插入图片描述

3 编译和反汇编的命令

3.1 编译的命令

需要注意的是如果不加-Wl,--no-as-needed编译选项,则在反汇编的时候无法查看到标准库的接口,不太容易理解对应的汇编程序。

riscv64-linux-gnu-gcc -Wl,--no-as-needed main.c -o rv_test

3.2 反汇编的命令

riscv64-linux-gnu-objdump -S -d rv_test

猜你喜欢

转载自blog.csdn.net/u014100559/article/details/132502923
今日推荐