RISC-V汇编指令
- RISC-V
- 2024-04-11
- 299热度
- 0评论
C源代码
unsigned int arithmetic(unsigned int a, unsigned int b)
{
unsigned int sum, diff, upper;
sum = a + b;
sum = sum + 2;
diff = a - b;
diff = diff -1;
upper = 8192;
return sum + diff + upper;
}
unsigned int shits(unsigned int *a, unsigned *b)
{
unsigned int shift_left,shift_right;
shift_left = 16 << 2;
shift_right = 8 >> 2;
shift_left = shift_left >> *a;
shift_right = shift_right << *b;
return shift_left + shift_right;
}
unsigned int logical(unsigned int a, unsigned int b)
{
unsigned and_op, or_op, xor_op;
and_op = a & b;
and_op = and_op & 3;
or_op = a | b;
or_op = or_op | 3;
xor_op = a ^ b;
xor_op = xor_op ^ 3;
return and_op + or_op + xor_op;
}
unsigned int compare(unsigned int a, unsigned int b)
{
return a > b ? 1 : 0;
}
void branch(unsigned int a, unsigned int b)
{
int c;
int i;
if (a <= b) {
c = a + b;
} else {
c = a - b;
}
for (i = 0; i < c; i ++) {
c = c + i;
}
}
unsigned int mul_div_rem(unsigned int a, unsigned int b)
{
unsigned int prod, quo, rem;
prod = a * b;
quo = a / b;
rem = b
return prod + quo + rem;
}
float fp_add(float a, float b)
{
return a + b;
}
double fp_mul(double a, double b)
{
return a * b;
}
int start_kernel(void)
{
unsigned int a = 8, b = 2, ret;
ret = arithmetic(a,b);
ret = shits(&ret, &b);
ret = logical(ret , a);
ret = compare(a, b);
branch(a, b);
float fa = 1.0f, fb = 2.0f;
fp_add(fa, fb);
double da = 1.0, db = 2.0;
fp_mul(da, db);
return 0;
}
汇编代码
baremetal.elf: file format elf64-littleriscv
Disassembly of section .text:
0000000080000000 <_start>:
.global _start
.text
_start:
la sp, __init_stack_end__
80000000: 00004117 auipc sp,0x4 //sp = pc + 0x4 << 12(0x400)
80000004: 3c010113 addi sp,sp,960 # 800043c0 //sp = sp + 960
<__init_stack_end__>
li t0, 0x6000
80000008: 6299 lui t0,0x6//t0 = 0x6 << 12
csrc mstatus, t0
8000000a: 3002b073 csrc mstatus,t0 //mstatus = mstatus & ~t0
li t0, 0x2000
8000000e: 6289 lui t0,0x2 //t0 = 0x2 << 12
csrs mstatus, t0
80000010: 3002a073 csrs mstatus,t0 //mstatus=mstatus | t0
使能mstauts[14:13]bit,使能浮点数单元。
j start_kernel
80000014: 00e0006f j 80000022 <start_kernel>
0000000080000018 <loop>:
loop:
nop
80000018: 0001 nop
nop
8000001a: 0001 nop
nop
8000001c: 0001 nop
nop
8000001e: 0001 nop
j loop
80000020: bfe5 j 80000018 <loop>
0000000080000022 <start_kernel>:
#include <test.h>
int start_kernel(void)
{
80000022: 7139 addi sp,sp,-64 //sp=sp-64,相当于分配64字节大小的栈空间
80000024: fc06 sd ra,56(sp)//ra存储到sp+56位置,ra是返回函数地址,64位系统占用8个字节。由于该函数有子函数,所以要存储ra。
80000026: f822 sd s0,48(sp)//s0存储到sp+48位置
80000028: 0080 addi s0,sp,64//s0=sp +64,s0指向当前栈帧位置,所以s0也常用于栈帧指针。更新当前函数的栈帧。
unsigned int a = 8, b = 2, ret;
8000002a: 47a1 li a5,8//a5=8
8000002c: fef42623 sw a5,-20(s0)//将a5存储到s0-20的位置,存储到栈帧里面去
80000030: 4789 li a5,2//a5=2,
80000032: fcf42623 sw a5,-52(s0)//将a5存储到s0-52的位置,存储栈帧空间去。(sw,store word,存储4字节)
ret = arithmetic(a,b);
80000036: fcc42703 lw a4,-52(s0)//加载s0-52地址的数据到a4中,就是b=2。
8000003a: fec42783 lw a5,-20(s0)//加载s0-20地址的数据到a5,就是a=8
8000003e: 85ba mv a1,a4//a1=a4,参数b
80000040: 853e mv a0,a5//a0=a5,参数a
80000042: 0c4000ef jal ra,80000106 <arithmetic>//ra=PC+4,存储函数的返回的地址,PC=80000106,跳转到arithmetic函数
80000046: 87aa mv a5,a0 //保存函数返回值
80000048: 2781 sext.w a5,a5 //将a5拓展为32位有符号数字,因为a0是64为寄存器。
8000004a: fcf42423 sw a5,-56(s0) //将a5存储到栈帧中(s0-56)
ret = shits(&ret, &b);
8000004e: fcc40713 addi a4,s0,-52 //a4=s0-52,获取b的地址
80000052: fc840793 addi a5,s0,-56//a5=s0-56,获取ret的地址
80000056: 85ba mv a1,a4//a1=a4,将b的地址赋值为a1,函数参数传递准备
80000058: 853e mv a0,a5//a0=a5,将ret的地址赋值为a0,函数参数传递准备
8000005a: 114000ef jal ra,8000016e <shits>//ra=PC+4,PC=8000016e
8000005e: 87aa mv a5,a0//保存函数的返回地址
80000060: 2781 sext.w a5,a5//将a5拓展为32位有符号数字
80000062: fcf42423 sw a5,-56(s0)//将a5存储到栈帧中(更新ret的值)
ret = logical(ret , a);
80000066: fc842783 lw a5,-56(s0)
8000006a: fec42703 lw a4,-20(s0)
8000006e: 85ba mv a1,a4
80000070: 853e mv a0,a5
80000072: 154000ef jal ra,800001c6 <logical>
80000076: 87aa mv a5,a0
80000078: 2781 sext.w a5,a5
8000007a: fcf42423 sw a5,-56(s0)
ret = compare(a, b);
8000007e: fcc42703 lw a4,-52(s0)
80000082: fec42783 lw a5,-20(s0)
80000086: 85ba mv a1,a4
80000088: 853e mv a0,a5
8000008a: 1b8000ef jal ra,80000242 <compare>
8000008e: 87aa mv a5,a0
80000090: 2781 sext.w a5,a5
80000092: fcf42423 sw a5,-56(s0)
branch(a, b);
branch(a, b);
80000096: fcc42703 lw a4,-52(s0)
8000009a: fec42783 lw a5,-20(s0)
8000009e: 85ba mv a1,a4
800000a0: 853e mv a0,a5
800000a2: 1d2000ef jal ra,80000274 <branch>
float fa = 1.0f, fb = 2.0f;
800000a6: 00000797 auipc a5,0x0
800000aa: 2fa78793 addi a5,a5,762 # 800003a0 <.LC0>
800000ae: 0007a787 flw fa5,0(a5)
800000b2: fef42427 fsw fa5,-24(s0)
800000b6: 00000797 auipc a5,0x0
800000ba: 2ee78793 addi a5,a5,750 # 800003a4 <.LC1>
800000be: 0007a787 flw fa5,0(a5)
800000c2: fef42227 fsw fa5,-28(s0)
fp_add(fa, fb);
800000c6: fe442587 flw fa1,-28(s0)
800000ca: fe842507 flw fa0,-24(s0)
800000ce: 286000ef jal ra,80000354 <fp_add>
对于浮点值,先存储到符号表上,去加载load到寄存器中去。
在标准RISC-V指令集中,浮点数确实不支持直接的立即数操作。大部分RISC-V的浮点指令涉及到的操作数通常是寄存器到寄存器的,也就是说,浮点运算的数据来源于浮点寄存器文件(FPU registers),而不是像整数指令那样可以从指令中直接获取一个立即数。
如果需要在程序中使用常量浮点数,通常会在程序初始化或相关代码段中先将这些常量加载到浮点寄存器中,然后再参与后续的浮点运算。例如,可以通过加载字节(LB, LBU, etc.)或加载半字(LH, LHU, etc.)指令从内存中读取浮点数的二进制表示(按照IEEE 754标准编码),然后利用适当的浮点装载指令(FLW或FLD)将这些数据载入浮点寄存器。
当然,在一些高级编程语言环境下,编译器会自动处理这些细节,程序员无需关心如何将常量放入寄存器的过程。而对于硬件设计者或底层软件开发者来说,理解这一机制是非常重要的。随着RISC-V生态的发展,未来有可能会出现扩展指令集来支持更丰富的浮点数立即数操作,但这不是当前标准RISC-V ISA的一部分。
double da = 1.0, db = 2.0;
800000d2: 00000797 auipc a5,0x0 //a5=PC+0x00<<12
800000d6: 2d678793 addi a5,a5,726 # 800003a8 <.LC2>//a5=a5+726
800000da: 239c fld fa5,0(a5)//fa5=*a5,获取a5的地址数据
800000dc: fcf43c27 fsd fa5,-40(s0)//将fa5存储到s0-40栈上。
800000e0: 00000797 auipc a5,0x0//a5=PC+0x00<<12
800000e4: 2d078793 addi a5,a5,720 # 800003b0 <.LC3>//a5=a5+720
800000e8: 239c fld fa5,0(a5)//fa5=*a5,获取a5地址的数据
800000ea: fcf43827 fsd fa5,-48(s0)//将fa5存储到s0-48栈上。
fp_mul(da, db);
800000ee: fd043587 fld fa1,-48(s0)//加载s0-48的数据到fa1,(da)
800000f2: fd843507 fld fa0,-40(s0)//加载s0-40的数据到fa0
800000f6: 282000ef jal ra,80000378 <fp_mul>//跳转到fp_mul
return 0;
800000fa: 4781 li a5,0
}
800000fc: 853e mv a0,a5
800000fe: 70e2 ld ra,56(sp)
80000100: 7442 ld s0,48(sp)
80000102: 6121 addi sp,sp,64
80000104: 8082 ret
0000000080000106 <arithmetic>:
unsigned int arithmetic(unsigned int a, unsigned int b)
{
80000106: 7179 addi sp,sp,-48
80000108: f422 sd s0,40(sp)
8000010a: 1800 addi s0,sp,48
8000010c: 87aa mv a5,a0
8000010e: 872e mv a4,a1
80000110: fcf42e23 sw a5,-36(s0)
80000114: 87ba mv a5,a4
80000116: fcf42c23 sw a5,-40(s0)
unsigned int sum, diff, upper;
sum = a + b;
8000011a: fdc42703 lw a4,-36(s0)
8000011e: fd842783 lw a5,-40(s0)
80000122: 9fb9 addw a5,a5,a4
80000124: fef42623 sw a5,-20(s0)
sum = sum + 2;
80000128: fec42783 lw a5,-20(s0)
8000012c: 2789 addiw a5,a5,2
8000012e: fef42623 sw a5,-20(s0)
diff = a - b;
80000132: fdc42703 lw a4,-36(s0)
80000136: fd842783 lw a5,-40(s0)
8000013a: 40f707bb subw a5,a4,a5
8000013e: fef42423 sw a5,-24(s0)
diff = diff -1;
80000142: fe842783 lw a5,-24(s0)
80000146: 37fd addiw a5,a5,-1
80000148: fef42423 sw a5,-24(s0)
upper = 8192;
8000014c: 6789 lui a5,0x2
8000014e: fef42223 sw a5,-28(s0)
return sum + diff + upper;
80000152: fec42703 lw a4,-20(s0)
80000156: fe842783 lw a5,-24(s0)
8000015a: 9fb9 addw a5,a5,a4
8000015c: 2781 sext.w a5,a5
8000015e: fe442703 lw a4,-28(s0)
80000162: 9fb9 addw a5,a5,a4
80000164: 2781 sext.w a5,a5
}
80000166: 853e mv a0,a5
80000168: 7422 ld s0,40(sp)
8000016a: 6145 addi sp,sp,48
8000016c: 8082 ret
000000008000016e <shits>:
unsigned int shits(unsigned int *a, unsigned *b)
{
8000016e: 7179 addi sp,sp,-48
80000170: f422 sd s0,40(sp)
80000172: 1800 addi s0,sp,48
80000174: fca43c23 sd a0,-40(s0)
80000178: fcb43823 sd a1,-48(s0)
unsigned int shift_left,shift_right;
shift_left = 16 << 2;
8000017c: 04000793 li a5,64
80000180: fef42623 sw a5,-20(s0)
shift_right = 8 >> 2;
80000184: 4789 li a5,2
80000186: fef42423 sw a5,-24(s0)
shift_left = shift_left >> *a;
8000018a: fd843783 ld a5,-40(s0)
8000018e: 439c lw a5,0(a5)
80000190: 873e mv a4,a5
80000192: fec42783 lw a5,-20(s0)
80000196: 00e7d7bb srlw a5,a5,a4
8000019a: fef42623 sw a5,-20(s0)
shift_right = shift_right << *b;
8000019e: fd043783 ld a5,-48(s0)
800001a2: 439c lw a5,0(a5)
800001a4: 873e mv a4,a5
800001a6: fe842783 lw a5,-24(s0)
800001aa: 00e797bb sllw a5,a5,a4
800001ae: fef42423 sw a5,-24(s0)
return shift_left + shift_right;
800001b2: fec42703 lw a4,-20(s0)
800001b6: fe842783 lw a5,-24(s0)
800001ba: 9fb9 addw a5,a5,a4
800001bc: 2781 sext.w a5,a5
}
800001be: 853e mv a0,a5
800001c0: 7422 ld s0,40(sp)
800001c2: 6145 addi sp,sp,48
800001c4: 8082 ret
00000000800001c6 <logical>:
unsigned int logical(unsigned int a, unsigned int b)
800001c6: 7179 addi sp,sp,-48
800001c8: f422 sd s0,40(sp)
800001ca: 1800 addi s0,sp,48
800001cc: 87aa mv a5,a0
800001ce: 872e mv a4,a1
800001d0: fcf42e23 sw a5,-36(s0)
800001d4: 87ba mv a5,a4
800001d6: fcf42c23 sw a5,-40(s0)
unsigned and_op, or_op, xor_op;
and_op = a & b;
800001da: fdc42703 lw a4,-36(s0)
800001de: fd842783 lw a5,-40(s0)
800001e2: 8ff9 and a5,a5,a4
800001e4: fef42623 sw a5,-20(s0)
and_op = and_op & 3;
800001e8: fec42783 lw a5,-20(s0)
800001ec: 8b8d andi a5,a5,3
800001ee: fef42623 sw a5,-20(s0)
or_op = a | b;
800001f2: fdc42703 lw a4,-36(s0)
800001f6: fd842783 lw a5,-40(s0)
800001fa: 8fd9 or a5,a5,a4
800001fc: fef42423 sw a5,-24(s0)
or_op = or_op | 3;
80000200: fe842783 lw a5,-24(s0)
80000204: 0037e793 ori a5,a5,3
80000208: fef42423 sw a5,-24(s0)
xor_op = a ^ b;
8000020c: fdc42703 lw a4,-36(s0)
80000210: fd842783 lw a5,-40(s0)
80000214: 8fb9 xor a5,a5,a4
80000216: fef42223 sw a5,-28(s0)
xor_op = xor_op ^ 3;
8000021a: fe442783 lw a5,-28(s0)
8000021e: 0037c793 xori a5,a5,3
80000222: fef42223 sw a5,-28(s0)
return and_op + or_op + xor_op;
80000226: fec42703 lw a4,-20(s0)
8000022a: fe842783 lw a5,-24(s0)
8000022e: 9fb9 addw a5,a5,a4
80000230: 2781 sext.w a5,a5
80000232: fe442703 lw a4,-28(s0)
80000236: 9fb9 addw a5,a5,a4
80000238: 2781 sext.w a5,a5
}
8000023a: 853e mv a0,a5
8000023c: 7422 ld s0,40(sp)
8000023e: 6145 addi sp,sp,48
80000240: 8082 ret
0000000080000242 <compare>:
unsigned int compare(unsigned int a, unsigned int b)
800001c6: 7179 addi sp,sp,-48
800001c8: f422 sd s0,40(sp)
800001ca: 1800 addi s0,sp,48
800001cc: 87aa mv a5,a0
800001ce: 872e mv a4,a1
800001d0: fcf42e23 sw a5,-36(s0)
800001d4: 87ba mv a5,a4
800001d6: fcf42c23 sw a5,-40(s0)
unsigned and_op, or_op, xor_op;
and_op = a & b;
800001da: fdc42703 lw a4,-36(s0)
800001de: fd842783 lw a5,-40(s0)
800001e2: 8ff9 and a5,a5,a4
800001e4: fef42623 sw a5,-20(s0)
and_op = and_op & 3;
800001e8: fec42783 lw a5,-20(s0)
800001ec: 8b8d andi a5,a5,3
800001ee: fef42623 sw a5,-20(s0)
or_op = a | b;
800001f2: fdc42703 lw a4,-36(s0)
800001f6: fd842783 lw a5,-40(s0)
800001fa: 8fd9 or a5,a5,a4
800001fc: fef42423 sw a5,-24(s0)
or_op = or_op | 3;
80000200: fe842783 lw a5,-24(s0)
80000204: 0037e793 ori a5,a5,3
80000208: fef42423 sw a5,-24(s0)
xor_op = a ^ b;
8000020c: fdc42703 lw a4,-36(s0)
80000210: fd842783 lw a5,-40(s0)
80000214: 8fb9 xor a5,a5,a4
80000216: fef42223 sw a5,-28(s0)
xor_op = xor_op ^ 3;
8000021a: fe442783 lw a5,-28(s0)
8000021e: 0037c793 xori a5,a5,3
80000222: fef42223 sw a5,-28(s0)
return and_op + or_op + xor_op;
80000226: fec42703 lw a4,-20(s0)
8000022a: fe842783 lw a5,-24(s0)
8000022e: 9fb9 addw a5,a5,a4
80000230: 2781 sext.w a5,a5
80000232: fe442703 lw a4,-28(s0)
80000236: 9fb9 addw a5,a5,a4
80000238: 2781 sext.w a5,a5
}
8000023a: 853e mv a0,a5
8000023c: 7422 ld s0,40(sp)
8000023e: 6145 addi sp,sp,48
80000240: 8082 ret
0000000080000242 <compare>:
unsigned int compare(unsigned int a, unsigned int b)
{
80000242: 1101 addi sp,sp,-32
80000244: ec22 sd s0,24(sp)
80000246: 1000 addi s0,sp,32
80000248: 87aa mv a5,a0
8000024a: 872e mv a4,a1
8000024c: fef42623 sw a5,-20(s0)
80000250: 87ba mv a5,a4
80000252: fef42423 sw a5,-24(s0)
return a > b ? 1 : 0;
80000256: fec42703 lw a4,-20(s0)
8000025a: fe842783 lw a5,-24(s0)
8000025e: 2701 sext.w a4,a4
80000260: 2781 sext.w a5,a5
80000262: 00e7b7b3 sltu a5,a5,a4
80000266: 0ff7f793 zext.b a5,a5
8000026a: 2781 sext.w a5,a5
}
8000026c: 853e mv a0,a5
8000026e: 6462 ld s0,24(sp)
80000270: 6105 addi sp,sp,32
80000272: 8082 ret
0000000080000274 <branch>:
void branch(unsigned int a, unsigned int b)
{
80000274: 7179 addi sp,sp,-48
80000276: f422 sd s0,40(sp)
80000278: 1800 addi s0,sp,48
8000027a: 87aa mv a5,a0
8000027c: 872e mv a4,a1
8000027e: fcf42e23 sw a5,-36(s0)
80000282: 87ba mv a5,a4
80000284: fcf42c23 sw a5,-40(s0)
int c;
int i;
if (a <= b) {
80000288: fdc42703 lw a4,-36(s0)
8000028c: fd842783 lw a5,-40(s0)
80000290: 2701 sext.w a4,a4
80000292: 2781 sext.w a5,a5
80000294: 00e7eb63 bltu a5,a4,800002aa <.L10>//无符号比较,if(a5<a4) 跳转到800002aa, a5=b,a4=a
c = a + b;
80000298: fdc42703 lw a4,-36(s0)
8000029c: fd842783 lw a5,-40(s0)
800002a0: 9fb9 addw a5,a5,a4
800002a2: 2781 sext.w a5,a5
800002a4: fef42623 sw a5,-20(s0)
800002a8: a811 j 800002bc <.L11>
00000000800002aa <.L10>:
} else {
c = a - b;
800002aa: fdc42703 lw a4,-36(s0)
800002ae: fd842783 lw a5,-40(s0)
800002b2: 40f707bb subw a5,a4,a5
800002b6: 2781 sext.w a5,a5
800002b8: fef42623 sw a5,-20(s0)
00000000800002bc <.L11>:
}
for (i = 0; i < c; i ++) {
800002bc: fe042423 sw zero,-24(s0)
800002c0: a829 j 800002da <.L12>
00000000800002c2 <.L13>:
c = c + i;
800002c2: fec42703 lw a4,-20(s0)
800002c6: fe842783 lw a5,-24(s0)
800002ca: 9fb9 addw a5,a5,a4
800002cc: fef42623 sw a5,-20(s0)
for (i = 0; i < c; i ++) {
800002d0: fe842783 lw a5,-24(s0)
800002d4: 2785 addiw a5,a5,1
800002d6: fef42423 sw a5,-24(s0)
00000000800002da <.L12>:
800002da: fe842703 lw a4,-24(s0)
800002de: fec42783 lw a5,-20(s0)
800002e2: 2701 sext.w a4,a4
800002e4: 2781 sext.w a5,a5
800002e6: fcf74ee3 blt a4,a5,800002c2 <.L13>
}
}
800002ea: 0001 nop
800002ec: 0001 nop
800002ee: 7422 ld s0,40(sp)
800002f0: 6145 addi sp,sp,48
800002f2: 8082 ret
00000000800002f4 <mul_div_rem>:
unsigned int mul_div_rem(unsigned int a, unsigned int b)
{
800002f4: 7179 addi sp,sp,-48
800002f6: f422 sd s0,40(sp)
800002f8: 1800 addi s0,sp,48
800002fa: 87aa mv a5,a0
800002fc: 872e mv a4,a1
800002fe: fcf42e23 sw a5,-36(s0)
80000302: 87ba mv a5,a4
80000304: fcf42c23 sw a5,-40(s0)
unsigned int prod, quo, rem;
prod = a * b;
80000308: fdc42703 lw a4,-36(s0)
8000030c: fd842783 lw a5,-40(s0)
80000310: 02f707bb mulw a5,a4,a5
80000314: fef42623 sw a5,-20(s0)
quo = a / b;
80000318: fdc42703 lw a4,-36(s0)
8000031c: fd842783 lw a5,-40(s0)
80000320: 02f757bb divuw a5,a4,a5
80000324: fef42423 sw a5,-24(s0)
rem = b
80000328: fd842703 lw a4,-40(s0)
8000032c: fdc42783 lw a5,-36(s0)
80000330: 02f777bb remuw a5,a4,a5
80000334: fef42223 sw a5,-28(s0)
return prod + quo + rem;
80000338: fec42703 lw a4,-20(s0)
8000033c: fe842783 lw a5,-24(s0)
80000340: 9fb9 addw a5,a5,a4
80000342: 2781 sext.w a5,a5
80000344: fe442703 lw a4,-28(s0)
80000348: 9fb9 addw a5,a5,a4
8000034a: 2781 sext.w a5,a5
}
8000034c: 853e mv a0,a5
8000034e: 7422 ld s0,40(sp)
80000350: 6145 addi sp,sp,48
80000352: 8082 ret
0000000080000354 <fp_add>:
float fp_add(float a, float b)
{
80000354: 1101 addi sp,sp,-32
80000356: ec22 sd s0,24(sp)
80000358: 1000 addi s0,sp,32
8000035a: fea42627 fsw fa0,-20(s0)
8000035e: feb42427 fsw fa1,-24(s0)
return a + b;
80000362: fec42707 flw fa4,-20(s0)
80000366: fe842787 flw fa5,-24(s0)
8000036a: 00f777d3 fadd.s fa5,fa4,fa5
}
8000036e: 20f78553 fmv.s fa0,fa5
80000372: 6462 ld s0,24(sp)
80000374: 6105 addi sp,sp,32
80000376: 8082 ret
0000000080000378 <fp_mul>:
double fp_mul(double a, double b)
{
80000378: 1101 addi sp,sp,-32
8000037a: ec22 sd s0,24(sp)
8000037c: 1000 addi s0,sp,32 //前奏阶段,咱不赘述
8000037e: fea43427 fsd fa0,-24(s0) //存储参数a数据,
80000382: feb43027 fsd fa1,-32(s0)//存储参数b数据
return a * b;
80000386: fe843707 fld fa4,-24(s0)//加载参数a的值
8000038a: fe043787 fld fa5,-32(s0)//加载参数b的值
8000038e: 12f777d3 fmul.d fa5,fa4,fa5/fa5=fa4*fa5
}
80000392: 22f78553 fmv.d fa0,fa5//返回值存储到fa0
80000396: 6462 ld s0,24(sp)//恢复上一个函数栈帧
80000398: 6105 addi sp,sp,32//销毁栈
8000039a: 8082 ret
000000008000039c <.LFE7>:
8000039c: 0000 unimp
...
00000000800003a0 <.LC0>:
800003a0: 0000 unimp
800003a2: 3f80 fld fs0,56(a5)
00000000800003a4 <.LC1>:
800003a4: 0000 unimp
800003a6: 4000 lw s0,0(s0)
00000000800003a8 <.LC2>:
800003a8: 0000 unimp
800003aa: 0000 unimp
800003ac: 0000 unimp
800003ae: 3ff0 fld fa2,248(a5)
00000000800003b0 <.LC3>:
800003b0: 0000 unimp
800003b2: 0000 unimp
800003b4: 0000 unimp
800003b6: 4000 lw s0,0(s0)
函数调用约定
函数调用过程可以分为6个阶段
-
- 将参数存放到函数可以访问的位置。
-
- 跳转到函数入口。
-
- 获取函数所需的局部存储资源,按需保存寄存器。
-
- 执行函数功能
-
- 将返回值存放到调用者可访问的位置,恢复寄存器,释放局部存储资源。
-
- 由于程序可从多处调用函数,需将控制权返回到调用点
stack
每一次函数调用,函数都会为自己创建一个栈帧(Stack Frame),只给自己用。函数通过移动Stack Pointer来完成Stack Frame的空间分配。栈空间是向下生长的,
创建一个栈帧的时候就是对sp多减法。一个函数的栈帧保存了寄存器,本地变量,以及超过8个的额外参数等。不同函数保存的大小是不一样的,因此每个函数栈帧的空间大小也是不一样的,但栈栈有一个共性的保存内容,函数的返回地址(ra寄存器)和上一个函数的栈帧指针(s0寄存器)。
- ra寄存器:一般存放在栈帧的第一位
- s0(fp)寄存器:一般存放在栈帧的第二位
之所以要保存ra寄存器是因为函数返回时可以找到返回地址,保存fp寄存器是因为函数返回时可以找到该函数的栈帧起始位置。
在栈帧中有两个重要的相关寄存器,那就是SP和FP;SP指向了栈帧的底部,表示分配了栈帧的空间结束地址,FP指向栈帧的顶部,指向栈帧的开始地址,ra和前一个栈帧的地址都在固定的栈帧位置,就可以通过FP很快的寻址到这两个寄存器,这也是为什么要有fp的一个原因之一。
一个函数的汇编代码构成,可以分为3部分,prologue(准备阶段)+body+epilogue(结束阶段)
- prologue:分配栈帧空间(减少SP的值),保存ra(函数中有子函数调用),s0,saved寄存器
- body:函数执行体,实际C语言看到的内容
- epilogue:恢复saved寄存器,恢复上一个函数的栈帧s0,必要情况恢复ra寄存器,增加sp,ret返回。
ra寄存器不一定会保存,只要当函数中需要调用其他子函数,在进入prologue的时候才会保存ra,否则不会保存ra到栈中,
函数调用中的寄存器,要么作为保存寄存器,其值在函数调用前后保持不变;要么作为零时寄存器,其值在函数调用前后可能改变。函数参数和返回地址在函数调用过程会被修改,与零时寄存器类似。函数的返回地址根据函数是否有子函数调用决定是否要入栈保存。