Go程序是如何编译并运行起来的(图文详解)
Go程序是如何编译的
从hello RdrB1te开始
package main import "fmt" func main() { fmt.Println("hello RdrB1te")
}
不实际编译它,只输出它的编译过程:
go build -n
简单的编译过程分析:
![![[hello程序的简单编译过程分析.png]]](https://img-blog.csdnimg.cn/direct/ee6593840eaa47fe8cb6dd03bf9dbc2d.png)
上面的过程确认了两个事情:
- Runtime会永远随着用户代码一起编译
- 在windows平台上编译出来了一个exe的可执行文件
Go 编译过程
![![[Go编译过程.png]]](https://img-blog.csdnimg.cn/direct/be9fbc3a6cca4aa69c27754917e075ef.png)
词法分析
- 将源代码翻译成Token
- Token是代码中的最小语义结构(如变量名、关键字、运算符等不可拆分的最小单元)
句法分析
- Token序列经过处理,变成语法树
语义分析
- 类型检查
- 类型推断
- 查看类型是否匹配
- 函数调用内联
- 逃逸分析
中间码生成:
- 为了处理不同平台的差异,先生成中间代码(SSA)
查看从代码到中间码(SSA)生成的整个过程
$env:GOSSAFUNC="main" # windows powershell
export GOSSAFUNC=main # linux
go build
会看到如下输出:
![![[从用户代码到中间码SSA生成过程查看命令.png]]](https://img-blog.csdnimg.cn/direct/a907e4cffcbc469da61c5f2b54cf0fa8.png)
用浏览器打开ssa.html文件:
![![[生成的中间码SSA的过程.png]]](https://img-blog.csdnimg.cn/direct/59a8757d1e4345d9b41a715faa8b4e5e.png)
sources就是你的源代码,AST就是生成的语法树,genssa就是生成的与平台无关的中间码SSA,当然中间还有很多的其它步骤,这里不再列举,可以点击展开查看
机器码生成:
- 先生成Plan9汇编代码(与平台相关)
- 最后编译为机器码
- 输出的机器码为.a文件
查看Plan9汇编代码
go build -gcflags -S main.go
链接:
- 将各个包进行链接,包括runtime,最终生成可执行文件
Go程序是如何运行起来的
Go程序的入口?
是下面的main方法吗?当然不是
func main() { fmt.Println("hello RdrB1te")
}
是runtime包下面的rt0_xxx.s文件,下面以Linux x86芯片架构上面运行的rt0_linux-amd64.s举例:
TEXT _rt0_amd64_linux(SB),NOSPLIT,$-8JMP _rt0_amd64(SB)
只要用了x86芯片架构都要进入到_rt0_amd64这个方法中去,这个方法调到了哪里呢,选中双击shift,打开在文件中查找:找到下面这行
![![[查找_rt0_amd64调用的位置.png]]](https://img-blog.csdnimg.cn/direct/196831cbace94bd2be91f34136edd1c8.png)
在asm_amd64.s这个文件中的这段代码:
TEXT _rt0_amd64(SB),NOSPLIT,$-8 MOVQ 0(SP), DI // argc LEAQ 8(SP), SI // argv JMP runtime·rt0_go(SB)
意思是读取命令行参数,复制参数数量argc和参数值argv到栈上,然后调用了runtime·rt0_go这个方法,这方法的位置就在这个文件的下面:
TEXT runtime·rt0_go(SB),NOSPLIT|TOPFRAME,$0 // copy arguments forward on an even stack MOVQ DI, AX // argc MOVQ SI, BX // argv SUBQ $(5*8), SP // 3args 2auto ANDQ $~15, SP MOVQ AX, 24(SP) MOVQ BX, 32(SP) // create istack out of the given (operating system) stack. // _cgo_init may update stackguard. MOVQ $runtime·g0(SB), DI
上面这段的意思时初始化g0执行栈,g0是为了调度协程而产生的协程,g0是每个Go程序的第一个协程。继续往下面看,找到下面这段:
CALL runtime·check(SB)
这行是第一次调用的go语言方法,要找到这个方法可以选中双击shift,找到下面这行:
![![[查找runtime.check方法.png]]](https://img-blog.csdnimg.cn/direct/1bacfba0f41e44b9bec66d83489a7aef.png)
进入:
func check(){}
check方法主要是做运行时检测:
- 检查各种类型的长度
- 检查指针操作
- 检查结构体字段的偏移量
- 检查atomic原子操作
- 检查CAS操作
- 检查栈大小是否是2的幂次
继续往下看,可以通过Ctrl+Alt+左右箭头进行快速跳转回退或前进,退到这个位置:
CALL runtime·check(SB) MOVL 24(SP), AX // copy argc
MOVL AX, 0(SP)
MOVQ 32(SP), AX // copy argv
MOVQ AX, 8(SP)
CALL runtime·args(SB)
CALL runtime·osinit(SB)
CALL runtime·schedinit(SB) // create a new goroutine to start program
MOVQ $runtime·mainPC(SB), AX // entry
PUSHQ AX
CALL runtime·newproc(SB)
POPQ AX
runtime·args(SB):参数初始化runtime.args,对命令行中的参数进行处理,参数数量赋值给argc int32,参数值复制给argv **byte
runtime·osinit:判断操作系统,执行相应的初始化组件,供调度器初始化所用
runtime·schedinit: 初始化Go调度器。初始化调度器会做哪些事情:
- 全局栈空间内存分配
- 加载命令行参数到 os.Args
- 堆内存空间的初始化
- 加载操作系统环境变量
- 初始化当前系统线程
- 垃圾回收器的参数初始化
- 算法初始化(map、hash)
- 设置 process 数量
继续往下看:
// create a new goroutine to start program MOVQ $runtime·mainPC(SB), AX // entry PUSHQ AX CALL runtime·newproc(SB) POPQ AX // start this M CALL runtime·mstart(SB) CALL runtime·abort(SB) // mstart should never return RET // mainPC is a function value for runtime.main, to be passed to newproc.
// The reference to runtime.main is made via ABIInternal, since the
// actual function (not the ABI0 wrapper) is needed by newproc.
DATA runtime·mainPC+0(SB)/8,$runtime·main<ABIInternal>(SB)
MOVQ $runtime·mainPC(SB):取mainPC的地址,这个mainPC的地址就是runtime·main这个方法的地址
CALL runtime·newproc:创建一个新的协程(主协程),执行runtime·main这个方法(主函数),放入调度器等待调度
CALL runtime·mstart(SB):初始化一个M,用来调度主协程,主协程开始执行主函数。
看下runtime·main这个方法里面干了什么,选中双击shift,找到下面这行:
![![[查找runtime·main方法.png]]](https://img-blog.csdnimg.cn/direct/d3a79591a1554981adda2c1a6dd0a6b8.png)
进入:
// The main goroutine.
func main() { doInit(&runtime_inittask) // 执行runtime包中的init方法gcenable() // 启动GC垃圾回收器doInit(&main_inittask) //执行用户包依赖的init方法fn := main_main // 执行用户主函数main.mian() fn()
}
按住ctrl进入main_main:
//go:linkname main_main main.main
func main_main()
主协程执行主函数:
- 执行runtime包中的init方法
- 启动GC垃圾回收器
- 执行用户包依赖的init方法
- 执行用户主函数
main.mian()
总结
- Go启动时经历了检查、各种初始化、初始化协程调度的过程
main.main()也是在协程中运行的
相关文章:
Go程序是如何编译并运行起来的(图文详解)
Go程序是如何编译的 从hello RdrB1te开始 package main import "fmt" func main() { fmt.Println("hello RdrB1te") }不实际编译它,只输出它的编译过程: go build -n简单的编译过程分析: 上面的过程确认了两个…...
程序员如何选择职业赛道
程序员的职业赛道就像是一座迷宫,有前端的美丽花园,后端的黑暗洞穴,还有数据科学的神秘密室。你准备好探索这个充满挑战和机遇的迷宫了吗?快来了解如何选择职业赛道吧! 方向一:自我评估与兴趣探索 选择适合…...
GOWIN软件使用
1、管脚复用 根据自己需求把复用管脚勾选上,管脚当普通管脚使用 JTAG设置成普通管脚,下载程序时候JTAGEN管脚需要上拉高电平(可以在下载器线上上拉个电阻,下载后把下载线拔走,否则JTAG管脚无法使用,管脚充…...
Ajax (1)
什么是Ajax: 浏览器与服务器进行数据通讯的技术,动态数据交互 axios库地址: <script src"https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script> 如何使用呢? 我们现有个感性的认识 <scr…...
Python基础语法:基本数据类型(数字类型和布尔类型)
在我们的日常生活中,经常会用到数字,所以数字(numbers)是 pytthon 中的一个基本数据类型。在 python 里面啊,numbers 这种数据类型是一个大类,在 numbers 这个大类下面有整型、浮点型(小数&…...
springboot 下载 Excel 文件的 Controller 层案例
环境 pom.xml 中 springboot版本: <parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.7.15</version></parent>Excel 文件依赖: &l…...
RabbitMQ队列
RabbitMQ队列 1、死信的概念 先从概念解释上搞清楚这个定义,死信,顾名思义就是无法被消费的消息,字面意思可以这样理解,一般来说,producer将消息投递到broker或者直接到queue里了,consumer 从 queue取出消息进行消…...
Day12:信息打点-Web应用源码泄漏开源闭源指纹识别GITSVNDS备份
目录 开源-CMS指纹识别源码获取方式 闭源-习惯&配置&特性等获取方式 闭源-托管资产平台资源搜索监控 思维导图 章节点 Web:语言/CMS/中间件/数据库/系统/WAF等 系统:操作系统/端口服务/网络环境/防火墙等 应用:APP对象/API接口/微…...
使用正确的技术和项目管理工具来定义项目范围
根据 PMI 的统计,34% 的项目会出现范围蔓延:悄悄增加超出范围的活动,威胁到利润空间、项目成功率和客户满意度。 预防和控制范围蔓延的方法之一,是首先明确界定项目范围。 项目范围是项目规划、资源调度和变更管理的重要步骤。然…...
【C++】类型转换和IO流
目录 C语言中的类型转换 C eplicit && volatitle eplicit volatile C强制类型转换 static_cast(相关类型) reinterpret_cast(不相关类型) const_cast(去掉const属性) dynamic_cast RTTI(了解) IO流 …...
leetCode刷题 5.最长回文子串
目录 1. 思路 2. 解题方法 3. 复杂度 4. Code 题目: 给你一个字符串 s,找到 s 中最长的回文子串。 如果字符串的反序与原始字符串相同,则该字符串称为回文字符串。 示例 1: 输入:s "babad" 输出&#x…...
计算机组成原理面试题
计算机组成原理是计算机科学的基础课程之一,涉及计算机系统的基本结构和工作原理。以下是一些可能出现在面试中的计算机组成原理相关题目: 1. **什么是冯诺依曼体系结构?** - 冯诺依曼体系结构是一种计算机组织架构,它将程序指…...
「Mybatis深入三」:高级查询-模糊查询
一、需求 根据username 模糊查询user 表 二、代码演示 1、方式1 数据库环境 CREATE DATABASE mybatis_db; USE mybatis_db; CREATE TABLE user (id INT(11) NOT NULL AUTO_INCREMENT,username VARCHAR(32) NOT NULL COMMENT 用户名称,birthday DATETIME DEFAULT NULL COMMEN…...
LabVIEW管道缺陷智能检测系统
LabVIEW管道缺陷智能检测系统 管道作为一种重要的输送手段,其安全运行状态对生产生活至关重要。然而,随着时间的推移和环境的影响,管道可能会出现老化、锈蚀、裂缝等多种缺陷,这些缺陷若不及时发现和处理,将严重威胁到…...
java在cmd中乱码的问题解决
本文深入探讨了在使用 Java 命令行(cmd)时可能出现的中文乱码问题,并提供了两种解决方案。首先,通过临时的方式,用户可以执行命令 chcp 936 选择字符集,然后再运行 Java 命令,确保在选择字符集过…...
OpenHarmony教程指南—ArkUI中组件、通用、动画、全局方法的集合
介绍 本示例为ArkUI中组件、通用、动画、全局方法的集合。 本示例使用 Tabs容器组件搭建整体应用框架,每个 TabContent内容视图 使用 div容器组件 嵌套布局,在每个 div 中使用 循环渲染 加载此分类下分类导航数据,底部导航菜单使用 TabCont…...
第二证券|金价逼近历史高点 黄金股价值有望重估
经过两个多月的震荡后,黄金打响新一波攻势,期货商场价格已逼近前史高点。 有分析认为,虽然黄金价格短期已有显着涨幅,存在震荡或许,但中长时间看,跟着美联储钱银政策的转向,黄金价格仍有上行动…...
关于51单片机晶振定时问题
单片机中晶振频率为12MHZ的机器周期怎么算? 1、系统晶振频率是12M,则机器周期=12/12=1us; 2、定时1ms=1*1000=1000us; 3、工作在方式1下:最大计数值是2&a…...
NoSQL--2.MongoDB配置(Windows版)
目录 2.MongdoDB配置 2.1 Windows环境下操作 2.1.1 注册MongDB Atlas: 2.1.2 MongoDB Community Server Download: 2.1.3 启动MondgoDB服务: 2.1.3.1 命令行参数的方式启动MongoDB服务: 2.1.3.2 使用配置文件方式启动Mongo…...
HTML静态网页成品作业(HTML+CSS)——安徽宣笔设计制作(5个页面)
🎉不定期分享源码,关注不丢失哦 文章目录 一、作品介绍二、作品演示三、代码目录四、网站代码HTML部分代码 五、源码获取 一、作品介绍 🏷️本套采用HTMLCSS,未使用Javacsript代码,共有6个页面。 🏷️想要…...
戴尔G15笔记本终极散热解决方案:TCC-G15开源温度控制中心完全指南
戴尔G15笔记本终极散热解决方案:TCC-G15开源温度控制中心完全指南 【免费下载链接】tcc-g15 Thermal Control Center for Dell G15 - open source alternative to AWCC 项目地址: https://gitcode.com/gh_mirrors/tc/tcc-g15 还在为戴尔G15笔记本玩游戏时过热…...
B站视频转文字终极指南:5分钟掌握高效知识管理神器
B站视频转文字终极指南:5分钟掌握高效知识管理神器 【免费下载链接】bili2text Bilibili视频转文字,一步到位,输入链接即可使用 项目地址: https://gitcode.com/gh_mirrors/bi/bili2text 你是否曾为了一段精彩的B站课程内容࿰…...
Linux环境下KingbaseES(人大金仓)数据库的自动化部署与配置实践
1. 为什么需要自动化部署KingbaseES? 第一次手动部署KingbaseES数据库的经历让我记忆犹新。那天我在机房折腾了整整6个小时,光是反复输入各种命令就让人抓狂,更别提中间因为权限问题重装了三次。相信很多DBA同行都有过类似的痛苦体验——手动…...
基于FONA808与Adafruit IO的实时GPS追踪系统实战
1. 项目概述与核心价值又到了一年一度的万圣节,孩子们最兴奋的“不给糖就捣蛋”活动即将上演。作为一个技术爱好者兼“鸡娃”家长,我每年都在琢磨怎么让这个传统活动变得更有趣、更高效。去年,我儿子抱怨说走了半天路,拿到的糖果却…...
DS18B20单总线温度传感器在CircuitPython中的实战应用指南
1. 项目概述与单总线协议的价值如果你正在用像Adafruit Feather M0 Express或Raspberry Pi Pico这类小巧的板子做项目,需要测量温度,DS18B20绝对是一个绕不开的经典选择。我这些年做过不少环境监测、智能家居的小玩意儿,从鱼缸水温到3D打印机…...
保姆级教程:用STM32+ESP8266+微信小程序,5分钟搞定Onenet数据上传与设备控制
零基础实战:STM32ESP8266微信小程序极速对接Onenet全指南 在物联网技术快速普及的今天,许多嵌入式开发者都希望快速搭建一个完整的智能设备系统。本文将带你用最简单的方式,通过STM32微控制器、ESP8266 WiFi模块和微信小程序,实现…...
从“早停”到“早退”:深度学习中两种效率优化策略的实战解析
1. 早停机制:训练过程的智能刹车系统 第一次接触早停机制是在处理一个图像分类项目时。当时我的模型在训练集上表现完美,验证集指标却开始下滑——典型的过拟合现象。早停机制就像给训练过程装了个智能刹车,当模型开始"死记硬背"训…...
441GB香港OSGB数据实战:从ContextCapture目录到Smart3D加载的完整指南
1. 441GB香港OSGB数据背景解析 第一次拿到441GB的香港OSGB数据时,我的硬盘指示灯疯狂闪烁了整整一晚上。这种规模的倾斜摄影数据在业内确实罕见,特别是覆盖香港565平方公里区域的完整数据集。实测发现,这套数据采用ContextCapture标准目录结构…...
告别重复劳动:用这个Maya Mel脚本插件,5分钟搞定Arnold材质批量调节
告别重复劳动:Maya Mel脚本插件在Arnold材质批量调节中的高效应用 在三维动画和视觉特效制作中,材质调节往往是项目后期最耗时的环节之一。当导演皱着眉头说"这个场景的金属感太强了"或者客户反馈"整体色调需要更暖一些"时…...
数字电路模块化设计的艺术:Logisim-evolution中的层次化抽象实践
数字电路模块化设计的艺术:Logisim-evolution中的层次化抽象实践 【免费下载链接】logisim-evolution Digital logic design tool and simulator 项目地址: https://gitcode.com/gh_mirrors/lo/logisim-evolution 在数字电路设计的世界里,复杂系统…...
