博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
go源码分析(一) 通过调试看go程序初始化过程
阅读量:5142 次
发布时间:2019-06-13

本文共 10996 字,大约阅读时间需要 36 分钟。

参考资料:

编写go语言test.go

package mainimport (	"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 filesSymbols 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 *0x44f4d0Breakpoint 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_goBreakpoint 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 nocpuinfonoavx:        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#endifneedtls:#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   // abortok:        // 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        RETDATA    runtime·mainPC+0(SB)/8,$runtime·main(SB)GLOBL   runtime·mainPC(SB),RODATA,$8

 设置断点runtime.main,接下来的代码是go语言写的了

(gdb) b runtime.mainBreakpoint 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        }}

 

转载于:https://www.cnblogs.com/Bin-DuS/p/9988749.html

你可能感兴趣的文章
wow 各职业体验(pvp)
查看>>
Streaming的receiver模式
查看>>
[转载]一个人的失败,99%失败于“脾气”
查看>>
【Nowcoder】玩游戏
查看>>
过滤器(Filter)
查看>>
字符串的操作
查看>>
性能优化之Java(Android)代码优化
查看>>
springMVC相关—文件上传
查看>>
由Oracle 11g SYSAUX 和 SYSTEM 表空间回收引发的联想
查看>>
uva 1416 Warfare And Logistics
查看>>
欲则不达
查看>>
盒子游戏
查看>>
OpenJudgeP1.10.08:病人排队__(刷题)_水题
查看>>
观察者模式
查看>>
Hadoop分布式文件系统中架构和设计要点汇总
查看>>
cout和printf
查看>>
UVa 10088 - Trees on My Island (pick定理)
查看>>
#C++PrimerPlus# Chapter11_Exersice4_mytimeV4
查看>>
iOS8 针对开发者所拥有的新特性汇总如下
查看>>
Jmeter + Grafana搭建实时监控可视化
查看>>