得到Go程序的汇编代码的方法

简介: 有多种方式可以获得Go程序的汇编代码, 尽管输出的格式有些不同,但是都是方便阅读的汇编代码,可以帮助我们更好的了解程序的底层运行方式。我们看下面一段代码, 它是sync.Once的实现,去掉了不必要的注释,复制出来用来研究的一段小代码:once.

有多种方式可以获得Go程序的汇编代码, 尽管输出的格式有些不同,但是都是方便阅读的汇编代码,可以帮助我们更好的了解程序的底层运行方式。

我们看下面一段代码, 它是sync.Once的实现,去掉了不必要的注释,复制出来用来研究的一段小代码:

once.go
 1type Once struct {
 2    m    sync.Mutex
 3    done uint32
 4}
 5func (o *Once) Do(f func()) {
 6    if atomic.LoadUint32(&o.done) == 1 {
 7        return
 8    }
 9    o.m.Lock()
10    defer o.m.Unlock()
11    if o.done == 0 {
12        defer atomic.StoreUint32(&o.done, 1)
13        f()
14    }
15}

方法一: go tool compile
使用go tool compile -N -l -S once.go生成汇编代码:

 1"".(*Once).Do STEXT size=239 args=0x10 locals=0x28
 2    0x0000 00000 (once.go:13)   TEXT    "".(*Once).Do(SB), $40-16
 3    0x0000 00000 (once.go:13)   MOVQ    (TLS), CX
 4    0x0009 00009 (once.go:13)   CMPQ    SP, 16(CX)
 5    0x000d 00013 (once.go:13)   JLS 229
 6    0x0013 00019 (once.go:13)   SUBQ    $40, SP
 7    0x0017 00023 (once.go:13)   MOVQ    BP, 32(SP)
 8    0x001c 00028 (once.go:13)   LEAQ    32(SP), BP
 9    0x0021 00033 (once.go:13)   FUNCDATA    $0, gclocals·fdbf1f5761f6d17e8ae3f0aaecb6a3c5(SB)
10    0x0021 00033 (once.go:13)   FUNCDATA    $1, gclocals·7d2d5fca80364273fb07d5820a76fef4(SB)
11    0x0021 00033 (once.go:13)   FUNCDATA    $3, gclocals·96839595c383af6ae8227769d90a999e(SB)
12    0x0021 00033 (once.go:14)   PCDATA  $2, $1
13    0x0021 00033 (once.go:14)   PCDATA  $0, $0
14    0x0021 00033 (once.go:14)   MOVQ    "".o+48(SP), AX
15    0x0026 00038 (once.go:14)   MOVL    8(AX), CX
16    0x0029 00041 (once.go:14)   CMPL    CX, $1
17    0x002c 00044 (once.go:14)   JEQ 213
18    0x0032 00050 (once.go:18)   PCDATA  $2, $0
19    0x0032 00050 (once.go:18)   MOVQ    AX, (SP)
20    0x0036 00054 (once.go:18)   CALL    sync.(*Mutex).Lock(SB)
21    0x003b 00059 (once.go:19)   PCDATA  $2, $1
22    0x003b 00059 (once.go:19)   MOVQ    "".o+48(SP), AX
23    ……

方法二: go tool objdump
首先先编译程序: go tool compile -N -l once.go,

使用go tool objdump once.o反汇编出代码 (或者使用go tool objdump -s Do once.o反汇编特定的函数:):

 1TEXT %22%22.(*Once).Do(SB) gofile../Users/……/once.go
 2  once.go:13        0x7cd           65488b0c2500000000  MOVQ GS:0, CX           [5:9]R_TLS_LE
 3  once.go:13        0x7d6           483b6110        CMPQ 0x10(CX), SP
 4  once.go:13        0x7da           0f86d2000000        JBE 0x8b2
 5  once.go:13        0x7e0           4883ec28        SUBQ $0x28, SP
 6  once.go:13        0x7e4           48896c2420      MOVQ BP, 0x20(SP)
 7  once.go:13        0x7e9           488d6c2420      LEAQ 0x20(SP), BP
 8  once.go:14        0x7ee           488b442430      MOVQ 0x30(SP), AX
 9  once.go:14        0x7f3           8b4808          MOVL 0x8(AX), CX
10  once.go:14        0x7f6           83f901          CMPL $0x1, CX
11  once.go:14        0x7f9           0f84a3000000        JE 0x8a2
12  once.go:18        0x7ff           48890424        MOVQ AX, 0(SP)
13  once.go:18        0x803           e800000000      CALL 0x808          [1:5]R_CALL:sync.(*Mutex).Lock
14  once.go:19        0x808           488b442430      MOVQ 0x30(SP), AX
15  once.go:19        0x80d           4889442410      MOVQ AX, 0x10(SP)
16  once.go:19        0x812           c7042408000000      MOVL $0x8, 0(SP)
17  ……

方法三: go build -gcflags -S
使用go build -gcflags -S once.go也可以得到汇编代码:

 1"".(*Once).Do STEXT size=239 args=0x10 locals=0x28
 2    0x0000 00000 (/Users/……/once.go:13) TEXT    "".(*Once).Do(SB), $40-16
 3    0x0000 00000 (/Users/……/once.go:13) MOVQ    (TLS), CX
 4    0x0009 00009 (/Users/……/once.go:13) CMPQ    SP, 16(CX)
 5    0x000d 00013 (/Users/……/once.go:13) JLS 229
 6    0x0013 00019 (/Users/……/once.go:13) SUBQ    $40, SP
 7    0x0017 00023 (/Users/……/once.go:13) MOVQ    BP, 32(SP)
 8    0x001c 00028 (/Users/……/once.go:13) LEAQ    32(SP), BP
 9    0x0021 00033 (/Users/……/once.go:13) FUNCDATA    $0, gclocals·fdbf1f5761f6d17e8ae3f0aaecb6a3c5(SB)
10    0x0021 00033 (/Users/……/once.go:13) FUNCDATA    $1, gclocals·7d2d5fca80364273fb07d5820a76fef4(SB)
11    0x0021 00033 (/Users/……/once.go:13) FUNCDATA    $3, gclocals·96839595c383af6ae8227769d90a999e(SB)
12    0x0021 00033 (/Users/……/once.go:14) PCDATA  $2, $1
13    0x0021 00033 (/Users/……/once.go:14) PCDATA  $0, $0
14    0x0021 00033 (/Users/……/once.go:14) MOVQ    "".o+48(SP), AX
15    0x0026 00038 (/Users/……/once.go:14) MOVL    8(AX), CX
16    0x0029 00041 (/Users/……/once.go:14) CMPL    CX, $1
17    0x002c 00044 (/Users/……/once.go:14) JEQ 213

go tool compile 和 go build -gcflags -S 生成的是过程中的汇编,和最终的机器码的汇编可以通过go tool objdump生成。

原文发布时间为:2019-1-1
本文作者:Golang语言社区
本文来自云栖社区合作伙伴“ Golang语言社区”,了解相关信息可以关注“Golangweb”微信公众号

相关文章
|
1月前
|
Go 索引
掌握Go语言:Go语言范围,优雅遍历数据结构,简化代码操作实战解析(24)
掌握Go语言:Go语言范围,优雅遍历数据结构,简化代码操作实战解析(24)
|
3月前
|
存储 Go C语言
如何用Go开发eBPF程序
【2月更文挑战第7天】
|
1天前
|
存储 Java Linux
聊聊Go程序是如何运行的
本文作者 **sharkChili** 是一名 Java 和 Go 语言开发者,同时也是 CSDN 博客专家和 JavaGuide 维护者。文章探讨了 Go 语言的执行过程,从汇编角度出发,解释了如何从 `main.go` 文件开始,经过入口跳转、参数拷贝、启动协程、运行 `g0` 的 `main` 方法等步骤,最终执行到用户定义的 `main` 函数。文章还展示了相关汇编代码片段,并提供了运行时检查、系统初始化和调度器初始化的细节。结尾提到,有兴趣的读者可以加入作者创建的交流群进行深入讨论。
9 0
|
11天前
|
Go 微服务
4. 参考 go 代码——服务注册与发现
4. 参考 go 代码——服务注册与发现
|
11天前
|
存储 Go 开发者
【Go语言专栏】Go语言中的结构体与方法
【4月更文挑战第30天】Go语言中的结构体是聚合数据类型,用于自定义复杂类型。通过`type`和`struct`关键字定义结构体,包含多个不同类型的字段。结构体实例化后,使用点操作符访问字段。方法为结构体添加行为,定义时需指定接收者(值或指针)。方法调用同样使用点操作符。匿名结构体无需命名,嵌套结构体可构建复杂数据结构。选择值或指针接收者取决于是否需要修改结构体状态。理解并熟练运用结构体和方法是编写高效Go代码的关键。
|
13天前
|
运维 Serverless Go
Serverless 应用引擎产品使用之在阿里云函数计算中,Go语言的函数计算服务Go程序没有正确打包如何解决
阿里云Serverless 应用引擎(SAE)提供了完整的微服务应用生命周期管理能力,包括应用部署、服务治理、开发运维、资源管理等功能,并通过扩展功能支持多环境管理、API Gateway、事件驱动等高级应用场景,帮助企业快速构建、部署、运维和扩展微服务架构,实现Serverless化的应用部署与运维模式。以下是对SAE产品使用合集的概述,包括应用管理、服务治理、开发运维、资源管理等方面。
23 0
|
13天前
|
Unix Linux Go
Golang深入浅出之-信号(Signals)处理与优雅退出Go程序
【4月更文挑战第25天】Go语言中的信号处理关乎程序对外部事件的响应,尤其是优雅地终止进程。本文介绍了信号基础,如SIGINT、SIGTERM等常见信号,以及处理流程:注册处理器、等待信号、执行清理和优雅退出。强调了三个易错点及避免方法,并提供实战代码示例展示如何监听和响应信号。信号处理应简洁高效,确保程序健壮性和用户体验。
20 0
|
15天前
|
Go
Golang深入浅出之-信号(Signals)处理与优雅退出Go程序
【4月更文挑战第23天】在Go语言中,使用`os/signal`包处理信号对实现程序优雅退出和响应中断至关重要。本文介绍了如何注册信号处理器、处理常见问题和错误,以及提供代码示例。常见问题包括未捕获关键信号、信号处理不当导致程序崩溃和忽略清理逻辑。解决方案包括注册信号处理器(如`SIGINT`、`SIGTERM`)、保持信号处理器简洁和执行清理逻辑。理解并正确应用这些原则能增强Go程序的健壮性和可管理性。
22 1
|
16天前
|
Go 开发者
Golang深入浅出之-Go语言方法与接收者:面向对象编程初探
【4月更文挑战第22天】Go语言无类和继承,但通过方法与接收者实现OOP。方法是带有接收者的特殊函数,接收者决定方法可作用于哪些类型。值接收者不会改变原始值,指针接收者则会。每个类型有相关方法集,满足接口所有方法即实现该接口。理解并正确使用这些概念能避免常见问题,写出高效代码。Go的OOP机制虽不同于传统,但具有灵活性和实用性。
23 1
|
1月前
|
安全 编译器 Serverless
掌握Go语言:深入Go语言常量:代码稳定的关键(10)
掌握Go语言:深入Go语言常量:代码稳定的关键(10)