comp1521-MIPS快速入门(一)数组以及函数

1 数组

// Read 10 numbers into an array
// then print the numbers which are
// larger than the last number read.

#include <stdio.h>

int main(void) {
    
    
    int i, last_number;
    int numbers[10] = {
    
     0 };

    i = 0;
    while (i < 10) {
    
    
        scanf("%d", &numbers[i]);
        last_number = numbers[i];
        i++;
    }
    i = 0;
    while (i < 10) {
    
    
        if (numbers[i] >= last_number) {
    
    
            printf("%d\n", numbers[i]);
        }
        i++;
    }
}

c语言对应的汇编

# Read 10 numbers into an array
# then print the numbers which are
# larger than the last number read.

# i in register $t0
# registers $t1, $t2 & $t3 used to hold temporary results
# t4 is the last value
main:
    li   $t0, 0         # i = 0
loop0:
    bge  $t0, 10, end0  # while (i < 10) {

    li   $v0, 5         #   scanf("%d", &numbers[i]);
    syscall             # 输入的数字储存在v0中

    mul  $t1, $t0, 4    #   calculate &numbers[i],一个int是4个bit
    la   $t2, numbers   #  储存数组的首地址
    add  $t3, $t1, $t2  #  数组的首地址,加上i * 4,就是0号元素应该在的位置
    sw   $v0, ($t3)     #   store entered number in array,sw就是save word的意思。
                        # v0输入的值储存在t3地址
    add  $t4, $v0, 0    # also can be s0
    addi $t0, $t0, 1    #   i++;
    j    loop0          # }
end0:
    li   $t0, 0         # i = 0
loop1:
    bge  $t0, 10, end1  # while (i < 10) {

    mul  $t1, $t0, 4    #   calculate &numbers[i]
    la   $t2, numbers   #
    add  $t3, $t1, $t2  #
    lw   $a0, ($t3)     #   load numbers[i] into $a0
    bge  $a0, $t4, print # 如果大于等于,就需要去有输出的分支。

    addi $t0, $t0, 1    #   i++
    j    loop1          # }
print:
    li   $v0, 1         #   printf("%d", numbers[i])
    syscall

    li   $a0, '\n'      #   printf("%c", '\n');
    li   $v0, 11
    syscall
    addi $t0, $t0, 1    #   i++  在输出分支里继续增加控制变量。
    j    loop1          # }
end1:

    jr   $ra              # return

.data

numbers:
    .word 0, 0, 0, 0, 0, 0, 0, 0, 0, 0  # int numbers[10] = {0};

2 函数

2.1 sw和lw

主要是sw和lw,这两个指令在操作内存。

sw   $v0, ($t3)     #   store entered number in array,sw就是save word的意思。
                        # v0输入的值储存在t3地址


lw   $a0, ($t3)     #   load *t3 into $a0

2.2 ra

jr $ra
在一个函数里,ra储存的地址是该函数执行完之后,应该返回的地址。所以,该命令执行后,相当于将PC的值设置为ra里的地址值。跳转回去原本函数调用的位置。

2.3 函数使用的一些默认寄存器

存放函数输入参数的四个寄存器: $a0, $a1, $a2, $a3
返回值寄存器在 $v0

2.4 函数调用 jal

jal function set $ra to PC+4 and jumps to function

2.5 无参函数直接调用示例

在这里插入图片描述

2.6 无参有返回值

在这里插入图片描述

2.7 嵌套函数调用

学会将当前的ra值压入stack!
当又调用一个函数的时候,stack向低地址生长!
在这里插入图片描述

2.7.1 sp

当前的栈指针

2.7.2 fp

在这里插入图片描述

2.7.3 示例

#include <stdio.h>

int sum_product(int a, int b);
int product(int x, int y);

int main(void) {
    
    
    int z = sum_product(10, 12);
    printf("%d\n", z);
    return 0;
}

int sum_product(int a, int b) {
    
    
    int p = product(6, 7);
    return p + a + b;
}

int product(int x, int y) {
    
    
    return x * y;
}

对应的汇编

main:
    addi $sp, $sp, -4   # move stack pointer down to make room
    sw   $ra, 0($sp)    # save $ra on $stack

    li   $a0, 10         # sum_product(10, 12);
    li   $a1, 12
    jal  sum_product

    move $a0, $v0       # printf("%d", z);
    li   $v0, 1
    syscall

    li   $a0, '\n'      # printf("%c", '\n');
    li   $v0, 11
    syscall

    lw   $ra, 0($sp)    # recover $ra from $stack
    addi $sp, $sp, 4    # move stack pointer back up to what it was when main called

    li   $v0, 0         # return 0 from function main
    jr   $ra            # return from function main



sum_product:
    addi $sp, $sp, -12  # move stack pointer down to make room
    sw   $ra, 8($sp)    # save $ra on $stack
    sw   $a1, 4($sp)    # save $a1 on $stack
    sw   $a0, 0($sp)    # save $a0 on $stack

    li   $a0, 6         # product(6, 7);
    li   $a1, 7
    jal  product

    lw   $a1, 4($sp)    # restore $a1 from $stack
    lw   $a0, 0($sp)    # restore $a0 from $stack

    add  $v0, $v0, $a0  # add a and b to value returned in $v0
    add  $v0, $v0, $a1  # and put result in $v0 to be returned

    lw   $ra, 8($sp)    # restore $ra from $stack
    addi $sp, $sp, 12   # move stack pointer back up to what it was when main called

    jr   $ra            # return from sum_product


product:                # product doesn't call other functions
                        # so it doesn't need to save any registers
    mul  $v0, $a0, $a1  # return argument * argument 2
    jr   $ra            #

2.8 函数调用时假设不变量:

if function changes $sp, $fp, $s0..$s8 it restores their value
callers assume $sp, $fp, $s0..$s8 unchanged by call (jal)

a function may destroy the value of other registers e.g. $t0..$t9
callers must assume value in e.g. t 0.. t0.. t0..t9 changed by call (jal)

Guess you like

Origin blog.csdn.net/weixin_42089190/article/details/120782924