MIPS加载地址la并不总是使用寄存器$ 1?

请参阅编辑部分以获取我的解释。

这有点长,很难说明。 但我很欣赏花时间阅读本文。 请多多包涵。

假设我有这个:

.data
    str1: .asciiz "A"
    str2: .asciiz "1"
    myInt:
          .word 42      # allocate an integer word: 42
    myChar:
          .word 'Q'     # allocate a char word

    .text    
    .align 2
    .globl main

main:
    lw      $t0, myInt          # load myInt into register $t0

    lw      $t3, str1           # load str1 into register $t3

    lw      $t4, str2           #load str2 into register $t4

    la      $a0, str1           # load address str1

    la      $a1, str2           # load address str2

然后在SPIM中,用户文本段为

User Text Segment [00400000]..[00440000]
[00400000] 8fa40000  lw $4, 0($29)            ; 183: lw $a0 0($sp) # argc 
[00400004] 27a50004  addiu $5, $29, 4         ; 184: addiu $a1 $sp 4 # argv 
[00400008] 24a60004  addiu $6, $5, 4          ; 185: addiu $a2 $a1 4 # envp 
[0040000c] 00041080  sll $2, $4, 2            ; 186: sll $v0 $a0 2 
[00400010] 00c23021  addu $6, $6, $2          ; 187: addu $a2 $a2 $v0 
[00400014] 0c100009  jal 0x00400024 [main]    ; 188: jal main 
[00400018] 00000000  nop                      ; 189: nop 
[0040001c] 3402000a  ori $2, $0, 10           ; 191: li $v0 10 
[00400020] 0000000c  syscall                  ; 192: syscall # syscall 10 (exit) 
[00400024] 3c011001  lui $1, 4097             ; 23: lw $t0, myInt # load myInt into register $t0 
[00400028] 8c280004  lw $8, 4($1)             
[0040002c] 3c011001  lui $1, 4097             ; 25: lw $t3, str1 # load str1 into register $t3 
[00400030] 8c2b0000  lw $11, 0($1)            
[00400034] 3c011001  lui $1, 4097             ; 27: lw $t4, str2 #load str2 into register $t4 
[00400038] 8c2c0002  lw $12, 2($1)            
[0040003c] 3c041001  lui $4, 4097 [str1]      ; 29: la $a0, str1 # load address str1 
[00400040] 3c011001  lui $1, 4097 [str2]      ; 31: la $a1, str2 # load address str2 
[00400044] 34250002  ori $5, $1, 2 [str2]   

我知道lw是一个伪代码,所以需要将它分解为两条指令。 我理解这部分。 我们使用数据段的入口地址作为“基址指针”并相对访问其他数据(包括第一个数据)。

我还观察到str1str2的加载地址使用了两个不同的寄存器: $ 4$ 1 。 $ 4是$ a0。 这是为什么?

如果我交换了最后两条指令,在SPIM上我可以看到

...        
[0040003c] 3c011001  lui $1, 4097 [str2]      ; 31: la $a1, str2 # load address str2 
[00400040] 34250002  ori $5, $1, 2 [str2]     
[00400044] 3c041001  lui $4, 4097 [str1]      ; 32: la $a0, str1 # load address str1

那么,为什么加载地址很奇怪呢? 为什么str2使用$ 1 ? 我怎样才能解释lui $ 1,44097 [str2]和lui $ 4,4097 [str1]是如何不同的?

PS:有人可以向我解释为什么我们需要括号[str2]吗?

lui,$ 1,4097,[str2]只推送数据段的入口地址来注册$ 1。 即0x10010000。

非常感谢你!


编辑

我重写了整个脚本以简化情况。

脚本:http://pastebin.com/BHh89iqt文字细分:http://pastebin.com/t2eDEs1f

让我提醒你我们用伪指令编写,而不是真正的MIPS机器代码。 也就是说, “lw”,“jal”,“addi”等都是伪指令。

例如,lw(加载词)分解为两个机器指令(查看文本分段):

lui $1, 4097             ; 23: lw $t0, myInt # load myInt into register $t0 
lw $8, 4($1)

MIPS是32位的,因此我们将其分解为两条指令。 寻址32位地址的总数将产生43位指令集。这就是为什么我们分解成2部分的原因。 标签是指向我们分配的东西的内存地址。

MIPS只能读取lw $ rt,offset($ rs)形式的指令。 因此,大多数加载指令都遵循这种方法,并使用$ at将涉及标签的伪指令转换为MIPS机器指令。

这很简单。 对于la load address来说有点棘手。 请注意最后四条加载地址指令。 MIPS将它们转换为:

[0040003c] 3c041001  lui $4, 4097 [str1]      ; 27: la $a0, str1 # load address str2 
[00400040] 3c011001  lui $1, 4097 [str2]      ; 28: la $a0, str2 # load address str1 
[00400044] 34240002  ori $4, $1, 2 [str2]     
[00400048] 3c011001  lui $1, 4097 [str2]      ; 30: la $a0, str2 # load address str2 
[0040004c] 34240002  ori $4, $1, 2 [str2]     
[00400050] 3c041001  lui $4, 4097 [str1]      ; 31: la $a0, str1 # load address str1 

$ 4是指$ a0。 如果您查看说明,我交换了前两个加载指令,结果是最后两条指令。 我故意这样做来说明奇怪的行为:在交换之前,lui使用$ 4来存储str1的地址,但是如果我想要加载str2的地址,我将使用$ at,然后应用偏移量。

我无法弄清楚为什么昨天晚上,刚才我意识到这样做是因为编译器足够聪明,知道str1是数据段中的第一个数据,所以不需要转换任何东西。

然而,这也很奇怪,因为编译器如何知道在哪个字节停止打印字符串? (如果我们想打印一个字符串......)

我的猜测是:空字符来终止打印。

无论如何。 我想这只是MIPS使用的一个约定。


第二编辑

事实上,如果你只是在str1之上添加一个新数据,你会发现我的解释是正确的。

新脚本:http://pastebin.com/8DuzFrk0

新的文本段:http://pastebin.com/YXbvzc4z

我只将myCharB添加到数据段的顶部。

[0040003c] 3c011001  lui $1, 4097 [str1]      ; 29: la $a0, str1 #
load address str2
[00400040] 34240004  ori $4, $1, 4 [str1]
[00400044] 3c011001  lui $1, 4097 [str2]      ; 30: la $a0, str2 #
load address str1
[00400048] 34240006  ori $4, $1, 6 [str2] 

我还观察到str1和str2的加载地址使用了两个不同的寄存器:$ 4和$ 1。 $ 4是$ a0。 这是为什么?

那么,谁在乎? xD这是内部SPIM实现,只要不破坏MIPS ABI,就可以使用任何寄存器。 我只是建议你不要太依赖伪指令来确定哪些寄存器已经改变/它们保存了什么值。 通常LW不是一个伪指令,但是就像你使用它的方式一样。

有人可以向我解释为什么我们需要括号[str2]吗?

你不需要任何括号。 这只是程序员为了显示此指令正在加载str2地址的SPIM信息。 这不是大会的一部分。

lui,$ 1,4097,[str2]只推送数据段的入口地址来注册$ 1。 即0x10010000

实际上它只加载了1美元的上半部分。 恰好发生的是低半字是纯粹的零。 请记住,LUI不会修改较低的半字,因此您必须确保它保存您想要的值(重置寄存器或使用LI)。

然而,这也很奇怪,因为编译器如何知道在哪个字节停止打印字符串? (如果我们想打印一个字符串......)

无效终止,正如你猜对的那样。

我想这只是MIPS使用的一个约定。

这比MIPS更古老。 MIPS没有对此做任何定义,或者是其他架构。 这是数据处理,它在OS的上层定义。 在这种情况下,它自己的系统调用是SPIM约定。 无论如何,以null结尾的字符串很常见。 C编程语言对字符串使用如此。

链接地址: http://www.djcxy.com/p/19205.html

上一篇: MIPS load address la doesn't always use register $1?

下一篇: Load half word and load byte in a single cycle datapath