Go语言汇编快速指南

如果想要深入了解Go语言,Go汇编是一个绕不过的环节。

神池网站建设公司成都创新互联公司,神池网站设计制作,有大型网站制作公司丰富经验。已为神池近1000家提供企业网站建设服务。企业网站搭建\外贸网站制作要多少钱,请找那个售后服务好的神池做网站的公司定做!

本文以Go官方文档 A Quick Guide to Go's Assembler 为基础对Go汇编进行介绍。

Go汇编是在 Plan 9 汇编的基础上进化出的新版本。如果需要进一步深入学习,还是建议阅读A Manual for the Plan 9 assembler 。

关于 Go 的汇编,最重要的一点是它不是底层机器码的直接表示。而是进行了一层抽象,但是抽象的也不是很理想,所以称为semi-abstract instruction set(半抽象)。所以一些细节指令精确地映射到机器码,但有些没有,这可以在本文的示例代码中看到。

因为每种处理器架构的指令集、寄存器各不相同,所以汇编代码实现功能需要适配各种处理器架构;当然,也要适配各种操作系统。

环境

OS : Ubuntu 20.04.2 LTS; x86_64
Go : go version go1.16.2 linux/amd64

声明

操作系统、处理器架构、Go版本不同,均有可能造成相同的源码编译后运行时的寄存器值、内存地址、数据结构等存在差异。

本文仅包含 linux/amd64 系统架构下的 64 位可执行程序的示例。

本文仅保证学习过程中的分析数据在当前环境下的准确有效性。

代码清单

go.mod

module go-asm-guide
go 1.16

main.go

package main
import (
"fmt"
"unsafe"
)
type Text struct {
Language string
_ uint8
Length int
}
func add(a, b int) int
func addX(a, b int) int
// 获取 Text 的 Length 字段的值
func length(text *Text) int
// 获取 Text 结构体的大小
func sizeOfTextStruct() int
func main() {
println(add(1, 2))
println(addX(1, 2))
text := &Text{
Language: "chinese",
Length: 1024,
}
fmt.Println(text)
println(length(text))
println(sizeOfTextStruct())
println(unsafe.Sizeof(*text))
}

main.s

#include "textflag.h"
#include "go_asm.h" // 该文件自动生成
TEXT ·add(SB),NOSPLIT,$0-24
MOVQ a+0(FP), AX // 读取第一个参数
MOVQ b+8(FP), BX // 读取第二个参数
ADDQ BX, AX
MOVQ AX, ret+16(FP) // 保存结果
RET
TEXT ·addX(SB),NOSPLIT,$0-24
MOVQ a+0(FP), AX
MOVQ b+8(FP), BX
ADDQ BX, AX
MOVQ $x(SB), BX // 读取全局变量 x 的地址
MOVQ 0(BX), BX // 读取全局变量 x 的值
ADDQ BX, AX
MOVQ AX, ret+16(FP)
RET
TEXT ·length(SB),NOSPLIT,$0-16
MOVQ text+0(FP), AX
MOVQ Text_Length(AX), AX // 通过字段在结构体中的偏移量读取字段值
MOVQ AX, ret+8(FP)
RET
TEXT ·sizeOfTextStruct(SB),NOSPLIT,$0-8
MOVQ $Text__size, AX // 保存结构体的大小到 AX 寄存器
MOVQ AX, ret+0(FP)
RET
DATA x+0(SB)/8, $10 // 初始化全局变量 x, 赋值为 10
GLOBL x(SB), RODATA, $8 // 声明全局变量 x

常用命令

Go汇编的学习需要时间,不是天才、没有牢固的汇编基础的话,看一篇教程,花一天时间是不能立即熟练掌握的。

但是熟练使用工具能够使我们有效地学习Go汇编。

编译生成汇编

这是Go语言自带的功能,通过以下命令即可查看。当然还可以指定各种参数进行详细的研究,此处不再赘述。

  • go tool compile -S x.go
  • go build -gcflags -S x.go

$ cat x.go
package main

func main() {
println(3)
}
$ go tool compile -S x.go
"".main STEXT size=77 args=0x0 locals=0x10 funcid=0x0
0x0000 00000 (x.go:3) TEXT "".main(SB), ABIInternal, $16-0
0x0000 00000 (x.go:3) MOVQ (TLS), CX
0x0009 00009 (x.go:3) CMPQ SP, 16(CX)
0x000d 00013 (x.go:3) PCDATA $0, $-2
0x000d 00013 (x.go:3) JLS 70
0x000f 00015 (x.go:3) PCDATA $0, $-1
0x000f 00015 (x.go:3) SUBQ $16, SP
0x0013 00019 (x.go:3) MOVQ BP, 8(SP)
0x0018 00024 (x.go:3) LEAQ 8(SP), BP
0x001d 00029 (x.go:3) FUNCDATA $0, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB)
0x001d 00029 (x.go:3) FUNCDATA $1, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB)
0x001d 00029 (x.go:4) PCDATA $1, $0
0x001d 00029 (x.go:4) NOP
0x0020 00032 (x.go:4) CALL runtime.printlock(SB)
0x0025 00037 (x.go:4) MOVQ $3, (SP)
0x002d 00045 (x.go:4) CALL runtime.printint(SB)
0x0032 00050 (x.go:4) CALL runtime.printnl(SB)
0x0037 00055 (x.go:4) CALL runtime.printunlock(SB)
0x003c 00060 (x.go:5) MOVQ 8(SP), BP
0x0041 00065 (x.go:5) ADDQ $16, SP
0x0045 00069 (x.go:5) RET
0x0046 00070 (x.go:5) NOP
0x0046 00070 (x.go:3) PCDATA $1, $-1
0x0046 00070 (x.go:3) PCDATA $0, $-2
0x0046 00070 (x.go:3) CALL runtime.morestack_noctxt(SB)
0x004b 00075 (x.go:3) PCDATA $0, $-1
0x004b 00075 (x.go:3) JMP 0
0x0000 64 48 8b 0c 25 00 00 00 00 48 3b 61 10 76 37 48 dH..%....H;a.v7H
0x0010 83 ec 10 48 89 6c 24 08 48 8d 6c 24 08 0f 1f 00 ...H.l$.H.l$....
0x0020 e8 00 00 00 00 48 c7 04 24 03 00 00 00 e8 00 00 .....H..$.......
0x0030 00 00 e8 00 00 00 00 e8 00 00 00 00 48 8b 6c 24 ............H.l$
0x0040 08 48 83 c4 10 c3 e8 00 00 00 00 eb b3 .H...........
rel 5+4 t=17 TLS+0
rel 33+4 t=8 runtime.printlock+0
rel 46+4 t=8 runtime.printint+0
rel 51+4 t=8 runtime.printnl+0
rel 56+4 t=8 runtime.printunlock+0
rel 71+4 t=8 runtime.morestack_noctxt+0
go.cuinfo.packagename. SDWARFCUINFO dupok size=0
0x0000 6d 61 69 6e main
""..inittask SNOPTRDATA size=24
0x0000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x0010 00 00 00 00 00 00 00 00 ........
gclocals·33cdeccccebe80329f1fdbee7f5874cb SRODATA dupok size=8
0x0000 01 00 00 00 00 00 00 00

反编译程序

go tool objdump

这是Go语言自带的反编译命令。

$ cat x.go
package main
func main() {
println(3)
}
$ go build x.go
$ go tool objdump -s main.main x
TEXT main.main(SB) /home/foo/codes/goinmemory/go_asm/x.go
x.go:3 0x45ec60 64488b0c25f8ffffff MOVQ FS:0xfffffff8, CX
x.go:3 0x45ec69 483b6110 CMPQ 0x10(CX), SP
x.go:3 0x45ec6d 7637 JBE 0x45eca6
x.go:3 0x45ec6f 4883ec10 SUBQ $0x10, SP
x.go:3 0x45ec73 48896c2408 MOVQ BP, 0x8(SP)
x.go:3 0x45ec78 488d6c2408 LEAQ 0x8(SP), BP
x.go:4 0x45ec7d 0f1f00 NOPL 0(AX)
x.go:4 0x45ec80 e8fb05fdff CALL runtime.printlock(SB)
x.go:4 0x45ec85 48c7042403000000 MOVQ $0x3, 0(SP)
x.go:4 0x45ec8d e8ee0dfdff CALL runtime.printint(SB)
x.go:4 0x45ec92 e8a908fdff CALL runtime.printnl(SB)
x.go:4 0x45ec97 e86406fdff CALL runtime.printunlock(SB)
x.go:5 0x45ec9c 488b6c2408 MOVQ 0x8(SP), BP
x.go:5 0x45eca1 4883c410 ADDQ $0x10, SP
x.go:5 0x45eca5 c3 RET
x.go:3 0x45eca6 e8b5afffff CALL runtime.morestack_noctxt(SB)
x.go:3 0x45ecab ebb3 JMP main.main(SB)

objdump

这是Linux环境中一个通用的反编译工具,不仅仅适用于Go程序。

$ objdump --disassemble=main.main x
x: file format elf64-x86-64
Disassembly of section .text:
000000000045ec60 :
45ec60: 64 48 8b 0c 25 f8 ff mov %fs:0xfffffffffffffff8,%rcx
45ec67: ff ff
45ec69: 48 3b 61 10 cmp 0x10(%rcx),%rsp
45ec6d: 76 37 jbe 45eca6
45ec6f: 48 83 ec 10 sub $0x10,%rsp
45ec73: 48 89 6c 24 08 mov<

分享题目:Go语言汇编快速指南
分享链接:http://www.zyruijie.cn/qtweb/news45/495.html

网站建设、网络推广公司-创新互联,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等

广告

声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 创新互联