汇编call指令详解_RISCV汇编程序分析

最近在学RISC-V的汇编,这里我就以上次作业gcd函数为例,分享一下如何写汇编程序。

C语言版的如下。不多介绍了。

int gcd(int a,int b){

  if(b==0)

       return a;

  return gcd(b,a%b);

}

RISCV汇编的代码如下。

    .text

    .globl  gcd

    .type   gcd, @function

gcd:

    addi    sp,sp,-32   #调整栈指针

    sd  ra,24(sp)       #保存函数返回地址

    sd  s0,16(sp)       #保存帧指针(FP)

    addi    s0,sp,32    #指向栈顶

    mv  a4,a0           #第一个参数a放在a0中,移到a4

    mv  a5,a1           #第二个参数b放在a1中,移到a5

        #将其保存到堆栈中

    sw  a4,-20(s0)

    sw  a5,-24(s0)

    bne a5,zero,.return     #如果第二个参数b!=0,再调用一次

    lw  a4,-20(s0)          #如果为0,取出参数a,返回

    j   .end                

.return:

    remw    a1,a4,a5

    mv  a0,a5

    call    gcd

    mv  a4,a0               #将返回参数保存到a4

.end:

    mv  a0,a4               #返回参数a

    ld  ra,24(sp)           #恢复返回地址

    ld  s0,16(sp)           #恢复帧指针(FP)

    addi    sp,sp,32        #恢复栈指针

    ret   

基本指令介绍:

sd=store doubleword,存储双字(8个字节)

ld=load doubleword,加载双字

sw,lw,同理(4个字节)

addi,立即数加

bne=not equal 不等则跳转

j  无条件跳转

mv  寄存器存储到寄存器

ret  返回ra的地址,一般为程序的最后一条指令

一个汇编程序的开头和结尾:

程序的最开始需要

  1. 调整栈指针sp

  2. 保存返回地址ra

  3. 保存帧指针s0(FP)

  4. 让s0指向栈顶

相应的,程序的结尾需要

  1. 将返回参数写入a0

  2. 恢复返回地址ra

  3. 恢复帧指针s0(FP)

  4. 恢复栈指针sp

  5. ret返回

调用子程序用call指令,需要注意:一般将传入的参数写在a0,a1,a2,,,等寄存器中,将返回的参数写在a0中

关于调用堆栈的内容,参考软件课的课件。

(复旦大学周学功老师版权所有)

我们程序中每次调用的sp调整就是开一个新的frame,程序最后的恢复就是释放掉这一段空间。

我们用s0寄存器(帧指针FP)来确定数据在这一帧中的位置

见除了开头和结尾的所有sd、ld、sw、lw中的基址寄存器,都是用的s0

53edb9ab419baa97515c86642728ff63.png435fe2aed63ab8db7063837471ec4dae.png喜欢的朋友点个关注欢迎大家踊跃转发54ba782f26a7ddd1cdb8cd46e342bb2e.png