Go Assembly 学习笔记
Go Assembly首先安利一个获取当前goroutine id 的library,gid,支持 go1.7 - go1.9,可能是目前最小的库了,使用也很简单: Go汇编语法类似 Plan 9,它不是对机器语言的直接表达,拥有半抽象的指令集。总体来说, machine-specific 操作一般就是它们的本意,其他概念例如 memory move,subroutine call,return 是抽象的表达。 常量evaluation 优先级和 C 不同,例如 3&1<<2 == 4,解释为 (3&1) << 2。 符号4个预定义的符号,表示 pseudo-registers,伪寄存器(虚拟寄存器?)。
用户定义的符号都是通过偏移(offset)来表示的。 SB寄存器表示全局内存起点,foo(SB) 表示 符号foo作为内存地址使用。这种形式用于命名 全局函数,数据。 FP寄存器指向函数参数。0(FP)是第一个参数,8(FP)是第二个参数(64-bit machine). SP寄存器表示栈指针,指向 top of local stack frame,所以 offset 都是负数,范围在 [ -framesize,0 ),例如 x-8(SP). 对于硬件寄存器名称为SP的架构, 跳转和分支是针对PC的offset,或者 label,例如: label: MOVW $0,R1 JMP label label 范围是函数级别的,不同函数可以定义相同名称的label。 指令例如: TEXT runtime·profileloop(SB),NOSPLIT,$8 MOVQ $runtime·profileloop1(SB),CX MOVQ CX,0(SP) CALL runtime·externalthreadhandler(SB) RET TEXT 指令定义符号 全局数据符号用 DATA 声明,方式为 DATA divtab<>+0x00(SB)/4,$0xf4f8fcff DATA divtab<>+0x04(SB)/4,$0xe6eaedf0 ... DATA divtab<>+0x3c(SB)/4,$0x81828384 GLOBL divtab<>(SB),RODATA,$64 GLOBL runtime·tlsoffset(SB),NOPTR,$4 定义并初始化了 divtab<>,一个 只读的 64字节 表,每一项4字节。定义了 runtime·tlsoffset, 4字节空值,非指针。 指令有一个或两个参数。如果有两个,第一个是 bit mask,可以为数字表达式。值的定义如下:
Example: Add//main.go package main import "fmt" func add(x,y int64) int64 func main() { fmt.Println(add(2,3)) } // add.s TEXT ·add(SB),$0-24 MOVQ x+0(FP),BX MOVQ y+8(FP),BP ADDQ BP,BX MOVQ BX,ret+16(FP) RET 定义一个函数的方式为:
最后的 Example: Hellopackage main import _ "fmt" func hello() func main(){ hello() } #include "textflag.h" DATA world<>+0(SB)/8,$"hello wo" DATA world<>+8(SB)/4,$"rld " GLOBL world<>+0(SB),$12 // 需要 stack空间 88字节,没有参数和返回值 TEXT ·hello(SB),$88-0 SUBQ $88,SP MOVQ BP,80(SP) LEAQ 80(SP),BP // 创建字符,存在 my_string LEAQ world<>+0(SB),AX MOVQ AX,my_string+48(SP) MOVQ $11,my_string+56(SP) MOVQ $0,autotmp_0+64(SP) MOVQ $0,autotmp_0+72(SP) LEAQ type·string(SB),AX MOVQ AX,(SP) LEAQ my_string+48(SP),AX MOVQ AX,8(SP) // 创建一个 interface CALL runtime·convT2E(SB) MOVQ 24(SP),AX MOVQ 16(SP),CX MOVQ CX,autotmp_0+64(SP) MOVQ AX,autotmp_0+72(SP) LEAQ autotmp_0+64(SP),(SP) MOVQ $1,8(SP) MOVQ $1,16(SP) // 调用 fmt.Println CALL fmt·Println(SB) MOVQ 80(SP),BP ADDQ $88,SP RET 第一行的
Example: gidgid 库中用到的函数 #include "go_asm.h" #include "go_tls.h" #include "textflag.h" // 返回值 8 bytes,符号为 getg TEXT ·getg(SB),$0-8 // get_tls 的宏为: #define get_tls(r) MOVQ TLS,r // 等价于 MOVQ TLS,CX // 从 TLS(Thread Local Storage) 起始移动 8 byte 值 到 CX 寄存器 get_tls(CX) // g的宏为: g(r) 0(r)(TLS*1) // 等价于 0(CX)(TLS*1),AX // 查到意义为 indexed with offset,这里 offset=0,索引是什么意思不清楚 MOVQ g(CX),AX // 从AX起始移动 8 byte 值,到ret符号的位置 MOVQ AX,ret+0(FP) RET Example: SwapInt32一个原子交换 int32 的函数 package atomic import ( "unsafe" ) func SwapInt32(addr *int32,new int32) (old int32) #include "textflag.h" // 参数大小 = 8 + 4 + 4,+ 4 (默认的 ret符号?) TEXT ·SwapInt32(SB),$0-20 JMP ·SwapUint32(SB) TEXT ·SwapUint32(SB),$0-20 // 第一个参数 移动 8 byte 到 BP MOVQ addr+0(FP),BP // 第二个参数 移动 4 byte 到 AX MOVL new+8(FP),AX // 原子操作,write-after-read,把 (AX,offset=0) 与 (BP,offset=0) 交换 4 byte 数据 XCHGL AX,0(BP) // 移动 AX 到 old 符号 MOVL AX,old+16(FP) RET (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |