前置知识
1.编译go程序
我们先来追踪一下go build的过程
有如下coding(公寓网炸了,暂时用不了xshell,虚拟机界面太小不好截图,暂用网上例子,后续实验补充)
hello.go
package main
import "fmt"
func main() {
fmt.Println("Hello World")
}
执行编译命令(-n表示不执行打印,-x表示执行并打印)
go build -n hello.go
打印结果如下
mkdir -p $WORK/b001/
cat >$WORK/b001/importcfg << 'EOF' # internal
# import config
packagefile fmt=/usr/local/go/pkg/darwin_amd64/fmt.a
packagefile runtime=/usr/local/go/pkg/darwin_amd64/runtime.a
EOF
cd /Users/polo/Public/Work/go/src/study/basic/hello
/usr/local/go/pkg/tool/darwin_amd64/compile -o $WORK/b001/_pkg_.a -trimpath $WORK/b001 -p main -complete -buildid fVbBEz0nTJc3r6VxU5ye/fVbBEz0nTJc3r6VxU5ye -goversion go1.11.1 -D _/Users/polo/Public/Work/go/src/study/basic/hello -importcfg $WORK/b001/importcfg -pack -c=4 ./hello.go
/usr/local/go/pkg/tool/darwin_amd64/buildid -w $WORK/b001/_pkg_.a # internal
cat >$WORK/b001/importcfg.link << 'EOF' # internal
packagefile command-line-arguments=$WORK/b001/_pkg_.a
...
packagefile internal/race=/usr/local/go/pkg/darwin_amd64/internal/race.a
EOF
mkdir -p $WORK/b001/exe/
cd .
/usr/local/go/pkg/tool/darwin_amd64/link -o $WORK/b001/exe/a.out -importcfg $WORK/b001/importcfg.link -buildmode=exe -buildid=P1Y_fbNXAEG6zEEGqFsM/fVbBEz0nTJc3r6VxU5ye/fVbBEz0nTJc3r6VxU5ye/P1Y_fbNXAEG6zEEGqFsM -extld=clang $WORK/b001/_pkg_.a
/usr/local/go/pkg/tool/darwin_amd64/buildid -w $WORK/b001/exe/a.out # internal
mv $WORK/b001/exe/a.out hello
过程分析:
1.创建临时目录(这里的$WORK会临时赋值,我机器上指向的是tmp中临时创建的一个目录)
mkdir -p $WORK/b001/
2.查找依赖源
cat >$WORK/b001/importcfg << ...
3.执行源代码编译
/usr/local/go/pkg/tool/darwin_amd64/compile
4.收集链接库文件
cat >$WORK/b001/importcfg.link
5.生成可执行文件(链接)
/usr/local/go/pkg/tool/darwin_amd64/link -o
6.移动可执行文件(从临时创建的目录中移出)
mv $WORK/b001/exe/a.out hello
我们可以看到大致过程和c程序的编译是大同小异:预处理->编译->链接。表现为显示过程就是compile与link
1.1Compile工具
从上文可知go build执行过程主要使用了compile和link两个工具,compile简单来说将同一个package的多个文件编译成一个.o文件 image.png调用该工具使用命令
go tool compile --help
具体该工具干了啥可阅读(该工具本身是用go语言实现的)初识别go compile
大致过程可概括为
解析文件->解析语法->类型检查->编译->写入文件
咱们试一试
go tool compile -S hello.go | more
但生成的文件并不是一个二进制文件ELF格式,而是汇编代码文件(我们用objdump反汇编一下让我们能看懂)
go tool objdump hello.o
(go build -gcflags -S 也可以)
1.2Link工具
go tool link --help
负责将.o目标文件与其他对象组合成一个包档案或直接传给连接器(在上一章的c中动态链接也是靠链接器完成的),并将其组合到可执行的二进制文件中
image.png
1.3run指令
有了上面的知识储备我们再来看看run指令
go run -x hello.go
run指令
与build区别就是在链接完成后并没有移动文件,而是直接执行程序
如何拿到中间文件?使用--work选项
WORK=/var/folders/bw/8yw8h4yj2vb6mxtb6t8t41f00000gn/T/go-build149627400
可以拿到临时目录
1.4执行可执行文件步骤
1.解析ELF Header
2.加载文件内容至内存
3.从entry point开始执行代码(设置CS:IP寄存器)
readelf - h hello
readelf
参考
1.go编译执行流程
2.编译链接过程概述
3.main程序启动过程
4.得到go汇编程序的办法
网友评论