连跳(和链接)怪异的MIPS汇编指令的行为 [英] Weird MIPS assembler behavior with jump (and link) instruction

查看:289
本文介绍了连跳(和链接)怪异的MIPS汇编指令的行为的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

所以,我们正在研究在学校的MIPS架构,我们正在实施一个MIPS32架构。我想我会使用GNU交叉的binutils作为汇编但说明JAL,J和JR打交道时,我越来越怪异的输出。汇编器似乎在错误的地方插入指令。我不知道为什么会这样,我怀疑MIPS汇编程序将是坏掉了,所以我想这是应该发生。

So, we're studying MIPS architecture at school and we're implementing a MIPS32 architecture. I thought I'd use GNU cross-binutils as assembler but I'm getting weird output when dealing with instructions jal, j and jr. The assembler seems to insert the instructions at the wrong places. I have no idea why this happens, and I doubt the MIPS assembler would be that broken, so I assume this is supposed to happen.

下面是我的虚拟装配文件:

Here is my dummy assembly file:

.section .text
.globl __start

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

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

然而,当我拆开我得到这样的输出:

However, when I disassemble I get this output:

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

这是一些建筑怪癖?如果是这样,什么是理这背后?

Is this some architectural quirk? If so, what is the rationale behind this?

编辑:
经测试加入一些NOP只是为了赫克...

Tested adding some nop's just for the heck ...

.section .text
.globl __start

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

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

和它给我的东西,似乎有点正确的。

and it gives me something that seems somewhat 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

为什么JAL和j的最后一个指令交换的地方?

Why are jal and j swapping places with the last instruction?

推荐答案

MIPS有明确的管道的危害;指令紧跟一个分支或跳转指令就一定会执行(该指令有时称为分支延迟槽)。如果你的code真的组装完全按照你写的:

MIPS has explicit pipeline hazards; the instruction immediately following a branch or jump instruction will always be executed (this instruction is sometimes referred to as the "branch delay slot"). If your code was really assembled exactly as you wrote it:

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

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

那么添加指令将围绕该 JAL 发生时执行两次:一次是在延迟槽,而一旦在当程序计数器变化实际上已经生效以下循环

then the add instruction would be executed twice around the time that the jal happens: once in the delay slot, and once on the following cycle when the program counter change has actually taken effect.

默认情况下,GNU汇编重新安排说明你:很显然,第二个阿迪必须执行,因此它可以用<$ C $互换C> JAL 指令,使阿迪移动到延迟槽。 (在汇编器不能推断它是安全做到这一点的情况下,它会插入 NOP 进入延迟槽来代替。)

By default, the GNU assembler reorders instructions for you: it is clear that the second addi must always be executed, so it can be swapped with the jal instruction, so that the addi moves into the delay slot. (In cases where the assembler can't deduce that it is safe to do this, it will insert a nop into the delay slot instead.)

如果你不希望它这样做重新排序为你添加指令

If you don't want it to do this reordering for you, add the directive

.set noreorder

在源文件的顶部。你必须应对灾害自己在这种情况下。如果你这样做,我建议注释的延迟槽,使他们脱颖而出 - 例如通过加入缩进一个额外的空间(或两个)。例如:

at the top of your source file. You must deal with the hazards yourself in this case. If you do this, I recommend annotating the delay slots so that they stand out - e.g. by adding an extra space (or two) of indentation. For example:

.set noreorder

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

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

这篇关于连跳(和链接)怪异的MIPS汇编指令的行为的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆