[RV64 程序调用标准]
下图是介绍一个简单函数调用的示例,在该示例中简单介绍了栈的使用。
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;
}
000000000000071e :
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
跳转并链接到地址为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
将返回值保存到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,a4
a = 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
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;
}
000000000000069c :
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
将返回值保存到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
将返回值保存到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,a4
b + 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
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;
}
000000000000062a :
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
将返回值保存到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
需要注意的是如果不加-Wl,--no-as-needed
编译选项,则在反汇编的时候无法查看到标准库的接口,不太容易理解对应的汇编程序。
riscv64-linux-gnu-gcc -Wl,--no-as-needed main.c -o rv_test
riscv64-linux-gnu-objdump -S -d rv_test