在 MIPS64 中加载地址
这可能是一件简单、明显的事情,我只是没有看到,但如何在 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]
这让我觉得有点……对于像加载这样基本的东西来说有点复杂一个地址,所以它让我确信我忽略了一些东西。
我忽略了什么(如果有的话)?
This is probably a simple, obvious thing I'm just not seeing, but how do I load an address in a MIPS64 processor? In a MIPS32 processor the following assembler pseudo-instruction:
la $at, LabelAddr
Expands into:
lui $at, LabelAddr[31:16]
ori $at,$at, LabelAddr[15:0]
Looking at the MIPS64 instruction set, I see that lui
still loads a 16-bit immediate into the upper half of a 32-bit word. There doesn't appear to be any kind of expanded instruction that loads an immediate anywhere into the upper area of a 64-bit word. This seems, then, that to do the equivalent of an la
pseudo-instruction I'd need to expand into code something like:
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]
This strikes me as a bit ... convoluted for something as basic as loading an address so it leaves me convinced that I've overlooked something.
What is it I've overlooked (if anything)?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我认为如果您需要加载很多常量,您应该将其放入常量池(又名"literal pool") 靠近当前代码,然后通过 ld 指令加载它。
例如:
$s0
包含池的基地址,而你要加载的常量位于偏移量48处,你可以通过指令将其加载到
$t1
ld $t1, 48($s0)这种技术在 ARM,其中指令只能加载 12 位立即数(只有更高版本的 ARM 可以加载 16 位立即数,但有一些限制)。它也用于 Java 中。
然而不知何故,MIPS编译器仍然总是生成多个指令来加载 64 位立即数。例如,在 MIPS gcc 上加载 0xfedcba0987654321 使用
许多其他 RISC 架构有更有效的方法来加载立即数,因此它们需要更少的指令,但仍然至少 4。在这些情况下,指令缓存成本可能低于数据缓存成本,或者可能有人只是不喜欢这个想法
这是 MIPS 上手写常量池的示例
我未能说服任何 MIPS 编译器发出文字池,但是 这是编译器生成的示例ARM
I think if you need to load a lot of constants, you should put it in a constant pool (A.K.A "literal pool") near the current code and then load it by an
ld
instruction.For example:
$s0
contains the pool's base address, and the constant you want to load is at offset 48, you can load it to$t1
by the instructionld $t1, 48($s0)
This technique is very common in ARM, where instructions could only load a 12-bit immediate (only later versions of ARM can load 16-bit immediates with some restrictions). And it is used in Java too.
However somehow MIPS compilers still always generate multiple instructions to load a 64-bit immediate. For example to load 0xfedcba0987654321 on MIPS gcc uses
Many other RISC architectures have more efficient ways to load an immediate so they need less instructions, but still at least 4. Maybe the instruction cache cost is lower than data cache cost in those cases, or maybe someone just don't like that idea
Here's an example of handwritten constant pool on MIPS
I failed to persuade any MIPS compilers to emit a literal pool but here's a compiler-generated example on ARM
您缺少的是,即使在 Mips64 中,指令大小仍为 32 位(4 字节)。在这个32位机器代码编码系统中,翻译为“lui”+“ori”组合的“la”最多可以处理32位值(地址)。 4 字节机器指令中没有足够的位来轻松编码 64 位地址。为了处理 64 位地址,需要使用相同的更多迭代 (lui+ori) 以及移位 (dsll)。
帕克希姆
What you are missing is that even in Mips64 the instruction size stays 32bit (4bytes). In this 32bit machine code encoding system, The 'la' translated to 'lui' + 'ori' combination can handle a max of 32 bit value (address). There are not enough bits in the 4byte machine instruction to easily encode a 64bit address. To deal with 64bit address, more iterations of the same (lui+ori) is used along with shifts (dsll).
Paxym