go 引导、启动与初始化

本文是《循序渐进go语言》第三篇-go 引导、启动与初始化。本文将结合一个最简单的例子,看下go底层是如何启动的,又是如何执行的。

1 一个小例子

package main

func main() {
    println("hello")
}

如此简单的例子,底层是如何执行的呢?

2 gdb出场

先编译一下文件:

go build test.go

生成可执行文件 test
然后我们使用 gdb进行调试。

gdb test

3 流程分析

3.1 入口在哪儿?

首先我们找一下程序的入口:
在gdb环境下,执行如下指令

info files

可以得到如下结果:


entrypoint.png

如图所示:入口(Entry point )在 0x1047f80。
那我们在entry Point 这个地方打一个断点。

b *0x1047f80

结果是

file /Users/zhangpeng/golang/go/src/runtime/rt0_darwin_amd64.s, line 8

没错,这就是程序的入口,并不是我们想的main.main 函数。

3.2 rt0_darwin_amd64.s 干了什么?

代码比较少,直接贴出来吧

TEXT _rt0_amd64_darwin(SB),NOSPLIT,$-8
    LEAQ    8(SP), SI // argv
    MOVQ    0(SP), DI // argc
    MOVQ    $main(SB), AX
    JMP AX

设置参数,执行main(SB)。main(SB) 也比较简洁

TEXT main(SB),NOSPLIT,$-8
    MOVQ    $runtime·rt0_go(SB), AX
    JMP AX

那我们看下$runtime·rt0_go 具体的位置在哪儿

(gdb) b runtime.rt0_go
Breakpoint 2 at 0x10447b0: file /Users/zhangpeng/golang/go/src/runtime/asm_amd64.s, line 12.

这儿包含了初始化与执行的核心逻辑。我们先列一下主流程【次要代码省略】,然后一个一个看。

TEXT runtime·rt0_go(SB),NOSPLIT,$0
    ...
nocgo:
    ...
    BL  runtime·check(SB) // 只是做了一些简单的check, 这儿不做分析

    ...
    BL  runtime·args(SB)
    BL  runtime·osinit(SB)
    BL  runtime·schedinit(SB)

    // create a new goroutine to start program
    // 创建main goroutine 用于执行runtime.main
    MOVD    $runtime·mainPC(SB), R0     // entry
    ...
    BL  runtime·newproc(SB)
    ...

    // start this M 让当前线程开始执行main goroutine
    BL  runtime·mstart(SB)

    ...

看看它们具体在哪儿

(gdb) b runtime.args
Breakpoint 4 at 0x102f540: file /Users/zhangpeng/golang/go/src/runtime/runtime1.go, line 61.
(gdb) b runtime.osinit
Breakpoint 5 at 0x101fd90: file /Users/zhangpeng/golang/go/src/runtime/os_darwin.go, line 48.
(gdb) b runtime.schedinit
Breakpoint 6 at 0x10251d0: file /Users/zhangpeng/golang/go/src/runtime/proc.go, line 463.
(gdb) b runtime.mainPC
Breakpoint 7 at 0x106c928
(gdb) b runtime.mstart
Breakpoint 8 at 0x1026b60: file /Users/zhangpeng/golang/go/src/runtime/proc.go, line 1133.
(gdb) b runtime.main
Breakpoint 9 at 0x1023d20: file /Users/zhangpeng/golang/go/src/runtime/proc.go, line 106.
(gdb) b main.main
Breakpoint 10 at 0x104bfe0: file /Users/zhangpeng/goProject/test.go, line 3.
(gdb) b runtime.newproc
Breakpoint 14 at 0x102af10: file /Users/zhangpeng/golang/go/src/runtime/proc.go, line 2842.
3.2.1 runtime·args

只是将参数复制了一下。

3.2.2 runtime·osinit

做了两件事情:获取cpu核数, 设置pagesize 。 没有做其他事情。

3.2.3 runtime·schedinit

其主要的作用是新定义一个go routine, 去调用runtime.main。
在这个方法里面,做了好多的初始化,这儿我们先简单罗列一下,后续分析到具体模块时,应该还会再回来看这部分。

// 栈、内存分配器、调度器相关初始化
    tracebackinit()
    moduledataverify()
    stackinit()
    mallocinit()
    mcommoninit(_g_.m)
    alginit()       // maps must not be used before this call
    modulesinit()   // provides activeModules
    typelinksinit() // uses maps, activeModules
    itabsinit()     // uses activeModules

    msigsave(_g_.m)
    initSigmask = _g_.m.sigmask
// 处理命令行参数和环境变量
    goargs()
    goenvs()
// 处理GODEBUG、GOTRACEBACK相关的环境变量设置
    parsedebugvars()
// 垃圾回收相关处理
    gcinit()
3.2.4 执行runtime.main

核心代码在 /Users/zhangpeng/golang/go/src/runtime/proc.go, line 106.

func main() {
    println("welcome to zp'go source world~~~")
    g := getg()

    ...
    runtime_init() // must be before defer

    ...
    gcenable()  // gc启动

    ...

    fn := main_init // make an indirect call, as the linker doesn't know the address of the main package when laying down the runtime
    fn()
    ...
    fn = main_main // make an indirect call, as the linker doesn't know the address of the main package when laying down the runtime
    fn()
    ...
}
3.2.4.1 runtime_init

如《Go语言学习笔记》中所述,我们看看最终生成的代码中有多少runtime.init

go tool objdump -s "runtime\.init\b"

结果是

TEXT runtime.init.1(SB) /Users/zhangpeng/golang/go/src/runtime/cpuflags_amd64.go
    ...
TEXT runtime.init.2(SB) /Users/zhangpeng/golang/go/src/runtime/mstats.go
    ...
TEXT runtime.init.3(SB) /Users/zhangpeng/golang/go/src/runtime/panic.go
    ...
TEXT runtime.init.4(SB) /Users/zhangpeng/golang/go/src/runtime/proc.go
    ...
TEXT runtime.init.5(SB) /Users/zhangpeng/golang/go/src/runtime/signal_unix.go
    ...
TEXT runtime.init(SB) /Users/zhangpeng/golang/go/src/runtime/write_err.go
    ...

看了下,总共上面六处。
我又反查了runtime 文件目录下的init函数
指令

cd $HOME/golang/go/src/runtime
git grep " init() " | grep -v "test"

得到如下结果:


image.png

应该是有几个没有用到而已。
按照《Go语言学习笔记》的总结:

runtime.init 主要是执行runtime内的init函数。

3.2.4.2 main_init

类似的操作,看下main.init 到底做了什么?


main_init

我们的例子比较简单,《Go语言学习笔记》 上举例一个例子,你可以自己去copy一下代码,然后执行途中的命令,就会发现main.init 做了好几次。
直接给结论吧

main.init 调用非runtime包的初始化参数,包括引用的第三方类库、标准库的init函数。

3.2.4.3 main_main

最后的最后,开始执行main包的main函数。

4 总结

本文使用gdb工具,对一个简单的go demo做了调试。从go引导启动,初始化,一直追到main.main函数。 希望对你有用~

5 参考文献

(1)《Go语言学习笔记》
(2) go 源码

6 其他

本文是《循序渐进go语言》的第三篇-《go 引导、启动与初始化》。
如果有疑问,可以直接留言,也可以关注公众号 “链人成长chainerup” 提问留言,或者加入知识星球“链人成长” 与我深度链接~

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,802评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,109评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,683评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,458评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,452评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,505评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,901评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,550评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,763评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,556评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,629评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,330评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,898评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,897评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,140评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,807评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,339评论 2 342

推荐阅读更多精彩内容