1-6-过程的执行

过程的执行步骤

将参数放在过程可以访问的位置

调用者将参数放在$a0-$a3寄存器中。

将控制转交给过程

通过jal指令,跳转到过程开始所在的指令。此时会把下一条指令的地址(即 PC+4)存储在$ra寄存器中,供控制返回时跳转。

程序计数器(PC):寄存器,其值为程序中正在被执行的指令的地址。

获得过程所需的存储资源

为避免寄存器使用冲突,需要将寄存器的值换出到存储器(压栈),返回之前,将寄存器还原(出栈)。
栈指针存储在$sp寄存器中。

leaf_example:

addi $sp, $sp, -12 // 申请3个空间

// 将 $s0、$s1、$s2三个寄存器的值压栈
sw $s0, 8($sp)
sw $s1, 4($sp)
sw $s2, 0($sp)

// 自由使用这三个存储器
...

// 返回前,将三个存储器的值还原
lw $s2, 0($sp)
lw $s1, 4($sp)
lw $s0, 8($sp)

addi $sp, $sp, 12 // 释放申请的3个空间

jr $ra

在调用过程之前(a)、之中(b)、之后(c)栈指针以及栈的值得变化

执行需要的任务

将结果的值放在调用程序可以访问的位置

被调用者将结果放在$v0$v1寄存器中。

将控制返回初始点

调用寄存器跳转指令jr,跳转到初始点,其位置在$ra寄存器中。

例:计算阶乘

int fact (int n) {
    if (n > 1) {
        return 1;
    } else {
        return (n * fact(n - 1))
    }
}
fact:

    // 申请2个空间存储返回地址寄存器$ra和参数寄存器$a0
    addi $sp, $sp, -8
    sw $ra, 4($sp)
    sw $a0, 0($sp)

    // 如果n < 1,$t0的值为1,如果$t0的值为0(即n>=1),则跳转到L1
    slti $t0, $a0, 1
    beq $t0, $zero, L1

    // 如果 n < 1,返回1(存储在$v0寄存器中)
    addi $v0, $zero, 1
    addi $sp, $sp, 8 // 释放申请的寄存器空间
    
    // 返回
    jr $ra

L1:
    // 将参数n的值减1,重新调用fact
    addi $a0, $a0, -1
    jal fact

fact返回处:
    // 释放申请的栈空间
    lw $a0, 0($sp)
    lw $ra, 4($sp)
    addi $sp, $sp, 8
    
    //计算乘法
    mul $v0, $a0, $v0
    jr $ra