2

我知道如何在 MIPS 中创建一个接受 4 个参数的函数,因为我知道我可以将参数放入寄存器 $a0-$a3 中。但是假设你想要超过 4 个参数,你如何绕过 MIPS 中只有 4 个参数寄存器($a0-$a3)的事实?

4

1 回答 1

2

有几种不同的方法可以做到这一点,每种方法都有自己的权衡:(1) 使用 mips ABI,(2) 使用您自己的内部寄存器约定,或 (3) 使用类似 C 的结构


mips ABI:

mips ABI [与大多数其他拱门一样],当您用完参数寄存器时,剩余的参数将被压入堆栈。

考虑以下 C 程序:

void
callee(int a,int b,int c,int d,int e,int f)
{
}

void
caller(void)
{
    int a;
    int b;
    int c;
    int d;
    int e;
    int f;

    callee(a,b,c,d,e,f);
}

mips ABI 等效项如下所示:

caller:
    addiu   $sp,$sp,-8              # space for e,f

    lw      $t0,f
    sw      $t0,4($sp)

    lw      $t0,e
    sw      $t0,0($sp)

    lw      $a3,d
    lw      $a2,c
    lw      $a1,b
    lw      $a0,a

    jal     callee
    addiu   $sp,$sp,8               # remove space for e,f

    jr      $ra

callee:
    addiu   $sp,$sp,-4
    sw      $ra,0($sp)

    move    $t0,$a0                 # get a
    move    $t1,$a1                 # get b
    move    $t2,$a2                 # get c
    move    $t3,$a3                 # get d
    lw      $t4,4($sp)              # get e
    lw      $t5,8($sp)              # get f

    # ...

    lw      $ra,0($sp)
    addiu   $sp,$sp,4
    jr      $ra

自带功能:

如果你的函数是自包含在程序中的[即你没有调用外部 ABI 兼容函数],你可以在任何你想要的寄存器中传递参数:

caller:
    lw      $s7,f
    lw      $s6,e

    lw      $a3,d
    lw      $a2,c
    lw      $a1,b
    lw      $a0,a

    jal     callee

    jr      $ra

callee:
    addiu   $sp,$sp,-4
    sw      $ra,0($sp)

    move    $t0,$a0                 # get a
    move    $t1,$a1                 # get b
    move    $t2,$a2                 # get c
    move    $t3,$a3                 # get d
    move    $t4,$s6                 # get e
    move    $t5,$s7                 # get f

    # ...

    lw      $ra,0($sp)
    addiu   $sp,$sp,4
    jr      $ra

使用 C 结构:

就像在 C 中一样,你可以在一个结构体中传递很多东西:

struct args {
    int a;
    int b;
    int c;
    int d;
    int e;
    int f;
};

void
callee(struct args *av)
{
    int tmp;

    tmp = av->a;
    tmp = av->b;
    tmp = av->c;
    tmp = av->d;
    tmp = av->e;
    tmp = av->f;
}

void
caller(void)
{
    struct args args;

    args.a = 1;
    args.b = 2;
    args.c = 3;
    args.d = 4;
    args.e = 5;
    args.f = 6;

    callee(&args);
}

C 结构的 asm 等价物是使用 equates 来偏移基址寄存器:

# offsets within "struct"
a = 0
b = 4
c = 8
d = 12
e = 16
f = 20

caller:
    la      $a0,args

    li      $t0,1
    sw      $t0,a($a0)

    li      $t0,2
    sw      $t0,b($a0)

    li      $t0,3
    sw      $t0,c($a0)

    li      $t0,4
    sw      $t0,d($a0)

    li      $t0,5
    sw      $t0,e($a0)

    li      $t0,3
    sw      $t0,f($a0)

    jal     callee

    jr      $ra

callee:
    addiu   $sp,$sp,-4
    sw      $ra,0($sp)

    lw      $t0,a($a0)              # get a
    lw      $t1,b($a0)              # get b
    lw      $t2,c($a0)              # get c
    lw      $t3,d($a0)              # get d
    lw      $t4,e($a0)              # get e
    lw      $t5,f($a0)              # get f

    # ...

    lw      $ra,0($sp)
    addiu   $sp,$sp,4
    jr      $ra
于 2016-06-08T19:36:30.793 回答