【发布时间】:2020-04-21 20:40:13
【问题描述】:
我一直在阅读作为 MIPS 介绍的项目书,但遇到了一个问题。书中的一行代码是lb $t3, ($t2)。我不知道括号是做什么的,因为在此之前,我没有看到它们被使用过,而且这本书只是一开始就没有提到它们。为什么代码不只是lb $t3, $t2?
【问题讨论】:
标签: assembly mips addressing-mode
我一直在阅读作为 MIPS 介绍的项目书,但遇到了一个问题。书中的一行代码是lb $t3, ($t2)。我不知道括号是做什么的,因为在此之前,我没有看到它们被使用过,而且这本书只是一开始就没有提到它们。为什么代码不只是lb $t3, $t2?
【问题讨论】:
标签: assembly mips addressing-mode
MIPS 寻址模式语法是constant($reg)。
($t2) 允许作为 0($t2) 的特殊情况简写。相同的指令可以lb $t3, 13($t2) 将地址13 + $t2 的内存中的一个字节加载(和符号扩展)到寄存器$t3。
MIPS 唯一的寻址模式是reg + sign_extended_imm16;加载/存储指令(包括lb 和lbu)是I 型的。在0($t2) 中省略0 只是源代码级别的语法细节;机器代码仍然有 16 个零位来编码该常量零。
顺便说一句,我忽略了 MIPS 的索引 FP 加载/存储指令的存在,例如使用 2 个整数寄存器的 lwxc1。它们是 FP-only perhaps because 整数存储版本需要 3 个 GP 寄存器作为输入,但该寄存器文件否则只需要 2 个读取端口(用于标量管道)。 (并且架构师显然认为加载和存储之间的对称性比仅为加载提供 2 寄存器寻址模式更重要;这对于很多代码来说都很好且有用)。
在一些较新的 MIPS 版本中,还有lwpc 用于 PC 相对寻址。但是lw/lb/lbu等没有位来编码什么类型的寻址方式;它总是 reg + imm16。其他任何东西都需要不同的指令,而经典 MIPS 没有其他任何东西。
语义(对于 asm 文本语法的人类读者)是一个解引用操作,就像在 C 中 int t3 = *t2; 或 t2[0] 加载指向的值 (lb) 而不是int tmp = (int)p 将指针复制为整数 (move)。
() 始终是内存操作数,只能与加载或存储指令一起使用。裸寄存器不是内存寻址方式,不能作为第二个操作数来加载或存储指令。
加载/存储指令在寻址模式上需要括号是一件好事,这样您就不会混淆哪个操作数是地址,哪个是值。例如sw $t3, 12($t2) 将$t3 中的字存储到地址12+$t2 的内存字中。如果sw $t3, $t2 是有效的语法,您可能会忘记地址总是在 MIPS 上的内存指令的右侧(就像大多数 RISC 一样),即使其他指令都将目标作为第一个操作数。
这使它在视觉上与move $t3, $t2 更加不同。在代码块中发现加载和存储是很好的可视化操作。
如果您正在为 MIPS 汇编语言设计自己的语法或编写汇编程序,则可以将 lb $t3, $t2 作为 lb $t3, 0($t2) 的简写来合法化。但是 asm 语法是由汇编器(作者)定义的,而 MIPS 语法的设计者决定不这样做。
在此之前,我还没有看到它们被使用过,而且书上只是一开始就没有提到它们。
继续阅读;希望本书在首次介绍新语法后的一段时间内继续解释它。教程或书籍只向您展示一些代码作为示例而不停止解释所有内容是完全正常的,尤其是当解释是基于尚未涉及的概念时。
【讨论】:
在这种情况下,括号没有任何区别。
像lw 这样的一些指令可以使用寄存器值的立即偏移量,例如lw $t3, 16($t2)。这意味着将$t3 的内存内容加载到$t2 + 16。
【讨论】:
lb)是 I 型的。在0($t2) 中省略0 只是源代码级别的语法精巧;机器代码仍然有 16 个零位来编码该寻址模式。所有 MIPS 加载/存储指令都使用相同的语法,所以我不会说它们“没有区别”。 (顺便说一句,我忽略了使用 2 个整数寄存器的 MIPS 索引 FP 加载/存储指令的存在。FP 可能只是因为整数存储版本需要 3 个输入 GP 寄存器。)