深入理解 Golang: Go 程序的编译运行过程

Go program 编译过程

package main

import "fmt"

func main() {
 fmt.Println("Hello Go")
}

编译前端

  1. 词法分析
    • 将源代码翻译成 Token(最小语义结构)
  2. 句法分析
    • Token 序列经过处理,变成语法树 AST
  3. 语义分析
    • 类型检查
    • 类型推断
    • 函数调用内联
    • 逃逸分析

编译后端

  1. 中间代码生成(SSA)
    • 处理不同平台的差异,生成中间代码
  2. 代码优化
  3. 机器码生成
    • 生成 Plan9 汇编代码
  4. 链接
    • 将各个包(.a 文件)进行链接,包括 runtime

查看从代码到 SSA 中间码的过程

# windows
$env:GOSSAFUNC="main"
# linux
export GOSSAFUNC="main"

执行 go build main.go,得到 ssa.html 文件。
在这里插入图片描述
在这里插入图片描述
从 sourses -> ast -> … -> genssa

查看 Plan9 汇编代码

go build -gcflags -S main.go

在这里插入图片描述

Go program 的入口

tips: 第一行代码并非为用户自定义的 main 方法

  1. 首先进入 %GOROOT%\src\runtime 下的对应的 rt0_xxx.s 汇编文件,如在 windows 系统下,进入 rt0_windows_amd64.s,执行 JMP _rt0_amd64(SB)
    在这里插入图片描述
    在这里插入图片描述
  2. 调用 _rt0_amd64(SB) 方法,该方法位于 %GOROOT%\src\runtime\asm_amd64.s
    在这里插入图片描述
  3. 该方法将调用命令参数 argc,argc 放入寄存器,随后调用 runtime·rt0_go(SB)
    在这里插入图片描述
  • 读取命令行参数。复制参数数量 argc 和参数值 argv 到栈上,参数可能有也可能没有,取决于启动程序时参数是否输入。
  • 初始化 g0 执行栈。启动 g0 协程,g0 是 Go 程序的第一个协程,且不归调度器管理,是为了调度协程而产生的协程。
  • 经过一系列判断后,开始运行时检测 runtime.check,该检测方法位于 %GOROOT%\src\runtime\runtime1.go。主要检测包括:
    在这里插入图片描述
    • 检查各种类型的长度
    • 检查指针操作
    • 检查结构体字段的偏移量
    • 检查 atomic 原子操作
    • 检查 CAS 操作
    • 检查栈大小是否为 2 的幂次
  • 初始化 runtime.args。对命令行中的参数进行处理,拷贝参数到 go 代码,参数数量赋值给 argc int32,参数值赋值给 argv **byte。
  • 执行 runtime·osinit(SB) 判断 cpu 核数,用于后续调度器的初始化 runtime·schedinit(SB)
    • 全局占空间内存分配
    • 加载命令行参数到 os.Args
    • 堆内存空间的初始化
    • 加载操作系统环境变量
    • 初始化当前系统线程
    • 垃圾回收器的参数初始化
    • 算法初始化
    • 设置 process 数量
  • 取 runtime 主函数地址 MOVQ $runtime·mainPC(SB), AX,创建启动主协程 runtime·newproc(SB),初始化调度器 M runtime·mstart(SB),调度主协程用于运行 runtime.main,runtime 的 main 方法位于 %GOROOT%\src\runtime\proc.go
  • 主协程执行主函数。执行 runtime 中的 init 方法,启动垃圾回收器,执行用户包依赖的 init 方法,最后执行用户自定义的主函数 main.main():
    在这里插入图片描述
    在这里插入图片描述
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值