在MIPS64中加载地址

JUS*_*ION 7 mips mips64

这可能是一个简单明了的事情,我只是没有看到,但如何在MIPS64处理器中加载地址?在MIPS32处理器中,以下汇编程序伪指令:

la $at, LabelAddr
Run Code Online (Sandbox Code Playgroud)

扩展到:

lui $at, LabelAddr[31:16]
ori $at,$at, LabelAddr[15:0]
Run Code Online (Sandbox Code Playgroud)

看一下MIPS64指令集,我看到lui仍然会在32位字的上半部分加载一个16位立即数.似乎没有任何类型的扩展指令将立即加载到64位字的上部区域.那么,似乎要做一个la伪指令的等价物,我需要扩展到代码中,例如:

lui $at, LabelAddr[63:48]
ori $at, $at, LabelAddr[47:32]
sll $at, 16
ori $at, $at, LabelAddr[31:16]
sll $at, 16
ori $at, $at, LabelAddr[15:0]
Run Code Online (Sandbox Code Playgroud)

这让我觉得有点......因为加载一个地址这样基本的东西令人费解,所以它让我确信我忽略了一些东西.

我忽略了什么(如果有的话)?

phu*_*clv 3

我认为如果你需要加载很多常量,你应该把它放在当前代码附近的常量池(又名“文字池”ld )中,然后通过指令加载它。

例如:$s0包含池的基地址,而你要加载的常量位于偏移量48处,你可以$t1通过指令加载它ld $t1, 48($s0)

这种技术在ARM中非常常见,其中指令只能加载 12 位立即数(只有更高版本的 ARM 可以加载 16 位立即数,但有一些限制)。Java中也使用它。

然而,不知何故,MIPS 编译器仍然总是生成多个指令来加载 64 位立即数。例如,要在 MIPS gcc 上加载 0xfedcba0987654321 使用

    li      $2,-9568256       # 0xffffffffff6e0000
    daddiu  $2,$2,23813
    dsll    $2,$2,17
    daddiu  $2,$2,-30875
    dsll    $2,$2,16
    daddiu  $2,$2,17185
Run Code Online (Sandbox Code Playgroud)

许多其他 RISC 架构有更有效的方法来加载立即数,因此它们需要更少的指令,但仍然至少 4 条。在这些情况下,指令缓存成本可能低于数据缓存成本,或者可能有人不喜欢这个想法

下面是MIPS上手写常量池的例子

# load pool base address
    dla $s0, pool
foo:
# just some placeholder
    addu $t0, $t0, $t1
bar:
# load from pool
    ld $a0, pool_foo($s0)
    ld $a1, pool_bar($s0)

.section pool
# macro helper to define a pool entry
.macro ENTRY label
pool_entry_\label\(): .quad \label
.equ pool_\label\(), pool_entry_\label - pool
.endm
ENTRY foo
ENTRY bar
Run Code Online (Sandbox Code Playgroud)

我未能说服任何 MIPS 编译器发出文字池,但这是 ARM 上编译器生成的示例