只想简单地写写,就不写的太复杂了。注释都在: https://github.com/jiajunhuang/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
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.checkruntime.argsruntime.osinitruntime.schedinitruntime.newproc
runtime.newprocruntime.mainPC
MOVQ $runtime·mainPC(SB), AX // entry
// 然后再下面就有:
DATA runtime·mainPC+0(SB)/8,$runtime·main(SB)
runtime.mainPCruntime.newproc
MachineProcessorGoroutineMG
TornadoAsyncIOTornadoAsyncIO@gen.coroutine
所以有了Go这种,在语言层面实现异步的方式(gevent其实与此十分类似)。
newprocsystemstack
// systemstack runs fn on a system stack.
// If systemstack is called from the per-OS-thread (g0) stack, or
// if systemstack is called from the signal handling (gsignal) stack,
// systemstack calls fn directly and returns.
// Otherwise, systemstack is being called from the limited stack
// of an ordinary goroutine. In this case, systemstack switches
// to the per-OS-thread stack, calls fn, and switches back.
// It is common to use a func literal as the argument, in order
// to share inputs and outputs with the code around the call
// to system stack:
//
// ... set up y ...
// systemstack(func() {
// x = bigcall(y)
// })
// ... use x ...
//
// systemstack如果是由g0调用,或者收到信号而调用,就会调用fn然后返回。
// 否则,systemstack切换到 per-OS-thread栈执行完fn之后,又切回去
//go:noescape
func systemstack(fn func())
newprocsystemstacknewproc1newproc1runtime.mainPCruntime.main
runtime.main
151 systemstack(func() {
152 newm(sysmon, nil)
153 })
system monitor
然后执行
- `runtime_init`。这个是动态生成的。
- `gcenable` 启动gc
- `main_init` 动态生成的。
- `main_main` 就是我们 `main` 包里的main函数了。
- 通过for循环确保 `&runningPanicDefers` 为0才退出。
- `exit` 退出。
_initimport
似乎到这里,整个启动流程就看完了。接下来我们跳到其中的细节去看。
thread cache mallocschedinit
findrunnableruntime1.goruntime2.goproc.gomheap.gomalloc.go
虽然看起来是Cython写的,其实是Python,当时为了练习一下Cython就全部加上了类型改了后缀名,没差。Python中实现协程 毕竟简单多了,方便理解。