Assembly 您必须在MIPS中初始化寄存器吗

Assembly 您必须在MIPS中初始化寄存器吗,assembly,mips,cpu-registers,x86,Assembly,Mips,Cpu Registers,X86,在用汇编语言编写函数时,是否需要将寄存器初始化为0 只是为了确保这些寄存器中没有以前程序中的值。一般来说,可能是的 程序启动时的寄存器状态取决于操作系统。例如,如果您运行的操作系统支持,那么寄存器$2、$29和$31在程序启动时具有有意义的值,而其他寄存器包含未指定的值-请参阅“进程初始化”部分 听起来你可能对程序和函数之间的区别感到困惑。psABI中还记录了一个函数在输入时的期望值-参见同一文档中的“函数调用顺序”部分-简短版本为$4-$7、$25、$28、$29、$31、$f12、$f13、

在用汇编语言编写函数时,是否需要将寄存器初始化为0


只是为了确保这些寄存器中没有以前程序中的值。

一般来说,可能是的

程序启动时的寄存器状态取决于操作系统。例如,如果您运行的操作系统支持,那么寄存器$2、$29和$31在程序启动时具有有意义的值,而其他寄存器包含未指定的值-请参阅“进程初始化”部分

听起来你可能对程序和函数之间的区别感到困惑。psABI中还记录了一个函数在输入时的期望值-参见同一文档中的“函数调用顺序”部分-简短版本为$4-$7、$25、$28、$29、$31、$f12、$f13、$f14和$f15可能包含有用的值,所有其他值都未指定,您必须确保在$16-$23中找到的值,输入时的$28、$29、$30和$f20-$f31在退出时保持不变(即,如果更改它们,则必须保存旧值并在退出前恢复它们;相反,如果您自己调用函数,则必须假设它在返回之前已用未指定的值覆盖所有其他寄存器)


如果您使用的操作系统不支持ELF psABI,那么您需要为您的操作系统找到相应的文档。在某个地方会有一些规范。可以想象,您必须对编译器进行反向工程才能获得它。

不,您不需要将它们归零,但您确实需要假设每个寄存器在函数/程序的条目上都包含随机垃圾,但包含输入的寄存器除外(例如函数参数)或者调用约定要求具有某种有用的值(例如堆栈指针)

通常情况下,这很好;你不需要“早”清除随机垃圾。如果你第一次使用寄存器是向它写东西,你不需要先写一个零,然后再写你真正想写的东西

但是,如果要将其用作计数器(即在循环中递增),则需要在循环之前将其归零。寄存器作为源操作数(而不仅仅是目标操作数)的任何其他用途也是如此


请注意,这是汇编语言中为数不多的几件事情之一,在每种体系结构的每种汇编语言中都是相同的

一些体系结构(如)具有带有隐式输入(如)的指令,但仍然只是在读取寄存器之前将其归零的情况


换句话说:每个寄存器都有一个值,所以第一次使用寄存器作为只写操作数没有什么特别之处

您只需确保代码的正确性不依赖于不需要具有任何特定值的任何寄存器或内存的内容


奖金阅读

就性能而言,这条规则很少有例外:在某些微体系结构中,并非所有只写操作都是相同的。有些实际上对输出的旧值有错误的依赖性使用一种廉价的打破依赖关系的方法来写入寄存器,可以让无序执行避免等待它不需要的“输入”,以防代码在长依赖关系链末尾(例如,涉及缓存未命中)可能使用该寄存器的某个对象后运行

我不知道任何MIPS示例(希望没有),因此我将使用x86作为示例:

对于将结果放入向量寄存器低位元素的int->float指令(例如),英特尔采取了短视的方法,将其设计为合并到目标向量中,而不是将目标的其余部分归零。第一代拥有SSE的CPU是英特尔奔腾III,它只有64位向量执行单元。我认为将向量的上64位归零会花费额外的uop,或者至少在内部需要convert指令来生成向量的两半作为输出,而不仅仅是修改后的下半部分

int->float转换的绝大多数用例只希望将float作为标量,而不是插入到另一个向量中,因此对目标寄存器的依赖可能是有害的。gcc在运行CVTSI2SS之前通过将目标XMM寄存器归零来避免这种情况。这种额外的归零指令即使在最新的CPU上也不是完全免费的:它需要代码大小和前端带宽。因此,每次int->float转换的额外成本通常非常小,以避免在不可预测的情况下,当两个原本独立的依赖链由同一寄存器上的输入依赖项链接时出现罕见但可能较大的减速

此外,/LZCNT/TZCNT的目标寄存器在体系结构上是只写的,而不是Intel的实现。因此,在运行POPCNT之前将目标寄存器归零确实是有意义的,如果有必要的话,可以避免意外地创建循环携带的依赖链


请参见gcc在.p>上的popcnt和int->float转换之前插入额外的xor归零指令的示例,以不获取所有重言式,而仅获取重要的值。所以,任何关于“我是否需要初始化这个”的问题本质上取决于上下文。