汇编器假定是64位模式。如果想改到32位模式,模式伪操作:
MODE $32
这个作用主要是检测给定的模式中指令是否合法,但是loader仍然假设是32位操作数和地址,调用和返回都是32位的PC。大多类似上面的386。体系结构中有额外的R8到R15。所有寄存器都是64位,但是指令会访问低8位,16位和32位。例如对AX进行MOVL会将低32位赋值,高32位清0。64位使用MOVQ。Plan 9的C语言使用额外寄存器是从R15往下。有一些MMX和XMM等指令。MMX寄存器是M0到M7,XMM寄存器是X0到X15。都统一使用L表示'long word'(32位),Q表示'quad word'(64位)。有些指令使用O('octword')表示128位。C语言的long long类型是64位的,但它是传递和返回的是值而不是引用。更要注意的是,C指针是64位的。AX仍然是返回值,但跟386不同的是,浮点返回值是X0。所有少于8字节的参数在栈中都是按8字节对齐的。
本来看这个的目的是源于对go语言汇编的学习,结果看了一圈发现意义不大,还不如直接看看各种情况下go生成的汇编码,在实践中学习。
func f(x,y int32) int32 {
return x
}
汇编出来之后是
--- prog list "f" --- 0000 (test.go:3) TEXT f+0(SB),$0-12 0001 (test.go:4) MOVL x+0(FP),BX 0002 (test.go:4) MOVL BX,.noname+8(FP) 0003 (test.go:4) RET ,
x+0(FP)中x是变量名x,这个好像没什么用,0(FP)这个是指第一个参数。.noname也是没什么用的。注意的是这里把最后的返回值放到了8(FP)。0(FP)是参数x,4(FP)是参数y,因此可以看出go语言的函数调用协议:返回值是挨着参数放在栈中的。这样就很容易解释多值返回了。
这个代码有点短,调用的时候被内联了。如果写长一点,再看看函数调用生成的汇编
f(3,4)
汇编之后
0034 (test.go:14) MOVL $3,(SP) 0035 (test.go:14) MOVL $4,4(SP) 0036 (test.go:14) CALL ,f+0(SB) 0037 (test.go:15) RET ,
这里可以看出参数的进栈顺序,SP之上依次是第一个参数,第二个参数…