Golang源码探索(一) 编译和调试源码

栏目: Go · 发布时间: 6年前

内容简介:GO可以说是近几年最热门的新兴语言之一了, 一般人看到这个系列的文章会通过研究golang的源代码来分析内部的实现原理,和CoreCLR不同的是, golang的源代码已经被很多人研究过了, 我将会着重研究他们未提到过的部分.

原文来自博客园 作者: q303248153

GO可以说是近几年最热门的新兴语言之一了, 一般人看到 分布式大数据 就会想到GO,

这个系列的文章会通过研究golang的源代码来分析内部的实现原理,

和CoreCLR不同的是, golang的源代码已经被很多人研究过了, 我将会着重研究他们未提到过的部分.

另一点和CoreCLR不同的是, golang的源代码 非常易懂 , 注释也 非常的丰富 ,

很明显Google的工程师在写代码的时候有考虑其他人会去看这份代码.

尽管代码非常易懂, 研究它们还是需要实际运行和调试才能得到更好的理解,

这个系列分析的golang源代码是Google官方的实现的1.9.2版本, 不适用于其他版本和gccgo等其他实现,

运行环境是Ubuntu 16.04 LTS 64bit.

编译golang源代码

go的源代码是用 go 写的, 编译也需要一个可运行的go.

首先我们从官网下载源代码和二进制文件.

注意两个压缩包解压出来文件夹名称都是go, 我们解压到以下目录:

源代码: ~/git_go/go_src
二进制: ~/git_go/go_bin
Golang源码探索(一) 编译和调试源码

image

编译go之前需要设置环境变量,

GOROOT_BOOTSTRAP 是go二进制文件夹的所在目录,

GO_GCFLAGS 是编译go时使用的参数.

export GOROOT_BOOTSTRAP=~/git_go/go_bin
export GO_GCFLAGS="-N -l"

这里的 -N 参数代表禁止优化, -l 参数代表禁止内联, go在编译目标程序的时候会嵌入运行时(runtime)的二进制,

禁止优化和内联可以让运行时(runtime)中的函数变得更容易调试.

都准备好以后就可以进入go的源代码文件夹执行 all.bash 编译了:

Golang源码探索(一) 编译和调试源码

image

编译的结果在 ~/git_go/go_src/bin 下:

Golang源码探索(一) 编译和调试源码

image

调试golang源代码

之前CoreCLR的系列中我使用了lldb, 在这个系列中我继续沿用这个调试器.

这个系列中使用的是lldb 4.0.

以以下源代码(hello.go)为例:

package main

import (
    "fmt"
    "time"
)

func printNumber(from, to int, c chan int) {
    for x := from; x <= to; x++ {
        fmt.Printf("%d\n", x)
        time.Sleep(1 * time.Millisecond)
    }
    c <- 0
}

func main() {
    c := make(chan int, 3)
    go printNumber(1, 3, c)
    go printNumber(4, 6, c)
    _, _ = <- c, <- c
}

编译源代码使用以下命令, 这里的 -l 参数的意思和上面一样, 如果有需要还可以加 -N 参数:

~/git_go/go_src/bin/go build -gcflags "-l" hello.go

编译后使用lldb运行:

lldb ./hello
Golang源码探索(一) 编译和调试源码

image

go里面的函数符号名称的命名规则是 包名称.函数名称 , 例如主函数的符号名称是 main.main , 运行时中的 newobject 的符号名称是 runtime.newobject .

首先给主函数下一个断点然后运行:

Golang源码探索(一) 编译和调试源码

image

可以看到成功的进入了主函数, 并且有源代码提示.

接下来给按文件名和行数来下断点:

Golang源码探索(一) 编译和调试源码

image

然后查看函数的汇编代码:

Golang源码探索(一) 编译和调试源码

image

关于lldb的命令可以查看 这篇文档 .

在我使用的环境中lldb可以正常的下断点, 步进和步过go代码或者汇编指令,

打印变量输出的值有可能是错的 , 即使不开启优化.

虽然打印变量这个功能不好用, 我们仍然可以直接让go输出我们想要的值,

例如修改 runtime/malloc.go 输出当前环境下arena|spans|bitmap区的大小:

Golang源码探索(一) 编译和调试源码

image

修改后进入 src 并执行 ./make.bash , 然后重新编译目标程序, 运行:

Golang源码探索(一) 编译和调试源码

image

可以看到当前环境下arena是512G, spans是512M, bitmap是16G.

这个方法虽然比较笨, 但是可以在任何情况下输出我们想要的值.

此外, go运行时(runtime)的源代码会包括在目标文件中,

例如你对 runtime.newobject 下断点可以对go自身的源代码进行调试.

参考链接

接下来我将分析golang的任务调度机制和三色GC的具体实现, 敬请期待.


以上所述就是小编给大家介绍的《Golang源码探索(一) 编译和调试源码》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Programming in Haskell

Programming in Haskell

Graham Hutton / Cambridge University Press / 2007-1-18 / GBP 34.99

Haskell is one of the leading languages for teaching functional programming, enabling students to write simpler and cleaner code, and to learn how to structure and reason about programs. This introduc......一起来看看 《Programming in Haskell》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具