【问题标题】:Simple MIPS Instructions and Compilers简单的 MIPS 指令和编译器
【发布时间】:2010-07-19 22:21:45
【问题描述】:

编译器(例如 gcc)生成将一些空内存元素加载到寄存器中的指令是否常见?就像... lw at,0(sp) where memory[sp + 0] = 0. 这基本上只是将 0 放入 $at ($R1.) 我问是因为我正在查看可执行文件的十六进制转储(可执行文件是编译 c++ 文件的结果),我正在手动验证它,如果我从 objdump 状态入口点开始,我会遇到执行此操作的指令。如果这只是一个常见的编译器操作,我不确定是否应该将其视为错误。将寄存器归零似乎是一种糟糕的方法。添加 $at,$0,$0 会更好。或 SLL $at,$0,$0..

入口点是 400890。最后 jal 的跳转目标是一个空的内存位置(告诉我可能有问题...)请注意,我之前的示例是故意仲裁的。

为了清楚起见,-32636+gp 是一个空的内存位置。如果您需要证据,我可以在此时发布内存内容:)。

00400890 <__start>:
  400890:   03e00021    move    zero,ra
  400894:   04110001    bal 40089c <__start+0xc>
  400898:   00000000    nop
  40089c:   3c1c0fc0    lui gp,0xfc0
  4008a0:   279c7864    addiu   gp,gp,30820
  4008a4:   039fe021    addu    gp,gp,ra
  4008a8:   0000f821    move    ra,zero
  4008ac:   8f848034    lw  a0,-32716(gp)
  4008b0:   8fa50000    lw  a1,0(sp)
  4008b4:   27a60004    addiu   a2,sp,4
  4008b8:   2401fff8    li  at,-8
  4008bc:   03a1e824    and sp,sp,at
  4008c0:   27bdffe0    addiu   sp,sp,-32
  4008c4:   8f878054    lw  a3,-32684(gp)
  4008c8:   8f888084    lw  t0,-32636(gp)<------ this instruction
  4008cc:   00000000    nop
  4008d0:   afa80010    sw  t0,16(sp)
  4008d4:   afa20014    sw  v0,20(sp)
  4008d8:   afbd0018    sw  sp,24(sp)
  4008dc:   8f998068    lw  t9,-32664(gp)
  4008e0:   00000000    nop
  4008e4:   0320f809    jalr    t9
  4008e8:   00000000    nop

Jal 目标是 4010c0。

4010c0: 8f998010    lw  t9,-32752(gp)
  4010c4:   03e07821    move    t7,ra
  4010c8:   0320f809    jalr    t9

【问题讨论】:

  • 我不熟悉 MIPS,但肯定是从堆栈中加载一个值 - 可能是一个函数参数,可能由运行时提供以提供命令行参数,如果这是程序条目观点。该值要到运行时才能知道,因此编译器不能假定它为零。
  • 我实际上是在运行时谈论这条指令。含义这将是程序入口点之后的指令 10 或其他内容,并且在此之前没有分配要从中加载的内存元素的指令。这告诉我,要么是故意的(应用不佳)nop,要么是可执行文件的一部分应该在 .text 部分之前加载。
  • 您可以添加更多上下文吗?也许在前后贴上 5-10 条指令?
  • 不是跳转到t9,不是t0吗? t9 是 -32664(gp),而不是 -32636+gp
  • “我正在手动验证它”。伙计,我不知道你的工作是什么,但它非常核心。

标签: c++ compiler-construction assembly mips


【解决方案1】:

也许它被放置在跳转语句之后?如果是这样,则该语句在跳转发生之前运行,并且可能是无操作指令(nop)。除此之外,它可能只是处于较低优化设置的编译器。另一种可能性是编译器保留了 CPU 标志字段。 Shift 和 Add 玩标志,而我不相信负载。

【讨论】:

  • 它实际上被放置在 ADDU 之后,然后是 LW。因为我禁用了加载延迟,所以我很确定目标寄存器实际上应该被分配一个非零值。但这意味着 readelf 和 objdump 定义的入口点实际上并不是必须执行的第一条指令。
  • 那么代码是否需要来自 ADDU 调用的标志?如果是这样,那可能解释了这项任务。另外,您使用的是什么优化级别?
  • 03 是我正在使用的优化。此外,当没有其他东西可以放在那里时,跳转/分支延迟槽被 nops 填充,正如您在显示的最后一条指令中看到的那样。
【解决方案2】:

这看起来像 CRT 代码。我认为这段代码正在将操作系统传递的一些参数加载到 $a0 和 $a1 寄存器中。可能在堆栈上传递了一些更大的结构,并且代码正在将该结构加载到正确的堆栈位置。 这段代码可能不是由 C 编译器生成的,而是在汇编中手工编码的。

【讨论】:

    猜你喜欢
    • 2019-01-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-18
    • 2018-05-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多