9

それで、私たちは学校で MIPS アーキテクチャを勉強していて、MIPS32 アーキテクチャを実装しています。GNU cross-binutils をアセンブラーとして使用すると思っていましたが、命令 jal、j、および jr を処理するときに奇妙な出力が得られます。アセンブラが間違った場所に命令を挿入しているようです。なぜこれが起こるのか私にはわかりません.MIPSアセンブラがそれほど壊れているとは思えないので、これが起こるはずだと思います.

ここに私のダミーアセンブリファイルがあります:

.section .text
.globl __start

__start:
   addi $a0, $0, 100
   addi $a1, $0, 200 
   jal test

test:
   add $v0, $a0, $a1
   jr $ra

ただし、逆アセンブルすると、次の出力が得られます。

Disassembly of section .text:

00000000 <__start>:
   0:   20040064    addi    a0,zero,100
   4:   0c000003    jal c <test>    <--- Why is jal coming before addi?
   8:   200500c8    addi    a1,zero,200

0000000c <test>:
   c:   03e00008    jr  ra  <--- Why is jr coming before add?
  10:   00851020    add v0,a0,a1
    ...

これは建築上の癖ですか?もしそうなら、これの背後にある理論的根拠は何ですか?

編集:念のためにいくつかのnopを追加してテストしました...

.section .text
.globl __start

__start:
   addi $a0, $0, 100
   addi $a1, $0, 200 
   nop
   jal test

test:
   add $v0, $a0, $a1
   nop
   jr $ra

そして、それは私にいくらか正しいと思われるものを与えてくれます。

Disassembly of section .text:

00000000 <__start>:
   0:   20040064    addi    a0,zero,100
   4:   200500c8    addi    a1,zero,200
   8:   0c000004    jal 10 <test>
   c:   00000000    nop

00000010 <test>:
  10:   00851020    add v0,a0,a1
  14:   03e00008    jr  ra
  18:   00000000    nop
  1c:   00000000    nop

jal と j が最後の命令で場所を交換するのはなぜですか?

4

1 に答える 1

12

MIPS には明示的なパイプラインの危険性があります。分岐またはジャンプ命令の直後の命令は常に実行されます (この命令は「分岐遅延スロット」と呼ばれることもあります)。あなたのコードがあなたが書いたとおりに実際に組み立てられた場合:

__start:
   addi $a0, $0, 100
   addi $a1, $0, 200 
   jal test

test:
   add $v0, $a0, $a1
   jr $ra

その場合、add命令は発生する前後に 2 回実行されます。1 回jalは遅延スロットで実行され、もう 1 回はプログラム カウンタの変更が実際に有効になった次のサイクルで実行されます。

デフォルトでは、GNU アセンブラーが命令を並べ替えます。2 番目の命令は常に実行する必要があることは明らかなので、命令addiと交換して、遅延スロットに移動できます。(アセンブラがこれを行うことが安全であると推測できない場合、代わりに a を遅延スロットに挿入します。)jaladdinop

この並べ替えを行わない場合は、ディレクティブを追加します

.set noreorder

ソースファイルの先頭に。この場合、自分で危険に対処する必要があります。これを行う場合は、遅延スロットが目立つように注釈を付けることをお勧めします。たとえば、余分なスペース (または 2 つ) のインデントを追加します。例えば:

.set noreorder

__start:
   addi $a0, $0, 100
   jal test
     addi $a1, $0, 200 

test:
   add $v0, $a0, $a1
   jr $ra
     nop
于 2010-09-27T23:15:02.517 に答える