SPARC 汇编/SPARC 指令
以下是对编写 SPARC 代码时算术指令格式的快速概览
- 助记符 %rsrcA, srcB, %rdest
指令助记符(通常但不准确地也称为“操作码”)指定要执行的操作类型。rsrcA 是第一个操作数,而 srcB 是第二个操作数。rsrcA 必须是寄存器,srcB 通常可以是带符号的立即数(13 位)常量或第二个寄存器。rdest 是目标寄存器,并非所有指令都有目标寄存器(例如:cmp 用于比较)。
请注意,在 SPARC 汇编语言中,指令始终从左到右读取。左(如果有的话,还有中间)操作数是源操作数。如果操作将结果写入任何位置(几乎所有操作都会这样做),则结果将写入最右边的操作数(目标寄存器或目标内存位置)。
在 SPARC 汇编语言中,以下指令完全有效
add %r3, %r4, %r5
add %r3, 16, %r5
- 第一条指令将寄存器 3 和寄存器 4 相加,并将结果放在寄存器 5 中。
- 第二条指令将寄存器 3 和数字 16 相加,并将结果放在寄存器 5 中。
如您所见,SPARC 汇编在每个寄存器名称之前放置一个 % 符号,而数字文字则以普通方式写入。
警告:此语法与英特尔语法(在 PPC 芯片和一些编译器中使用)相反。
还应注意,许多 SPARC 指令(例如逻辑和算术指令)都有每个指令的版本,在助记符末尾附加了“cc”。这些指令执行与其非“cc”对应指令相同的功能,但还会设置条件代码(稍后会详细介绍),这些条件代码可用于在程序中控制分支。例如,上面提到的“add”指令有一个对应指令“addcc”,当执行加法时,它会设置特定的条件代码,这些条件代码会在后面的分支指令检查这些代码时决定是否要分支到程序的另一个部分。
注释不会被编译器读取,并且用感叹号表示。感叹号之后的该行上的任何内容都将被忽略。注释有助于您理解自己在做什么以及为什么要这样做。以下是一个注释的糟糕示例
sub %l0, %l3, %g1 ! Subtract local register 3 from l0, and put the result in global 1. ! add %g1, %l4, %g1! We should add in local 4, but I'm not doing that yet
我们可以轻松地知道我们在做什么;代码说明了这一点。注释没有告诉我们任何信息。
但是,这更好
sub %l0, %l3, %g1 ! Subtract our monthly expenses from our monthly income. ! This will later be used in function _foo. ! add %g1, %l4, %g1! Local 4 will hold "other" sources of income, but we're not there yet.
现在我们知道我们在做什么(我们在计算这个月的零钱),以及为什么要这样做(函数 foo 显然会使用这个)。此外,请注意这两个示例中的第二行都不会执行,因为它们的指令已被注释掉(显然是为了以后实现)。
请注意,许多人在汇编代码中几乎注释每一行代码,因为有时在没有像变量名称、复杂结构等有用内容的情况下,很难判断发生了什么。
标签通过在代码中的某个位置放置“label_name:”来表示。由于标签只是为编译器提供地址的区域,因此它们可以用于直接存储在程序中的任何内容:最常用的是,它们用于函数跳转(通过分支或调用语句),或引用常量变量的方法。如果它是函数而不是跳转,则必须在它之前放置“.global”。就像每种语言一样,有一个特殊的标签/全局,那就是“main”标签,程序从这里开始。
.global main main: save %sp, -64, %sp mov 5, %l0 cmp %l0, 5 be,a end ta 1 ! Should NEVER happen end: mov 1, %g1 ta 0
在这个程序中,有很多东西可能无法理解,但这是一个完整的程序。它从主函数开始(由“.global main”定义,后面跟着标签)。然后它将值“5”复制到本地寄存器中,然后将该寄存器与值“5”进行比较。如果它们相等,它会分支到标签 end,程序然后退出。