基本指令

栈调整

intel 或 AT&T 汇编提供了 push 和 pop 指令族,plan9 中没有 push 和 pop,栈的调整是通过对硬件 SP 寄存器进行运算来实现的,例如:

数据搬运

常数在 plan9 汇编用 $num 表示,可以为负数,默认情况下为十进制。可以用 $0x123 的形式来表示十六进制数。
plan9 的汇编的操作数的方向是和 intel 汇编相反的,与 AT&T 类似。

常见计算指令

类似数据搬运指令,同样可以通过修改指令的后缀来对应不同长度的操作数。例如 ADDQ/ADDW/ADDL/ADDB。

条件跳转/无条件跳转

寄存器

amd64 的通用寄存器:
下面是通用通用寄存器的名字在 IA64 和 plan9 中的对应关系:
 
寄存器名字对应关系
IA64
RAX
RBX
RCX
RDX
RDI
RSI
RBP
RSP
R8
R9
R10
R11
R12
R13
R14
RIP
AX
BX
CX
DX
DI
SI
BP
SP
R8
R9
R10
R11
R12
R13
R14
PC

伪寄存器

FP: Frame pointer: arguments and locals. PC: Program counter: jumps and branches. SB: Static base pointer: global symbols. SP: Stack pointer: top of stack.
  1. 伪 SP 和硬件 SP 不是一回事,在手写代码时,伪 SP 和硬件 SP 的区分方法是看该 SP 前是否有 symbol。如果有 symbol,那么即为伪寄存器,如果没有,那么说明是硬件 SP 寄存器。
  1. SP 和 FP 的相对位置是会变的,所以不应该尝试用伪 SP 寄存器去找那些用 FP + offset 来引用的值,例如函数的入参和返回值。
  1. 官方文档中说的伪 SP 指向 stack 的 top,是有问题的。其指向的局部变量位置实际上是整个栈的栈底(除 caller BP 之外),所以说 bottom 更合适一些。
  1. 在 go tool objdump/go tool compile -S 输出的代码中,是没有伪 SP 和 FP 寄存器的,我们上面说的区分伪 SP 和硬件 SP 寄存器的方法,对于上述两个命令的输出结果是没法使用的。在编译和反汇编的结果中,只有真实的 SP 寄存器。
  1. FP 和 Go 的官方源代码里的 framepointer 不是一回事,源代码里的 framepointer 指的是 caller BP 寄存器的值,在这里和 caller 的伪 SP 是值是相等的。

变量声明

在汇编里所谓的变量,一般是存储在 .rodata 或者 .data 段中的只读值。对应到应用层的话,就是已初始化过的全局的 const、var、static 变量/常量。
使用 DATA 结合 GLOBL 来定义一个变量。DATA 的用法为:
大多数参数都是字面意思,不过这个 offset 需要稍微注意。其含义是该值相对于符号 symbol 的偏移,而不是相对于全局某个地址的偏移。
使用 GLOBL 指令将变量声明为 global,额外接收两个参数,一个是 flag,另一个是变量的总大小。
badge