2

レジスタ $a0-$a3 に引数を入れるだけでよいことを知っているので、MIPS で 4 つの引数を取る関数を作成する方法を知っています。しかし、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 struct に相当する asm は、ベース レジスタからのオフセットに等号を使用することです。

# 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 に答える