http://www.cnblogs.com/yjf512/p/6132868.html
我们可以很容易将一个golang程序转变成汇编语言。
比如我写了一个main.go:
package main
func@H_403_15@ g@H_403_15@(p int)@H_403_15@@H_403_15@ int {
return@H_403_15@ p+1@H_403_15@;
}
main@H_403_15@()@H_403_15@@H_403_15@ {
c@H_403_15@ := g(4@H_403_15@) + 1@H_403_15@
_@H_403_15@ = c@H_403_15@
}
使用命令:
GOOS=linux GOARCH=386@H_403_15@ go@H_403_15@ tool compile -S main.go@H_403_15@ >> main.S
我们就获取了main.S是main.go的汇编版本。
""@H_403_15@.g t=1@H_403_15@ size=16@H_403_15@ value=0@H_403_15@ args=0x10@H_403_15@ locals=0x0@H_403_15@
0x0000@H_403_15@ 00000@H_403_15@ (main.go@H_403_15@:4@H_403_15@) TEXT ""@H_403_15@.g(SB),$0@H_403_15@-16@H_403_15@
0x0000@H_403_15@ 00000@H_403_15@ (main.go@H_403_15@:4@H_403_15@) NOP
0x0000@H_403_15@ 00000@H_403_15@ (main.go@H_403_15@:4@H_403_15@) FUNCDATA $0@H_403_15@,gclocals·23e8278@H_403_15@e2b69a3a75fa59b23c49ed6ad(SB)
0x0000@H_403_15@ 00000@H_403_15@ (main.go@H_403_15@:4@H_403_15@) FUNCDATA $1@H_403_15@,gclocals·33@H_403_15@cdeccccebe80329f1fdbee7f5874cb(SB)
0x0000@H_403_15@ 00000@H_403_15@ (main.go@H_403_15@:5@H_403_15@) MOVQ ""@H_403_15@.p+8@H_403_15@(FP),BX
0x0005@H_403_15@ 00005@H_403_15@ (main.go@H_403_15@:5@H_403_15@) INCQ BX
0x0008@H_403_15@ 00008@H_403_15@ (main.go@H_403_15@:5@H_403_15@) MOVQ BX,""@H_403_15@.~r1+16@H_403_15@(FP)
0x000d@H_403_15@ 00013@H_403_15@ (main.go@H_403_15@:5@H_403_15@) RET
0x0000@H_403_15@ 48@H_403_15@ 8@H_403_15@b 5@H_403_15@c 24@H_403_15@ 08@H_403_15@ 48@H_403_15@ ff c3 48@H_403_15@ 89@H_403_15@ 5@H_403_15@c 24@H_403_15@ 10@H_403_15@ c3 H.\$.H..H.\$..
""@H_403_15@.main t=1@H_403_15@ size=16@H_403_15@ value=0@H_403_15@ args=0x0@H_403_15@ locals=0x0@H_403_15@
0x0000@H_403_15@ 00000@H_403_15@ (main.go@H_403_15@:8@H_403_15@) TEXT ""@H_403_15@.main(SB),$0@H_403_15@-0@H_403_15@
0x0000@H_403_15@ 00000@H_403_15@ (main.go@H_403_15@:8@H_403_15@) NOP
0x0000@H_403_15@ 00000@H_403_15@ (main.go@H_403_15@:8@H_403_15@) FUNCDATA $0@H_403_15@,255)">go@H_403_15@:8@H_403_15@) FUNCDATA $1@H_403_15@,255)">go@H_403_15@:9@H_403_15@) MOVQ $4@H_403_15@,BX
0x0007@H_403_15@ 00007@H_403_15@ (main.go@H_403_15@:9@H_403_15@) INCQ BX
0x000a@H_403_15@ 00010@H_403_15@ (main.go@H_403_15@:9@H_403_15@) INCQ BX
0x000d@H_403_15@ 00013@H_403_15@ (main.go@H_403_15@:11@H_403_15@) RET
0x0000@H_403_15@ 48@H_403_15@ c7 c3 04@H_403_15@ 00@H_403_15@ 00@H_403_15@ 00@H_403_15@ 48@H_403_15@ ff c3 48@H_403_15@ ff c3 c3 H......H..H...
""@H_403_15@.init t=1@H_403_15@ size=80@H_403_15@ value=0@H_403_15@ args=0x0@H_403_15@ locals=0x0@H_403_15@
0x0000@H_403_15@ 00000@H_403_15@ (main.go@H_403_15@:11@H_403_15@) TEXT ""@H_403_15@.init(SB),255)">go@H_403_15@:11@H_403_15@) MOVQ (TLS),CX
0x0009@H_403_15@ 00009@H_403_15@ (main.go@H_403_15@:11@H_403_15@) CMPQ SP,16@H_403_15@(CX)
0x000d@H_403_15@ 00013@H_403_15@ (main.go@H_403_15@:11@H_403_15@) JLS 62@H_403_15@
0x000f@H_403_15@ 00015@H_403_15@ (main.go@H_403_15@:11@H_403_15@) NOP
0x000f@H_403_15@ 00015@H_403_15@ (main.go@H_403_15@:11@H_403_15@) FUNCDATA $0@H_403_15@,gclocals·33@H_403_15@cdeccccebe80329f1fdbee7f5874cb(SB)
0x000f@H_403_15@ 00015@H_403_15@ (main.go@H_403_15@:11@H_403_15@) FUNCDATA $1@H_403_15@,255)">go@H_403_15@:11@H_403_15@) MOVBQZX ""@H_403_15@.initdone·(SB),BX
0x0016@H_403_15@ 00022@H_403_15@ (main.go@H_403_15@:11@H_403_15@) CMPB BL,$0@H_403_15@
0x0019@H_403_15@ 00025@H_403_15@ (main.go@H_403_15@:11@H_403_15@) JEQ 47@H_403_15@
0x001b@H_403_15@ 00027@H_403_15@ (main.0x0022@H_403_15@ 00034@H_403_15@ (main.2@H_403_15@
0x0025@H_403_15@ 00037@H_403_15@ (main.go@H_403_15@:11@H_403_15@) JNE 40@H_403_15@
0x0027@H_403_15@ 00039@H_403_15@ (main.go@H_403_15@:11@H_403_15@) RET
0x0028@H_403_15@ 00040@H_403_15@ (main.go@H_403_15@:11@H_403_15@) PCDATA $0@H_403_15@,$0@H_403_15@
0x0028@H_403_15@ 00040@H_403_15@ (main.go@H_403_15@:11@H_403_15@) CALL runtime.throwinit(SB)
0x002d@H_403_15@ 00045@H_403_15@ (main.go@H_403_15@:11@H_403_15@) UNDEF
0x002f@H_403_15@ 00047@H_403_15@ (main.go@H_403_15@:11@H_403_15@) MOVB $1@H_403_15@,21)">""@H_403_15@.initdone·(SB)
0x0036@H_403_15@ 00054@H_403_15@ (main.go@H_403_15@:11@H_403_15@) MOVB $2@H_403_15@,21)">""@H_403_15@.initdone·(SB)
0x003d@H_403_15@ 00061@H_403_15@ (main.go@H_403_15@:11@H_403_15@) RET
0x003e@H_403_15@ 00062@H_403_15@ (main.go@H_403_15@:11@H_403_15@) CALL runtime.morestack_noctxt(SB)
0x0043@H_403_15@ 00067@H_403_15@ (main.go@H_403_15@:11@H_403_15@) JMP 0@H_403_15@
首先这个程序根据TEXT是定义函数的,分为3个部分
0x0000@H_403_15@ 00000@H_403_15@ (main.go:4@H_403_15@) TEXT 16@H_403_15@
0x0000@H_403_15@ 00000@H_403_15@ (main.go:8@H_403_15@) TEXT 0@H_403_15@
0x0000@H_403_15@ 00000@H_403_15@ (main.go:11@H_403_15@) TEXT 0@H_403_15@
这个"". 代表的是这个函数的命名空间。
g(SB) 这里就有个SB的伪寄存器。全名未Static Base,代表g这个函数地址,@H_403_15@
NOP命令是作为占位符使用,提供给编译器使用的。可以忽略不看。
下面是
0x0000@H_403_15@ 00000@H_403_15@ (main.go:4@H_403_15@) FUNCDATA $0,gclocals·23@H_403_15@e8278e2b69a3a75fa59b23c49ed6ad(SB)
0x0000@H_403_15@ 00000@H_403_15@ (main.go:4@H_403_15@) FUNCDATA $1,gclocals·33@H_403_15@cdeccccebe80329f1fdbee7f5874cb(SB)
这里的FUNCDATA是golang编译器自带的指令,plan9和x86的指令集都是没有的。它用来给gc收集进行提示。提示@H_403_15@
下面是
0x0000@H_403_15@ 00000 (main@H_403_15@.go@H_403_15@:5)@H_403_15@ MOVQ@H_403_15@ "".p@H_403_15@+8(FP@H_403_15@),BX@H_403_15@
0x0005@H_403_15@ 00005 (INCQ@H_403_15@ x0008@H_403_15@ 00008 (MOVQ@H_403_15@ BX@H_403_15@,"".~r1@H_403_15@+16(FP@H_403_15@)
这里有一个FP寄存器,FP是frame pointer,是指向栈底,SP是指向栈顶。BX是一个临时寄存器,那么上面的句子是代表把FP+8这个位置的数据(参数p),保存到BX中。FP+8代表什么呢,按照上面的图,代表的是参数
INCQ是自增算法,BX里面的数自加1,然后把BX里面的数存储到FP+16,代表的是返回值。
下面就是RET,直接返回。
下面再看看main,我们会发现,main函数里面并没有call g函数,这是由于go汇编编译器会把一些短的函数变成内嵌函数,减少函数调用。
if
package main
c@H_403_15@ := g(4@H_403_15@) + 1@H_403_15@
var@H_403_15@ d bool
if@H_403_15@ (c@H_403_15@ > 4@H_403_15@) {
d = true@H_403_15@
} else@H_403_15@ {
d = false@H_403_15@
}
_@H_403_15@ = d
return@H_403_15@
}
对应的main的汇编为:
0x0000@H_403_15@ 00000@H_403_15@ (main.go@H_403_15@:11@H_403_15@) CMPQ BX,$4@H_403_15@
0x0011@H_403_15@ 00017@H_403_15@ (main.go@H_403_15@:11@H_403_15@) JLE 27@H_403_15@
0x0013@H_403_15@ 00019@H_403_15@ (main.go@H_403_15@:12@H_403_15@) MOVQ $1@H_403_15@,AX
0x001a@H_403_15@ 00026@H_403_15@ (main.go@H_403_15@:17@H_403_15@) RET
0x001b@H_403_15@ 00027@H_403_15@ (main.go@H_403_15@:14@H_403_15@) MOVQ $0@H_403_15@,AX
0x001d@H_403_15@ 00029@H_403_15@ (main.go@H_403_15@:17@H_403_15@) JMP 26@H_403_15@
可以看是试用CMPQ来进行比较的,JLE代表CMP比较之后的结果,如果BX小于等于4,那么就跳到27指令,就是MOVQ $0,AX,把AX赋值为0,就是false,否则赋值为1,true
for
程序改为:
package main
var@H_403_15@ sum int
for@H_403_15@ i := 0@H_403_15@; i < p; i++ {
sum = sum + i
}
return@H_403_15@ sum
}
c@H_403_15@
}
这里面有一个for循环,产生的汇编为:
0x0000@H_403_15@ 00000@H_403_15@ (main.go@H_403_15@:4@H_403_15@) MOVQ 0x0005@H_403_15@ 00005@H_403_15@ (main.23e8278@H_403_15@e2b69a3a75fa59b23c49ed6ad(SB)
0x0005@H_403_15@ 00005@H_403_15@ (main.33@H_403_15@cdeccccebe80329f1fdbee7f5874cb(SB)
0x0005@H_403_15@ 00005@H_403_15@ (main.go@H_403_15@:5@H_403_15@) MOVQ $0@H_403_15@,CX
0x0007@H_403_15@ 00007@H_403_15@ (main.go@H_403_15@:6@H_403_15@) MOVQ $0@H_403_15@,AX
0x0009@H_403_15@ 00009@H_403_15@ (main.go@H_403_15@:6@H_403_15@) CMPQ AX,DX
0x000c@H_403_15@ 00012@H_403_15@ (main.go@H_403_15@:6@H_403_15@) JGE $0@H_403_15@,25@H_403_15@
0x000e@H_403_15@ 00014@H_403_15@ (main.go@H_403_15@:7@H_403_15@) ADDQ AX,CX
0x0011@H_403_15@ 00017@H_403_15@ (main.go@H_403_15@:6@H_403_15@) INCQ AX
0x0014@H_403_15@ 00020@H_403_15@ (main.go@H_403_15@:6@H_403_15@) NOP
0x0014@H_403_15@ 00020@H_403_15@ (main.0x0017@H_403_15@ 00023@H_403_15@ (main.go@H_403_15@:6@H_403_15@) JLT $0@H_403_15@,14@H_403_15@
0x0019@H_403_15@ 00025@H_403_15@ (main.go@H_403_15@:9@H_403_15@) MOVQ CX,21)">""@H_403_15@.~r1+16@H_403_15@(FP)
0x001e@H_403_15@ 00030@H_403_15@ (main.go@H_403_15@:9@H_403_15@) RET
AX存的是变量i,DX存的是参数p,CX存的是变量sum,下面的几个命令:
0x0009@H_403_15@ 00009@H_403_15@ (main.14@H_403_15@
实际上是使用CMP,JGE,JLT来不断控制循环过程。