美文网首页
GO笔记(二)之GO编译流程

GO笔记(二)之GO编译流程

作者: 温岭夹糕 | 来源:发表于2022-07-19 10:22 被阅读0次

    前置知识

    程序如何到进程和ELF文件格式

    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汇编程序的办法

    相关文章

      网友评论

          本文标题:GO笔记(二)之GO编译流程

          本文链接:https://www.haomeiwen.com/subject/amxeirtx.html