go是和c语言一样的静态语言,因此也就存在着编译的过程。然后反编译其实是为了看系统的整个调用。
编译编译主要是通过go build 这个命令去做的。通常的go run main.go其实也是在编译完成之后,直接运行代码里面的main方法。
然后也可以通过,go build 方法,先变成成为可执行文件之后再进行运行,加上-o指定可执行文件需要进行存放的目录。
当然go build 也有很多可以选择的参数,可以在安装完go之后,通过go help build进行查看。
用的比较多的参数有
-a
-a 强制编译,即使是代码没有进行更新,其实就是和makefile有点类似,本身make之后会有缓存,如果代码没有更新,make的时候会提醒.-a 就是即使没有更新也要重新编译。
-p
-p n.这个是后面接上参数的,一般是cpu的数量,缺省是设置的GOMAXPROCS.这个也是go编译这么快的原因之一,可以并发编译。
-race
-race 开启竞态检测,其实也就是检测有没有并发的问题。
接下来我们用一个示例代码,下面的代码明显是有着并发的问题。然后看看不加-race和加了的区别
package main
import (
"fmt"
)
func main() {
var a int
a = 1
go func() {
a++
}()
go func() {
a++
}()
fmt.Printf("is int:%v\n", a)
}
不加-race
加了race
因为截屏显示的问题,把内容都复制出来。
==================
WARNING: DATA RACE
Read at 0x00c0000b8018 by main goroutine:
main.main()
/Users/wangjian01/Documents/go/learn/study/runtime/map/t1.go:20 +0x134
Previous write at 0x00c0000b8018 by goroutine 7:
main.main.func1()
/Users/wangjian01/Documents/go/learn/study/runtime/map/t1.go:13 +0x44
Goroutine 7 (finished) created at:
main.main()
/Users/wangjian01/Documents/go/learn/study/runtime/map/t1.go:12 +0xbd
==================
is int:3
Found 1 data race(s)
很明显看这个不同的goroutine的读写操作说明的很清楚,因此需要根据提示做出加锁或者进行原子等操作避免。
我们试一下正确的代码下的输出。这个是加了读写锁的代码。
package main
import (
"fmt"
"sync"
)
func main() {
var a int
a = 1
var lock sync.RWMutex
go func() {
lock.Lock()
a++
lock.Unlock()
}()
go func() {
lock.Lock()
a++
lock.Unlock()
}()
lock.RLock()
fmt.Printf("is int:%v\n", a)
lock.RUnlock()
}
再加上-race进行编译,看已经没问题了
gcflags
go build 可以用-gcflags给go编译器传入参数,也就是传给go tool compile的参数,因此可以用go tool compile --help查看所有可用的参数。
其中-m可以检查代码的编译优化情况,包括逃逸情况和函数是否内联。
如果只在编译特定包时需要传递参数,格式应遵守“包名=参数列表”,如go build -gcflags -gcflags=‘log=-N -l’ main.go
go build用-ldflags给go链接器传入参数,实际是给go tool link的参数,可以用go tool link --help查看可用的参数。
常用-X来指定版本号等编译时才决定的参数值。例如代码中定义var buildVer string,然后在编译时用go build -ldflags “-X main.buildVer=1.0” … 来赋值。注意-X只能给string类型变量赋值。
通常为了调试的参数是-N参数代表禁止优化, -l参数代表禁止内联,
反编译
主要是为了底层如何运行,而将二进制文件转换成了汇编文件。
方法一
先编译成二进制,然后通过二进制文件,反编译成汇编文件。以上面的为例,
go build -o main
go tool objdump -S main > plan9.asm
然后看一下结果,因为比较多这里只截图一部分,
忽略其中的汇编,可以看到对于lock.RLock()的底层调用,对于我们的分析底层还是很有帮助的。
方法二
go tool compile -S -+ -l -m t1.go > plan9.asm
通过compile这个工具,可以看出编译器的整个过程,上面的是-m生成的效果,编译器的优化。