4

ローカル変数 x が 1 つしかない関数 f の MIPS アセンブリ コードを調べているとします。

void f(void) {
int x;
...
}

2 つの質問があります。

  1. f の関数プロローグとエピローグは、レジスタ $sp、$ra、および $fp に対して何を行いますか? $ra と $fp が、関数によって変更される唯一の呼び出し先保存レジスタであると仮定します。

  2. f の MIPS アセンブリ コードは変数 x にどのようにアクセスしますか。

私の試み: 関数プロローグはレジスタ $ra と $fp をコール スタックに保存します。関数エピローグは、これらのレジスタをスタックからポップして復元し、制御を $ra のアドレスに戻します。MIPS が変数 x にアクセスする方法はわかりませんが、ローカル変数もスタックに格納されていることはわかっています。

4

3 に答える 3

6

(a) f の関数プロローグとエピローグは、レジスタ $sp、$ra、および $fp に対して、関数によって変更される唯一の呼び出し先保存レジスタが $ra と $fp であると仮定して、何を行いますか。

( $fpは「ベース ポインター」とも呼ばれる「フレーム ポインター」、$spは「スタック ポインター」、および$raは「リターン アドレス」です)

' int x ' がどのようにアクセスされるかを説明するには、それがどこにどのように格納されているかを知ることが重要です。' int x ' はローカル変数であるため、MIPS は 32 ビット整数のバイト数 (4) を差し引いて、スタック上の整数に適切なスペースを割り当てます (または、スペースがある場合は、markgz が話していたメソッドを使用します)。スタックポインタから。関数が呼び出し元にリンクできるように、呼び出し元の戻りアドレスも保存されます (さらに 4 バイト)。

sub $sp, $sp, 8   #4 bytes for $ra + 4 bytes for 'int x' = 8 bytes allocated
sw $ra, 4($sp)    #note the order, $ra is always first
sw [int x], 0($sp)

また

addi $sp, $sp, -8  #an alternate to the code above
sw $ra, 4($sp)
sw [int x], 0($sp)

同様に、関数呼び出しの最後に、関数はスタック上のスペースの割り当てを解除することにより、呼び出し元にレジスタを復元します。

lw [int x], 0($sp)
lw $ra, 4($sp)
addi $sp, $sp, 8

フレーム ポインター ( $fp )の使用経験はあまりありませんが、スタック ポインター ( $sp ) が手順中に値を変更すると、参照ポイントとして使用できなくなるため、( $fp ) はそれは場所です($ spは単なる別のレジスタです)。

(b) f の MIPS アセンブリ コードは変数 x にどのようにアクセスしますか。

' int x ' にアクセスするには、関数 ' f ' で変数を一時レジスタにロードできます。

lw $t0, 0($sp)  #it can be any temporary register

ローカル変数は関数呼び出し間で保持されないため、一時レジスタに格納できます。基本的に、' push ' 命令は ' sw ' ('store word') になり、' pop ' 命令は ' lw ' ('load word') になります。

また、MIPS が面倒な場合があることも知っていますが、このリファレンス シートは本当に役に立ちました。

于 2012-06-14T22:44:49.473 に答える
0

ここでMIPS呼び出し規約を見てください。通常、関数内のローカル変数は、一時的な(呼び出し元が保存された)レジスタ$ t0〜$t9に保持されます。関数自体が関数を呼び出す場合、ローカル変数はスタックに保存されます。

pushMIPSにはまたは命令がないpopため、関数プロローグは、関数のスタックストレージのニーズをすべて満たすのに十分なワードだけスタックポインターをデクリメントし、関数エピローグはこれを元に戻します。

于 2012-06-14T20:47:56.983 に答える
0

f の関数プロローグとエピローグは、レジスタ $sp、$ra、および $fp に対して何を行いますか? $ra と $fp が、関数によって変更される唯一の呼び出し先保存レジスタであると仮定します。

$sp- スタック ポインタ $fp- フレーム ポインタ $ra- リターン アドレス

関数のプロローグとエピローグは、関数の開始時に戻りアドレス レジスタ (および必要に応じてその他のレジスタ) をスタックに保存し、関数の終了時にそれぞれのレジスタに値を返すことを指します。

お気づきかもしれませんが、MIPS アーキテクチャにはスタックがありません。スタックを作成する必要があります (使用しているシミュレータまたは特定のプロセッサのマニュアルを参照してください。このために招集されるアドレスはさまざまです)。

$sp で指定されたアドレスをメイン プログラムに保存します。

daddi $sp, $sp, 0x400 # this is the convention address for WinMIPS64's stack 

たとえば、次のようないくつかの理由でスタックを使用する場合があります。

  • $raネストされた関数の場合にリターン アドレス レジスタ ( ) を保存する
  • については$fp、質問に従って
  • $s0-$s7関数で使用する場合にレジスタを保存します。慣例により、これらは使用時に常にスタックに保存する必要があります (この場合は適用されませんが、他の誰かがこれを読んでいる可能性があるため)。

これを行うには、上記のユーザーが行ったようにコードを使用します (コードは、使用している MIPS のバージョンによって若干異なる場合があります。マニュアルを確認してください)。

スタックに PUSH するには、上記のコードを使用してスタック関数をエミュレートする必要があります (データ用のスペースを作成し、データをスタックに保存します)。上記のようにスタックに PUSH した場合、同じ量を POP して$sp元の位置に戻す必要があることに注意してください。これを逆の順序で行います (上記のユーザーが示すように)。

また、MIPS の関数の呼び出し命令 (jal f - jump and link) はリターン アドレスを単一のレジスタに自動的に保存するため ( $ra- リターン アドレス、覚えていますか?)、再帰を使用している場合や、最初の関数から 2 番目の関数を呼び出すと、メイン プログラムへのリターン アドレスが失われます。

$fpフレーム ポインタである$sp. $spこれを行うには、の値をロードして$fpから、移動するための変位値を追加します。

同じ場所に保持しながらスタックから値をロードできる$spため、プッシュ操作とポップ操作を追跡できます。

f の MIPS アセンブリ コードは変数 x にどのようにアクセスしますか。

慣例により、MIPS には引数と戻り値用の特定のレジスタがあります。MIPS では、関数に渡される引数は register に保存され$a0-$a3、戻り値は に保存され$v0-$v1ます。関数内で使用できる一時レジスタは使用できますが$t0-$t9、関数からの戻り時に値を保持しません。ただし、レジスタが不足する可能性があるため、スタックを使用する必要がある場合があります。慣例により、値はスタックを使用して保存される$s0-$s7保存レジスタです。

PS重要: WinMIPS64 シミュレーターを使用しています。MIPS アセンブリ言語は、レジスタ サイズ、命令セット、およびスタック アドレスが異なります。コードに影響するため、特定のバージョンのマニュアルを参照し、どの値がケースに適用されるかを確認してください。

于 2019-11-10T15:32:12.547 に答える