RISC-V汇编指令

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个阶段

    1. 将参数存放到函数可以访问的位置。
    1. 跳转到函数入口。
    1. 获取函数所需的局部存储资源,按需保存寄存器。
    1. 执行函数功能
    1. 将返回值存放到调用者可访问的位置,恢复寄存器,释放局部存储资源。
    1. 由于程序可从多处调用函数,需将控制权返回到调用点

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到栈中,

函数调用中的寄存器,要么作为保存寄存器,其值在函数调用前后保持不变;要么作为零时寄存器,其值在函数调用前后可能改变。函数参数和返回地址在函数调用过程会被修改,与零时寄存器类似。函数的返回地址根据函数是否有子函数调用决定是否要入栈保存。