Question

Alors, nous étudions l'architecture MIPS à l'école et nous mettons en œuvre une architecture MIPS32. Je pensais utiliser croisées binutils GNU comme assembleur mais je suis en train de sortie bizarre quand les instructions concernant jal, j et jr. L'assembleur semble insérer les instructions aux mauvais endroits. Je ne sais pas pourquoi cela arrive, et je doute que l'assembleur MIPS serait que cassé, donc je suppose que cela est censé se produire.

Voici mon fichier de montage fictif:

.section .text
.globl __start

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

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

Cependant, quand je démonte je reçois cette sortie:

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
    ...

Est-ce une bizarrerie architecturale? Si oui, quelle est la raison derrière tout cela?

EDIT: Testé en ajoutant quelques années NOP juste pour le diable ...

.section .text
.globl __start

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

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

et il me donne quelque chose qui semble un peu correct.

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

Pourquoi les lieux et j échange jal avec la dernière instruction?

Était-ce utile?

La solution

MIPS a explicitement les risques de pipeline; l'instruction qui suit immédiatement une branche ou d'une instruction de saut sera toujours exécuté (cette instruction est parfois appelée la « fente de retard de branche »). Si votre code a été vraiment assemblé exactement comme vous l'avez écrit:

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

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

alors l'instruction de add serait exécuté deux fois autour du moment où le jal arrive. Une fois dans la fente de retard, et une fois sur le cycle suivant lorsque le changement de compteur de programme a effectivement pris effet

Par défaut, l'assembleur GNU réordonne instructions pour vous: il est clair que la deuxième addi doit toujours être exécuté, il peut donc être échangé avec l'instruction jal, de sorte que les mouvements de addi dans la fente de retard. (Dans les cas où l'assembleur ne peut pas en déduire qu'il est sûr de le faire, il va insérer un nop dans la fente de retard à la place.)

Si vous ne voulez pas faire ce réordonnement pour vous, ajoutez la directive

.set noreorder

en haut de votre fichier source. Vous devez faire face aux risques vous-même dans ce cas. Si vous faites cela, je recommande annoter les fentes de retard afin qu'ils se démarquent - par exemple en ajoutant un espace supplémentaire (ou deux) de l'indentation. Par exemple:

.set noreorder

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

test:
   add $v0, $a0, $a1
   jr $ra
     nop
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top