go源码分析(一) 通过调试看go程序初始化过程
编写go语言test.go
package main
import (
"fmt"
)
func main(){
fmt.Println("Hello World")
}
带调试的编译代码
go build -gcflags "-N -l" -o test test.go
使用gdb进行调试 输入info files 查看入口点,
对于同一个程序来说 每一次运行的入口点是一样的,表明这是一个将对位置,
通过对代码的修改也不能改变,这个入口点可能是编译后的程序入口,与其他代码无关
更换编译器,Entry point 发生了变化,和编译器有关。
gdb test
(gdb) info files
Symbols from "/root/test/test".
Local exec file:
`/root/test/test', file type elf64-x86-64.
Entry point: 0x44f4d0
0x0000000000401000 - 0x0000000000482178 is .text
0x0000000000483000 - 0x00000000004c4a5a is .rodata
0x00000000004c4b80 - 0x00000000004c56c8 is .typelink
0x00000000004c56c8 - 0x00000000004c5708 is .itablink
0x00000000004c5708 - 0x00000000004c5708 is .gosymtab
0x00000000004c5720 - 0x000000000051343f is .gopclntab
0x0000000000514000 - 0x0000000000520bdc is .noptrdata
0x0000000000520be0 - 0x00000000005276f0 is .data
0x0000000000527700 - 0x0000000000543d88 is .bss
0x0000000000543da0 - 0x0000000000546438 is .noptrbss
0x0000000000400f9c - 0x0000000000401000 is .note.go.buildid
设置断点 b *0x44f4d0 每个程序的入口点可能不一样
(gdb) b *0x44f4d0
Breakpoint 1 at 0x44f4d0: file /usr/local/go/src/runtime/rt0_linux_amd64.s, line 8.
可以查看文件 /usr/local/go/src/runtime/rt0_linux_amd64.s
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. #include "textflag.h" TEXT _rt0_amd64_linux(SB),NOSPLIT,$-8
JMP _rt0_amd64(SB) 上一步的断点位置,也就是入口 TEXT _rt0_amd64_linux_lib(SB),NOSPLIT,$0
JMP _rt0_amd64_lib(SB)
设置断点runtime.rt0_go
(gdb) b runtime.rt0_go
Breakpoint 2 at 0x44be10: file /usr/local/go/src/runtime/asm_amd64.s, line 89.
查看/usr/local/go/src/runtime/asm_amd64.s 也就是函数真正的入口,汇编语言写的
TEXT runtime·rt0_go(SB),NOSPLIT,$0
// copy arguments forward on an even stack
MOVQ DI, AX // argc
MOVQ SI, BX // argv
SUBQ $(4*8+7), SP // 2args 2auto
ANDQ $~15, SP
MOVQ AX, 16(SP)
MOVQ BX, 24(SP) // create istack out of the given (operating system) stack.
// _cgo_init may update stackguard.
MOVQ $runtime·g0(SB), DI
LEAQ (-64*1024+104)(SP), BX
MOVQ BX, g_stackguard0(DI)
MOVQ BX, g_stackguard1(DI)
MOVQ BX, (g_stack+stack_lo)(DI)
MOVQ SP, (g_stack+stack_hi)(DI) // find out information about the processor we're on
MOVL $0, AX
CPUID
MOVL AX, SI
CMPL AX, $0
JE nocpuinfo // Figure out how to serialize RDTSC.
// On Intel processors LFENCE is enough. AMD requires MFENCE.
// Don't know about the rest, so let's do MFENCE.
CMPL BX, $0x756E6547 // "Genu"
JNE notintel
CMPL DX, $0x49656E69 // "ineI"
JNE notintel
CMPL CX, $0x6C65746E // "ntel"
JNE notintel
MOVB $1, runtime·isIntel(SB)
MOVB $1, runtime·lfenceBeforeRdtsc(SB)
notintel: // Load EAX=1 cpuid flags
MOVL $1, AX
CPUID
MOVL AX, runtime·processorVersionInfo(SB) TESTL $(1<<26), DX // SSE2
SETNE runtime·support_sse2(SB) TESTL $(1<<9), CX // SSSE3
SETNE runtime·support_ssse3(SB) TESTL $(1<<19), CX // SSE4.1
SETNE runtime·support_sse41(SB) TESTL $(1<<20), CX // SSE4.2
SETNE runtime·support_sse42(SB) TESTL $(1<<23), CX // POPCNT
SETNE runtime·support_popcnt(SB) TESTL $(1<<25), CX // AES
SETNE runtime·support_aes(SB) TESTL $(1<<27), CX // OSXSAVE
SETNE runtime·support_osxsave(SB) // If OS support for XMM and YMM is not present
// support_avx will be set back to false later.
TESTL $(1<<28), CX // AVX
SETNE runtime·support_avx(SB) eax7:
// Load EAX=7/ECX=0 cpuid flags
CMPL SI, $7
JLT osavx
MOVL $7, AX
MOVL $0, CX
CPUID TESTL $(1<<3), BX // BMI1
SETNE runtime·support_bmi1(SB) // If OS support for XMM and YMM is not present
// support_avx2 will be set back to false later.
TESTL $(1<<5), BX
SETNE runtime·support_avx2(SB) TESTL $(1<<8), BX // BMI2
SETNE runtime·support_bmi2(SB) TESTL $(1<<9), BX // ERMS
SETNE runtime·support_erms(SB) osavx:
CMPB runtime·support_osxsave(SB), $1
JNE noavx
MOVL $0, CX
// For XGETBV, OSXSAVE bit is required and sufficient
XGETBV
ANDL $6, AX
CMPL AX, $6 // Check for OS support of XMM and YMM registers.
JE nocpuinfo
noavx:
MOVB $0, runtime·support_avx(SB)
MOVB $0, runtime·support_avx2(SB) nocpuinfo:
// if there is an _cgo_init, call it.
MOVQ _cgo_init(SB), AX
TESTQ AX, AX
JZ needtls
// g0 already in DI
MOVQ DI, CX // Win64 uses CX for first parameter
MOVQ $setg_gcc<>(SB), SI
CALL AX // update stackguard after _cgo_init
MOVQ $runtime·g0(SB), CX
MOVQ (g_stack+stack_lo)(CX), AX
ADDQ $const__StackGuard, AX
MOVQ AX, g_stackguard0(CX)
MOVQ AX, g_stackguard1(CX) #ifndef GOOS_windows
JMP ok
#endif
needtls:
#ifdef GOOS_plan9
// skip TLS setup on Plan 9
JMP ok
#endif
#ifdef GOOS_solaris
// skip TLS setup on Solaris
JMP ok
#endif LEAQ runtime·m0+m_tls(SB), DI
CALL runtime·settls(SB) // store through it, to make sure it works
get_tls(BX)
MOVQ $0x123, g(BX)
MOVQ runtime·m0+m_tls(SB), AX
CMPQ AX, $0x123
JEQ 2(PC)
MOVL AX, 0 // abort
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) MOVL $0xf1, 0xf1 // crash
RET DATA runtime·mainPC+0(SB)/8,$runtime·main(SB)
GLOBL runtime·mainPC(SB),RODATA,$8
设置断点runtime.main,接下来的代码是go语言写的了
(gdb) b runtime.main
Breakpoint 3 at 0x427700: file /usr/local/go/src/runtime/proc.go, line 109
查看/usr/local/go/src/runtime/proc.go文件
func main() {
g := getg() // Racectx of m0->g0 is used only as the parent of the main goroutine.
// It must not be used for anything else.
g.m.g0.racectx = 0 // Max stack size is 1 GB on 64-bit, 250 MB on 32-bit.
// Using decimal instead of binary GB and MB because
// they look nicer in the stack overflow failure message.
if sys.PtrSize == 8 {//判断机器是32位还是64位,可以通过指针的长度进行判断,64位为8
maxstacksize = 1000000000
} else {
maxstacksize = 250000000
} // Allow newproc to start new Ms.
mainStarted = true systemstack(func() {
newm(sysmon, nil)
}) // Lock the main goroutine onto this, the main OS thread,
// during initialization. Most programs won't care, but a few
// do require certain calls to be made by the main thread.
// Those can arrange for main.main to run in the main thread
// by calling runtime.LockOSThread during initialization
// to preserve the lock.
lockOSThread() if g.m != &m0 {
throw("runtime.main not on m0")
} runtime_init() // must be before defer
if nanotime() == 0 {
throw("nanotime returning zero")
} // Defer unlock so that runtime.Goexit during init does the unlock too.
needUnlock := true
defer func() {
if needUnlock {
unlockOSThread()
}
}() // Record when the world started. Must be after runtime_init
// because nanotime on some platforms depends on startNano.
runtimeInitTime = nanotime() gcenable() main_init_done = make(chan bool)
if iscgo {
if _cgo_thread_start == nil {
throw("_cgo_thread_start missing")
}
if GOOS != "windows" {
if _cgo_setenv == nil {
throw("_cgo_setenv missing")
}
if _cgo_unsetenv == nil {
throw("_cgo_unsetenv missing")
}
}
if _cgo_notify_runtime_init_done == nil {
throw("_cgo_notify_runtime_init_done missing")
}
// Start the template thread in case we enter Go from
// a C-created thread and need to create a new thread.
startTemplateThread()
cgocall(_cgo_notify_runtime_init_done, nil)
} 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()
close(main_init_done) needUnlock = false
unlockOSThread() if isarchive || islibrary {
// A program compiled with -buildmode=c-archive or c-shared
// has a main, but it is not executed.
return
}
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()
if raceenabled {
racefini()
} // Make racy client program work: if panicking on
// another goroutine at the same time as main returns,
// let the other goroutine finish printing the panic trace.
// Once it does, it will exit. See issues 3934 and 20018.
if atomic.Load(&runningPanicDefers) != 0 {
// Running deferred functions should not take long.
for c := 0; c < 1000; c++ {
if atomic.Load(&runningPanicDefers) == 0 {
break
}
Gosched()
}
}
if atomic.Load(&panicking) != 0 {
gopark(nil, nil, "panicwait", traceEvGoStop, 1)
} exit(0)
for {
var x *int32
*x = 0
}
}
go源码分析(一) 通过调试看go程序初始化过程的更多相关文章
- 鸿蒙内核源码分析(信号生产篇) | 信号安装和发送过程是怎样的? | 百篇博客分析OpenHarmony源码 | v48.03
百篇博客系列篇.本篇为: v48.xx 鸿蒙内核源码分析(信号生产篇) | 年过半百,依然活力十足 | 51.c.h .o 进程管理相关篇为: v02.xx 鸿蒙内核源码分析(进程管理篇) | 谁在管 ...
- Orchard源码分析(5.1):Host初始化(DefaultOrchardHost.Initialize方法)
概述 Orchard作为一个可扩展的CMS系统,是由一系列的模块(Modules)或主题(Themes)组成,这些模块或主题统称为扩展(Extensions).在初始化或运行时需要对扩展进行安装:De ...
- Netty源码分析 (六)----- 客户端连接接入accept过程
通读本文,你会了解到1.netty如何接受新的请求2.netty如何给新请求分配reactor线程3.netty如何给每个新连接增加ChannelHandler netty中的reactor线程 ne ...
- Flink源码分析 - 剖析一个简单的Flink程序
本篇文章首发于头条号Flink程序是如何执行的?通过源码来剖析一个简单的Flink程序,欢迎关注头条号和微信公众号"大数据技术和人工智能"(微信搜索bigdata_ai_tech) ...
- spring源码分析之玩转ioc:bean初始化和依赖注入(一)
最近赶项目,天天加班到十一二点,终于把文档和代码都整完了,接上继续整. 上一篇聊了beanProcess的注册以及对bean的自定义修改和添加,也标志着创建bean的准备工作都做好了,接下来就是开大招 ...
- WebRTC 源码分析(五):安卓 P2P 连接过程和 DataChannel 使用
从本篇起,我们将迈入新的领域:网络传输.首先我们看看 P2P 连接的建立过程,以及 DataChannel 的使用,最终我们会利用 DataChannel 实现一个 P2P 的文字聊天功能. P2P ...
- Android4.0 Launcher 源码分析2——Launcher内容加载绑定详细过程
Launcher在应用启动的时候,需要加载AppWidget,shortcut等内容项,通过调用LauncherModel.startLoader(),开始加载的工作.launcherModel中加载 ...
- 源码分析之struts1自定义方法的使用与执行过程
最近有人问我,你做项目中用户的一个请求是怎么与struts1交互的,我说请求的url中包含了action的名字和方法名,这样就可以找到相应方法,执行并返回给用户了. 他又问,那struts1中有什么方 ...
- Orchard源码分析(5):Host相关(Orchard.Environment.DefaultOrchardHost类)
概述 Host 是应用程序域级的单例,代表了Orchard应用程序.其处理应用程序生命周期中的初始化.BeginRequest事件.EndRequest事件等. 可以简单理解为HttpApplicat ...
随机推荐
- [Redis] Redis哨兵模式部署 - zz胖的博客
1. 部署Redis集群 redis的安装及配置参考[redis部署] 本文以创建一主二从的集群为例. 1.1 部署与配置 先创建sentinel目录,在该目录下创建8000,8001,8002三个以 ...
- IDEA无法启动:Failed to create JVM:error code -1
转自:https://blog.csdn.net/u013243986/article/details/52296944 随便设置把内存加大了, 结果idea就奔溃了,再打开时就提示这样的错误,Fai ...
- FOR xml path 这么爽的SQL命令,居然今天才知道
select stuff((select ControlName from Base_Controls FOR xml path('')),1,1,'')
- win7图片只显示图标不显示预览图解决方案
问题描述: win7上图片只显示图标,不显示缩略图:不管是调节小图.中图还是大图或者其他均不显示:而且这种情况下使用截图工具截下来的图片都不自动带上扩展名:情况如下图: 解决方案: 打开计算机-> ...
- 6. Go 语言中结构体的使用
1. 结构体的定义格式 在go语言中结果的定义格式如下: 123 type structName struct { filedList} 列子如下: 1234 type Person struct { ...
- API网关Kong
官网:https://konghq.com/ 各种方式安装汇总:https://konghq.com/install/ 命令列表:https://docs.konghq.com/0.14.x/admi ...
- OSX编译安装Python3及虚拟开发环境Virtualenv
0X00.前言 因为工作原因,最近主要做Python开发,刚好电脑系统重装之后所有的东西都需要重新配置.此文主要记录OSX下通过源码编译安装Python3以及安装虚拟开发环境Virtualenv. 0 ...
- Autotestplat.com 更新了!
1 提供测试发帖留言功能 2 自动化平台体验功能 3 提供招聘资讯功能 4 提供推荐书籍功能
- 算法小练#1 - Dany Yang
开始记录每周做过的算法题,这是第一周,新的开始 1021. 删除最外层的括号 题目要求如下: 有效括号字符串为空 ("")."(" + A + ")& ...
- 恭喜你,Get到一份 正则表达式 食用指南
先赞后看,养成习惯 前言 正则表达式 正则表达式: 定义一个搜索模式的字符串. 正则表达式可以用于搜索.编辑和操作文本. 正则对文本的分析或修改过程为:首先正则表达式应用的是文本字符串(text/st ...