1 调试和源码分析
不同的平台,会执行不同的初始化代码,然后跳到golang的main函数。本次验证过程是基于CentOS 7平台。
测试代码如下:
package main
func main() {
println("hello, wenTao!")
}
执行编码,禁止优化
go build -gcflags "-N -l" main.go
找入口
[root@VM_0_14_centos opt]# gdb main
GNU gdb (GDB) Red Hat Enterprise Linux 7.6.1-80.el7
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-redhat-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /opt/main...done.
Loading Go Runtime support.
(gdb) source /usr/lib/golang/src/runtime/runtime-gdb.py
Loading Go Runtime support.
(gdb) info files
Symbols from "/opt/main".
Local exec file:
`/opt/main', file type elf64-x86-64.
Entry point: 0x44a4c0
0x0000000000401000 - 0x000000000044ec6f is .text
0x000000000044f000 - 0x0000000000478dd5 is .rodata
0x0000000000478f80 - 0x0000000000479654 is .typelink
0x0000000000479658 - 0x0000000000479660 is .itablink
0x0000000000479660 - 0x0000000000479660 is .gosymtab
0x0000000000479660 - 0x00000000004b6bfb is .gopclntab
0x00000000004b7000 - 0x00000000004b7c08 is .noptrdata
0x00000000004b7c20 - 0x00000000004b9950 is .data
0x00000000004b9960 - 0x00000000004d5c70 is .bss
0x00000000004d5c80 - 0x00000000004d8378 is .noptrbss
0x0000000000400f9c - 0x0000000000401000 is .note.go.buildid
(gdb) b *0x44a4c0
Breakpoint 1 at 0x44a4c0: file /usr/lib/golang/src/runtime/rt0_linux_amd64.s, line 8.
(gdb)
执行一段汇编代码之后会跳到ok标签(具体参考:Go源码分析1- 引导程序),在文件src/runtime/asm_amd64.s
ok:
// set the per-goroutine and per-mach "registers"
get_tls(BX)
LEAQ runtime·g0(SB), CX
MOVQ CX, g(BX)
LEAQ runtime·m0(SB), AX
// save m->g0 = g0
MOVQ CX, m_g0(AX)
// save m0 to g0->m
MOVQ AX, g_m(CX)
CLD // convention is D is always left cleared
CALL runtime·check(SB)
MOVL 16(SP), AX // copy argc
MOVL AX, 0(SP)
MOVQ 24(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
PUSHQ $0 // arg size
CALL runtime·newproc(SB)
POPQ AX
POPQ AX
// start this M
CALL runtime·mstart(SB)
CALL runtime·abort(SB) // mstart should never return
RET
// Prevent dead-code elimination of debugCallV1, which is
// intended to be called by debuggers.
MOVQ $runtime·debugCallV1(SB), AX
RET
执行runtime.check
(gdb) b runtime.check
Breakpoint 2 at 0x434c60: file /opt/go/src/runtime/runtime1.go, line 136.
执行runime.args
(gdb) b runtime.args
Breakpoint 5 at 0x430610: file /usr/lib/golang/src/runtime/runtime1.go, line 60.
执行runtime.osinit
(gdb) b runtime.osinit
Breakpoint 4 at 0x423170: file /opt/go/src/runtime/os_linux.go, line 289.
获取CPU核数和内存页大小
func osinit() {
ncpu = getproccount()
physHugePageSize = getHugePageSize()
}
执行runtime.schedinit
(gdb) b runtime.schedinit
Breakpoint 5 at 0x428dc0: file /opt/go/src/runtime/proc.go, line 532.
做了表多的前期工作,有时间慢慢分析,初步计划分析内存管理部分,和gc部分。
// The bootstrap sequence is:
//
// call osinit
// call schedinit
// make & queue new G
// call runtime·mstart
//
// The new G calls runtime·main.
func schedinit() {
// raceinit must be the first call to race detector.
// In particular, it must be done before mallocinit below calls racemapshadow.
_g_ := getg()
if raceenabled {
_g_.racectx, raceprocctx0 = raceinit()
}
sched.maxmcount = 10000
tracebackinit()
moduledataverify()
stackinit()
mallocinit()
mcommoninit(_g_.m)
cpuinit() // must run before alginit
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()
parsedebugvars()
gcinit()
sched.lastpoll = uint64(nanotime())
procs := ncpu
if n, ok := atoi32(gogetenv("GOMAXPROCS")); ok && n > 0 {
procs = n
}
if procresize(procs) != nil {
throw("unknown runnable goroutine during bootstrap")
}
// For cgocheck > 1, we turn on the write barrier at all times
// and check all pointer writes. We can't do this until after
// procresize because the write barrier needs a P.
if debug.cgocheck > 1 {
writeBarrier.cgo = true
writeBarrier.enabled = true
for _, p := range allp {
p.wbBuf.reset()
}
}
if buildVersion == "" {
// Condition should never trigger. This code just serves
// to ensure runtime·buildVersion is kept in the resulting binary.
buildVersion = "unknown"
}
if len(modinfo) == 1 {
// Condition should never trigger. This code just serves
// to ensure runtime·modinfo is kept in the resulting binary.
modinfo = ""
}
}
执行runtime.newproc
(gdb) b runtime.newproc
Breakpoint 6 at 0x42f7a0: file /opt/go/src/runtime/proc.go, line 3371.
执行runtime.mstart
(gdb) b runtime.mstart
Breakpoint 7 at 0x42a3a0: file /opt/go/src/runtime/proc.go, line 1069.
参考: