参考资料说 la (加载地址)的伪代码被翻译为:
Pseudo : la $1, Label
lui $1, Label[31:16]
ori $1,$1, label[15:0]
但是当我尝试在 MARS 中组装代码时,我得到了错误:
“无效的语言元素:16]
如果我删除 [31:16] 部分,我会得到
“标签”:操作数的类型不正确
任何想法?
这意味着标签的 16 个最高有效位设置在 $1 中。然后,将 16 个较低有效位与 16 个最高有效位进行或运算。
在这里你可以找到 lui 指令的描述。它在寄存器上加载标签地址的 16 msb 位并将 16 lsb 归零。
这样,您可以使用 32 位指令加载 32 位地址(在 mips32 中)。
它绝不打算成为“真正的代码”。[31:16] / [15:0] 部分不是有效的 mips,仅供您了解位移动。
编辑:为了回应您的评论,您必须知道要使用 lui 指令加载的地址。为此,您可以使用标签来指示所需的地址。例如
.data
my_var: .asciiz "This is a nul terminated string"
.text
andi $a0,$a0,0x0000ffff
lui $a0,my_var
ori $a0,$a0,my_var
这是一个非常好的问题,我自己找到了一个可能的解决方案。上面的答案不是无条件的。
实际上,应该可以说您希望数据段位于何处(例如,SPIM 允许您这样做)。该.data
指令采用一个可选参数,即该数据段应位于的 32 位地址。以这种方式编写异常处理程序(仅使用.kdata
而不是.data
)。
一个例子:
.data 0x10001000 #remember this location
.align 0
.asciiz "MIPS IS GREAT!" #this is at offset 0
.text
.align 2
.globl main
main: #let's assume we've got no arguments
addiu $sp, $sp, -24 #subroutine prolog
sw $ra, 16($sp)
sw $fp, 10($sp)
addiu $fp, $sp, 20
ori $v0, $0, 4
lui $a0, 0x1000 #sole argument must be str pointer
ori $a0, $a0, 0x1000
syscall #print STR out on console
lw $ra, 16($sp) #subroutine epilog
lw $fp, 10($sp)
addiu $sp, $sp, 24
jal
我实际上不确定,这是否是最好的解决方案,但它是我能想到的唯一解决方案(即使不使用虚拟寻址模式,即加载或存储指令的标签)并且这个想法应该有效(我的代码示例是否有效,我不知道,我没有测试过)。
编辑:我刚刚玩过,发现了一个非常棒的技巧,它允许我们在没有任何伪指令和自然寻址模式的情况下将标签加载到寄存器中。我的例子:
.data 0x10001000
.word LABEL
LABEL: .asciiz "Get LABEL to print this C string."
.text
.align 2
.globl main
#test if it loads LABEL
main:
lui $4, 0x1000
ori $4, $4, 0x1000
lw $4, 0($4)
ori $2, $0, 4
syscall
在 SPIM 中,它组装得很好!查看 0x10001000 处的内存显示,0x10001004 被存储!这种方法在内存中创建一个指针。我建议将指针放在其他可变长度数据的前面,以便您可以轻松计算指针的偏移量。