如果你想深入了解Go语言,Go语言汇编是一个绕不过去的环节。本文根据Go官方文档AQuickGuidetoGo'sAssembler介绍Go汇编。Go汇编是在Plan9汇编的基础上演化而来的新版本。如果需要进一步深入学习,推荐阅读Plan9汇编器手册。关于Go的汇编最重要的一点是它不是底层机器代码的直接表示。而是进行了一层抽象,但是抽象的不是很理想,所以称为半抽象指令集(semi-abstract)。因此,一些细节指令可以精确映射到机器代码,但有些则不能,正如您在本文的示例代码中看到的那样。由于各个处理器架构的指令集和寄存器不同,汇编代码实现需要适应各种处理器架构;当然,它还必须适应各种操作系统。环境操作系统:Ubuntu20.04.2LTS;x86_64Go:goversiongo1.16.2linux/amd64操作系统、处理器架构、Go版本不同,可能导致同一源码编译运行时的寄存器值、内存地址、数据结构有差异,等本文仅包含linux/amd64系统架构下的64位可执行程序示例。本文仅保证当前环境下学习过程中分析数据的准确性和有效性。代码清单go.modmodulego-asm-guidego1.16main.gopackagemainimport("fmt""unsafe")typeTextstruct{Languagestring_uint8Lengthint}funcadd(a,bint)intfuncaddX(a,bint)int//获取Text的Length域的值funclength(text*Text)int//获取Text结构体的大小funcsizeOfTextStruct()intfuncmain(){println(add(1,2))println(addX(1,2))text:=&Text{Language:"chinese",Length:1024,}fmt.Println(text)println(length(text))println(sizeOfTextStruct())println(unsafe.Sizeof(*text))}main.s#include"textflag.h"#include"go_asm.h"//这个文件自动生成TEXTadd(SB),NOSPLIT,$0-24MOVQa+0(FP),AX//读取第一个一个参数MOVQb+8(FP),BX//读取第二个参数ADDQBX,AXMOVQAX,ret+16(FP)//保存结果RETTEXTaddX(SB),NOSPLIT,$0-24MOVQa+0(FP),AXMOVQb+8(FP),BXADDQBX,AXMOVQ$x(SB),BX//读取全局变量x的地址MOVQ0(BX),BX//读取全局变量xADDQ的值BX、AXMOVQAX、ret+16(FP)RETTEXT长度(SB),NOSPLIT,$0-16MOVQ文本+0(FP),AXMOVQText_Length(AX),AX//通过字段在结构体中的偏移量读取字段值MOVQAX,ret+8(FP)RETTEXTsizeOfTextStruct(SB),NOSPLIT,$0-8MOVQ$Text__size,AX//保存结构体的大小到AX寄存器MOVQAX,ret+0(FP)RETDATAx+0(SB)/8,$10//初始化全局变量x,赋值10GLOBLx(SB),RODATA,$8//声明全局变量x常用命令学习Go汇编需要时间。如果你不是天才,没有扎实的汇编基础,看教程花一天时间就能马上掌握,但是熟练使用工具可以让我们有效地学习Go汇编。编译生成程序集这是Go语言的内置函数,可以通过以下命令查看。当然也可以指定各种参数进行详细研究,这里不再赘述。gotoolcompile-Sx.gogobuild-gcflags-Sx.go$catx.gopackagemainfuncmain(){println(3)}$gotoolcompile-Sx.go"".mainSTEXTsize=77args=0x0locals=0x10funcid=0x00x000000000(x.go:3)TEXT"".main(SB),ABIInternal,$16-00x000000000(x.go:3)MOVQ(TLS),CX0x000900009(x.go:3)CMPQSP,16(CX)0x000d00013(x.go:3)PCDATA$0,$-20x000d00013(x.go:3)JLS700x000f00015(x.go:3)PCDATA$0,$-10x000f00015(x.go:3)SUBQ$16,SP0x001300019(x.go:3)MOVQBP,8(SP)0x001800024(x.go:3)LEAQ8(SP),BP0x001d00029(X.Go:3)funcdata$0,gclocals·33cdeccccebe80329f1fdbee7f5874cb(sb)0x001d00029(x.go:3)funcdata$1,gclocals·gclocals.go:4)NOP0x002000032(x.go:4)CALLruntime.printlock(SB)0x002500037(x.go:4)MOVQ$3,(SP)0x002d00045(x.go:4)CALLruntime.printint(SB)0x003200050(x.go:4)CALLruntime.printnl(SB)0x003700055(x.go:4)CALLruntime.printunlock(SB)0x003c00060(x.go:5)MOVQ8(SP),BP0x004100065(x.go:5)ADDQ$16,SP0x004500069(x.go:5)RET0x004600070(x.go:5)NOP0x004600070(x.go:3)PCDATA$1,$-10x004600070(x.go:3)PCDATA$0,$-20x004600070(x.go:3)CALLruntime.morestack_noctxt(SB)0x004b00075(x.go:3)PCDATA$0,$-10x004b00075(x.go:3)JMP00x000064488b0c2500000000483b6110763748dH..%..H;a.v7H0x001083ec1048896c2408488d6c24080f1f00...H.l$.H.l$....0x0020e80000000048c7042403000000e80000.....H..$......0x00300000e800000000e800000000488b6c24.......H.l$0x0040084883c410c3e800000000ebb3.H......rel5+4t=17TLS+0rel33+4t=8runtime.printlock+0rel46+4t=8runtime.printint+0rel51+4t=8runtime.printnl+0rel56+4t=8runtime.printunlock+0rel71+4t=8runtime.morestack_noctxt+0go.cuinfo.packagename.SDWARFCUINFOdupoksize=00x00006d61696emain""..inittaskSNOPTRDATAsize=240x00000000000000000000000000000000..............0x00100000000000000000.....gclocals·33cdeccccebe80329f1fdbee7f5874cbSRODATAdupoksize=80x00000100000000000000decompilergotoolobjdump这个是自带的反编译命令围棋语言$catx.gopackagemainfuncmain(){println(3)}$gobuildx.go$gotoolobjdump-smain.mainxTEXTmain.main(SB)/home/foo/codes/goinmemory/go_asm/x.去x.go:30x45ec6064488b0c25f8ffffffMOVQFS:0xfffffff8,CXx.go:30x45ec69483b6110CMPQ0x10(CX),SPx.go:30x45ec6d7637JBE0x45eca6x.go:3xec0x45ec61$4883,SPx45ec6f01083.go:30x45ec7348896c2408MOVQBP,0x8(SP)x.go:30x45ec78488d6c2408LEAQ0x8(SP),BPx.go:40x45ec7d0f1f00NOPL0(AX)x.go:40x45ec80e8fb05fdffCALLruntime.printfdff调用(SB)x.go:40x45ec8548c7042403000000MOVQ$0x3,0(SP)x.go:40x45ec8de8ee0dfdffCALLruntime.printint(SB)x.go:40x45ec92e8a908fdffCALLruntime.printnl(SB)x.go:40x45ec97e86406fdffCALLruntime.printunlock(SB)x.go:50x45ec9c488b6c2408MOVQ0x8(SP),BPx.go:50x45eca14883c410ADDQ$0x10,SPx.go:50x45eca5c3RETx.go:30x45eca6e8b5afffffCALLruntime.morestack_noctxt(SB)x.go:30x45ecabebb3JMPmain.main(SB)objdumpthis是Linux环境下的通用反编译工具,不仅仅针对Go程序$objdump--disassemble=main.mainxx:文件格式elf64-x86-64Disassemblyofsection.text:000000000045ec60
