You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何mipsel-linux-gnu-as未将sw指令填入跳转延迟槽?

MIPS延迟槽优化问题解析

环境信息

使用的编译器版本:

mipsel-linux-gnu-gcc (GCC) 12.2.0
Copyright (C) 2022 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

汇编源代码

.global __start
__start:
        lw $10,array
        lw $11,array+4
        add $12, $10, $11
        sw $12,array+8
        j __start
array:
    .word 1
    .word 2
    .word 0

汇编与链接命令

mipsel-linux-gnu-as -mips2 asm/start.asm -o obj/start.asm.o 
mipsel-linux-gnu-ld -o final obj/start.asm.o  -Tlinker_script.ld

链接脚本内容

MEMORY
{
    SRAM (rwx) : ORIGIN = 0x100000, LENGTH = 0x60000
}

SECTIONS
{
    .text :
    {
        *(.text)
    } > SRAM

    .data : 
    {
        *(.data)
    } > SRAM

    .bss : 
    {
        *(.data)
    } > SRAM
}

.text段反汇编结果

mipsel-linux-gnu-objdump -j .text -D final           

final:     file format elf32-tradlittlemips


Disassembly of section .text:

00100000 <__start>:
  100000:       3c0a0010        lui     t2,0x10
  100004:       8d4a0024        lw      t2,36(t2)
  100008:       3c0b0010        lui     t3,0x10
  10000c:       8d6b0028        lw      t3,40(t3)
  100010:       014b6020        add     t4,t2,t3
  100014:       3c010010        lui     at,0x10
  100018:       ac2c002c        sw      t4,44(at)
  10001c:       08040000        j       100000 <__start>
  100020:       00000000        nop

00100024 <array>:
  100024:       00000001        0x1
  100028:       00000002        srl     zero,zero,0x0
  10002c:       00000000        nop

问题解答

你的理解完全正确,sw指令确实可以放到j的延迟槽中。汇编器填充nop不是伪指令的限制,而是因为mipsel-linux-gnu-as(GNU汇编器)的默认行为——它只做最基础的汇编工作,不会自动调整指令顺序做延迟槽优化。

GNU汇编器是"直通式"工具,严格按照你写的指令顺序生成机器码,只会在必须填充的时候(比如跳转指令的延迟槽)放nop,不会主动帮你调度指令。要实现延迟槽优化,有两种办法:

  • 手动调整代码顺序:把sw放到j指令的后面(也就是延迟槽的位置),代码改成这样:
    .global __start
    __start:
            lw $10,array
            lw $11,array+4
            add $12, $10, $11
            j __start
            sw $12,array+8  # 这行作为延迟槽指令
    array:
        .word 1
        .word 2
        .word 0
    
    这样汇编器就会把sw当作延迟槽指令执行,不会再填充nop。
  • 用gcc带优化编译:如果是写C代码,直接用gcc -O2编译,编译器会自动做指令调度优化延迟槽;如果是写汇编,用gcc -c -O2编译汇编文件,gcc的汇编前端会帮你完成指令调度。

另外需要确认:这个场景下把sw放到延迟槽是安全的——MIPS延迟槽指令在跳转指令取出时就会执行,而sw只依赖add的结果,和跳转目标没有任何依赖关系,不会产生错误。

内容的提问来源于stack exchange,提问作者Cheiron

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 20:17:49