RV64函数调用流程分析
- 1 RV64 函数调用实例
- 2 对应代码的分析
- 2.1 main函数及其对应的汇编程序
- 2.1.1 main的C代码实现
- 2.1.2 main函数对应汇编及其分析
- 2.1.3 执行完成之后栈的存放情况
 
- 2.2 test_fun_a函数及其对应的汇编程序
- 2.2.1 test_fun_a函数的C实现
- 2.2.2 test_fun_a函数对应汇编及其分析
- 2.2.3 执行完成之后栈帧的使用情况
 
- 2.3 test_fun_b函数及其对应的汇编程序
- 2.3.1 test_func_b函数的C实现
- 2.3.2 test_fun_b函数对应汇编及其分析
- 2.3.3 执行完成之后栈帧的使用情况
 
 
- 3 编译和反汇编的命令
- 3.1 编译的命令
- 3.2 反汇编的命令
 
[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,-32720:   ec06                    sd      ra,24(sp)722:   e822                    sd      s0,16(sp)724:   1000                    addi    s0,sp,32726:   4785                    li      a5,1728:   fef43023                sd      a5,-32(s0)72c:   4789                    li      a5,272e:   fef43423                sd      a5,-24(s0)732:   fe843683                ld      a3,-24(s0)736:   fe043603                ld      a2,-32(s0)73a:   00000597                auipc   a1,0x073e:   15658593                addi    a1,a1,342 # 890 <__func__.2104>                                                                                                                                    742:   00000517                auipc   a0,0x0746:   0fe50513                addi    a0,a0,254 # 840 <__libc_csu_fini+0x62>74a:   e07ff0ef                jal     ra,550 <printf@plt>74e:   4685                    li      a3,1750:   4601                    li      a2,0752:   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,a4768:   fef43023                sd      a5,-32(s0)76c:   fe843703                ld      a4,-24(s0)770:   fe043783                ld      a5,-32(s0)774:   97ba                    add     a5,a5,a4776:   fef43423                sd      a5,-24(s0)77a:   4781                    li      a5,077c:   853e                    mv      a0,a577e:   60e2                    ld      ra,24(sp)780:   6442                    ld      s0,16(sp)782:   6105                    addi    sp,sp,32784:   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,a4b + c将计算的值更到到a5寄存器中
- 6f6: fd843703 ld a4,-40(s0)从fp - 40的栈中取出第一个参数m的值到a4寄存器中
- 6fa: 97ba add a5,a5,a4b + 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,a4b + 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,-6469e:   fc06                    sd      ra,56(sp)6a0:   f822                    sd      s0,48(sp)6a2:   0080                    addi    s0,sp,646a4:   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,26b6:   fef43023                sd      a5,-32(s0)6ba:   478d                    li      a5,36bc:   fef43423                sd      a5,-24(s0)6c0:   fe843683                ld      a3,-24(s0)6c4:   fe043603                ld      a2,-32(s0)6c8:   00000597                auipc   a1,0x06cc:   1b858593                addi    a1,a1,440 # 880 <__func__.2098>6d0:   00000517                auipc   a0,0x06d4:   14050513                addi    a0,a0,320 # 810 <__libc_csu_fini+0x32>6d8:   e79ff0ef                jal     ra,550 <printf@plt>6dc:   4689                    li      a3,26de:   4601                    li      a2,06e0:   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,a46f6:   fd843703                ld      a4,-40(s0)                                                                                                                                                         6fa:   97ba                    add     a5,a5,a46fc:   fef43023                sd      a5,-32(s0)700:   fe043703                ld      a4,-32(s0)704:   fe843783                ld      a5,-24(s0)708:   97ba                    add     a5,a5,a470a:   fd043703                ld      a4,-48(s0)70e:   97ba                    add     a5,a5,a4710:   fef43423                sd      a5,-24(s0)714:   0001                    nop716:   70e2                    ld      ra,56(sp)718:   7442                    ld      s0,48(sp)71a:   6121                    addi    sp,sp,6471c:   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,-6462c:   fc06                    sd      ra,56(sp)62e:   f822                    sd      s0,48(sp)630:   0080                    addi    s0,sp,64632:   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,3644:   fef43023                sd      a5,-32(s0)648:   4791                    li      a5,464a:   fef43423                sd      a5,-24(s0)64e:   fe843683                ld      a3,-24(s0)                                                                                                                                                         652:   fe043603                ld      a2,-32(s0)656:   00000597                auipc   a1,0x065a:   21a58593                addi    a1,a1,538 # 870 <__func__.2089>65e:   00000517                auipc   a0,0x0662:   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,a4674:   fd843703                ld      a4,-40(s0)678:   97ba                    add     a5,a5,a467a:   fef43023                sd      a5,-32(s0)67e:   fe043703                ld      a4,-32(s0)682:   fe843783                ld      a5,-24(s0)686:   97ba                    add     a5,a5,a4688:   fd043703                ld      a4,-48(s0)68c:   97ba                    add     a5,a5,a468e:   fef43423                sd      a5,-24(s0)692:   0001                    nop694:   70e2                    ld      ra,56(sp)696:   7442                    ld      s0,48(sp)698:   6121                    addi    sp,sp,6469a:   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