代码之家  ›  专栏  ›  技术社区  ›  Maister

带跳转(和链接)指令的奇怪MIPS汇编程序行为

  •  7
  • Maister  · 技术社区  · 14 年前

    所以,我们在学校学习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
    

    为什么日航和日本航空要用最后一条指令交换位置?

    1 回复  |  直到 14 年前
        1
  •  11
  •   Matthew Slattery    14 年前

    MIPS有明显的管道危险;总是执行紧跟在分支或跳转指令之后的指令(此指令有时被称为“分支延迟槽”)。如果你的代码真的是按照你写的那样组装的:

    __start:
       addi $a0, $0, 100
       addi $a1, $0, 200 
       jal test
    
    test:
       add $v0, $a0, $a1
       jr $ra
    

    然后 add 指令将在 jal 发生:在延迟槽中发生一次,在程序计数器更改实际生效的下一个周期中发生一次。

    addi 必须始终执行,以便可以与 日航 指示,以便 阿迪 移动到延迟槽中。(如果汇编程序不能推断这样做是安全的,它将插入一个 nop 而不是进入延迟槽。)

    .set noreorder
    

    在源文件的顶部。在这种情况下,你必须自己处理这些危险。如果您这样做,我建议您对延迟槽进行注释,以便它们突出显示—例如,添加一个(或两个)额外的缩进空间。例如:

    .set noreorder
    
    __start:
       addi $a0, $0, 100
       jal test
         addi $a1, $0, 200 
    
    test:
       add $v0, $a0, $a1
       jr $ra
         nop