F7cd8b70abe732dd742b0d844881dcc7
Golang runtime 源码分析

只想简单地写写,就不写的太复杂了。注释都在: https://github.com/jiajunhuang/go

  • Go的编译方式是静态编译,把runtime直接编译到最终的可执行文件里。首先我们把代码考过来,然后编译出 go 这个可执行文件出来。

  • 编写以下代码,然后用我们自己编译出来的go来编译出一个二进制文件。注意要带调试信息并且禁止优化的,要不然不方便看。

package main

import (
    "fmt"
)

func main() {
    fmt.Println("hello world!")
}
$ ../bin/go build -gcflags "-N -l" -o test_demo1 demo1.go
$ gdb test_demo1
(gdb) source /home/jiajun/Code/go/src/runtime/runtime-gdb.py
Loading Go Runtime support.
(gdb) info files
Symbols from "/home/jiajun/Code/go/analysis/test_demo1".
Local exec file:
    `/home/jiajun/Code/go/analysis/test_demo1', file type elf64-x86-64.
    Entry point: 0x44fa90
    0x0000000000401000 - 0x0000000000482608 is .text
    0x0000000000483000 - 0x00000000004c4e3f is .rodata
    0x00000000004c4f60 - 0x00000000004c5ac0 is .typelink
    0x00000000004c5ac0 - 0x00000000004c5b00 is .itablink
    0x00000000004c5b00 - 0x00000000004c5b00 is .gosymtab
    0x00000000004c5b00 - 0x0000000000514042 is .gopclntab
    0x0000000000515000 - 0x0000000000521bdc is .noptrdata
    0x0000000000521be0 - 0x00000000005286f0 is .data
    0x0000000000528700 - 0x0000000000544d88 is .bss
    0x0000000000544da0 - 0x00000000005474b8 is .noptrbss
    0x0000000000400f9c - 0x0000000000401000 is .note.go.buildid
(gdb) b *0x44fa90
Breakpoint 1 at 0x44fa90: file /home/jiajun/Code/go/src/runtime/rt0_linux_amd64.s, line 8.

然后就跳到 rt0_linux_amd64.s 看。虽然没有系统的学汇编,但是边看边猜还是可以继续看下去的。

TEXT _rt0_amd64_linux(SB),NOSPLIT,$-8
    JMP _rt0_amd64(SB)

然后发现 _rt0_amd64 继续不下去了。于是:

(gdb) b _rt0_amd64
Breakpoint 2 at 0x44c2b0: file /home/jiajun/Code/go/src/runtime/asm_amd64.s, line 15.

发现跳到了 rt0_go, 不过gdb直接打断点发现打不出来,于是就在同一个文件里尝试搜索。发现在:
https://github.com/jiajunhuang/go/blob/67a58c5a2401e89fd4f688e8f70fd3be9506cea5/src/runtime/asm_amd64.s#L87

  • 继续跟踪,发现有标签,最后到了 ok 这个标签。
(gdb) b runtime.g0
Function "runtime.g0" not defined.
Make breakpoint pending on future shared library load? (y or [n]) n
(gdb) b runtime.m0
Function "runtime.m0" not defined.
Make breakpoint pending on future shared library load? (y or [n]) n
(gdb) b runtime.check
Breakpoint 3 at 0x434890: file /home/jiajun/Code/go/src/runtime/runtime1.go, line 141.
(gdb) b runtime.args
Breakpoint 4 at 0x434340: file /home/jiajun/Code/go/src/runtime/runtime1.go, line 65.
(gdb) b runtime.osinit
Breakpoint 5 at 0x424750: file /home/jiajun/Code/go/src/runtime/os_linux.go, line 274.
(gdb) b runtime.schedinit
Breakpoint 6 at 0x428b30: file /home/jiajun/Code/go/src/runtime/proc.go, line 508.
(gdb) b runtime.mainPC
Function "runtime.mainPC" not defined.
Make breakpoint pending on future shared library load? (y or [n]) n
(gdb) b runtime.main
Breakpoint 7 at 0x427980: file /home/jiajun/Code/go/src/runtime/proc.go, line 131.
(gdb) b runtime.newproc
Breakpoint 8 at 0x42f540: file /home/jiajun/Code/go/src/runtime/proc.go, line 3321.
(gdb) b runtime.mstart
Breakpoint 9 at 0x42a920: file /home/jiajun/Code/go/src/runtime/proc.go, line 1208.

因此函数调用链是:

runtime.check -> runtime.args -> runtime.osinit -> runtime.schedinit -> runtime.newproc

最后一步里的 runtime.newproc 之前有把 runtime.mainPC 压栈。

MOVQ    $runtime·mainPC(SB), AX     // entry

// 然后再下面就有:
DATA    runtime·mainPC+0(SB)/8,$runtime·main(SB)
top Created with Sketch.