7

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

la $at, LabelAddr

扩展为:

lui $at, LabelAddr[31:16]
ori $at,$at, LabelAddr[15:0]

查看 MIPS64 指令集,我发现它lui仍然将 16 位立即数加载到 32 位字的上半部分。似乎没有任何类型的扩展指令将立即数加载到 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]

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

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

4

2 回答 2

3

我认为如果你需要加载很多常量,你应该把它放在当前代码附近的一个常量池(AKA “literal pool”)中,然后通过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

许多其他 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

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

于 2011-06-28T14:10:25.807 回答
0

地址,所以它让我确信我忽略了一些东西。我忽略了什么(如果有的话)?

您缺少的是,即使在 Mips64 中,指令大小也保持 32bit (4bytes)。在这个 32 位机器码编码系统中,翻译成 'lui' + 'ori' 组合的 'la' 可以处理最大 32 位值(地址)。4 字节机器指令中没有足够的位来轻松编码 64 位地址。为了处理 64 位地址,相同的更多迭代 (lui+ori) 与移位 (dsll) 一起使用。

派克西姆

于 2016-07-22T02:30:01.513 回答