这可能是一个简单明了的事情,我只是没有看到,但如何在MIPS64处理器中加载地址?在MIPS32处理器中,以下汇编程序伪指令:
la $at, LabelAddr
扩展为:
lui $at, LabelAddr[31:16]
ori $at,$at, LabelAddr[15:0]
查看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]
这让我觉得有点......因为加载一个地址这样基本的东西令人费解,所以它让我确信我忽略了一些东西。
我忽略了什么(如果有的话)?
答案 0 :(得分:3)
我认为如果你需要加载很多常量,你应该把它放在当前代码附近的常量池(AKA "literal pool")中然后通过ld
指令加载它。
例如:$s0
包含池的基址,要加载的常量为偏移量48,您可以通过指令$t1
将其加载到ld $t1, 48($s0)
这种技术在ARM中很常见,其中指令只能加载12位立即数(只有更高版本的ARM可以加载16位立即数,但有一些限制)。它也在Java中使用。
然而,某些MIPS编译器仍然总是generate multiple instructions to load a 64-bit immediate。例如,在MIPS上加载0xfedcba0987654321 gcc使用
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.在这些情况下,指令缓存成本可能低于数据缓存成本,或者有人可能不喜欢那个想法
Here's an example of handwritten constant pool on 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编译器发出文字池但是here's a compiler-generated example on ARM
答案 1 :(得分:0)
解决这个问题让我确信我忽视了一些事情。 我忽略了什么(如果有的话)?
您缺少的是,即使在Mips64中,指令大小仍为32位(4字节)。在这个32位机器码编码系统中,The' la'翻译成' lui' +' ori'组合可以处理最大32位值(地址)。 4字节机器指令中没有足够的位来轻松编码64位地址。为了处理64位地址,使用相同(lui + ori)的更多迭代以及移位(dsll)。
Paxym