新聞中心
如果想要深入了解Go語言,Go匯編是一個繞不過的環(huán)節(jié)。

神池網(wǎng)站建設(shè)公司成都創(chuàng)新互聯(lián)公司,神池網(wǎng)站設(shè)計制作,有大型網(wǎng)站制作公司豐富經(jīng)驗。已為神池近1000家提供企業(yè)網(wǎng)站建設(shè)服務(wù)。企業(yè)網(wǎng)站搭建\外貿(mào)網(wǎng)站制作要多少錢,請找那個售后服務(wù)好的神池做網(wǎng)站的公司定做!
本文以Go官方文檔 A Quick Guide to Go's Assembler 為基礎(chǔ)對Go匯編進(jìn)行介紹。
Go匯編是在 Plan 9 匯編的基礎(chǔ)上進(jìn)化出的新版本。如果需要進(jìn)一步深入學(xué)習(xí),還是建議閱讀A Manual for the Plan 9 assembler 。
關(guān)于 Go 的匯編,最重要的一點是它不是底層機(jī)器碼的直接表示。而是進(jìn)行了一層抽象,但是抽象的也不是很理想,所以稱為semi-abstract instruction set(半抽象)。所以一些細(xì)節(jié)指令精確地映射到機(jī)器碼,但有些沒有,這可以在本文的示例代碼中看到。
因為每種處理器架構(gòu)的指令集、寄存器各不相同,所以匯編代碼實現(xiàn)功能需要適配各種處理器架構(gòu);當(dāng)然,也要適配各種操作系統(tǒng)。
環(huán)境
OS : Ubuntu 20.04.2 LTS; x86_64
Go : go version go1.16.2 linux/amd64
聲明
操作系統(tǒng)、處理器架構(gòu)、Go版本不同,均有可能造成相同的源碼編譯后運(yùn)行時的寄存器值、內(nèi)存地址、數(shù)據(jù)結(jié)構(gòu)等存在差異。
本文僅包含 linux/amd64 系統(tǒng)架構(gòu)下的 64 位可執(zhí)行程序的示例。
本文僅保證學(xué)習(xí)過程中的分析數(shù)據(jù)在當(dāng)前環(huán)境下的準(zhǔn)確有效性。
代碼清單
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 結(jié)構(gòu)體的大小
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 // 讀取第一個參數(shù)
MOVQ b+8(FP), BX // 讀取第二個參數(shù)
ADDQ BX, AX
MOVQ AX, ret+16(FP) // 保存結(jié)果
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 // 通過字段在結(jié)構(gòu)體中的偏移量讀取字段值
MOVQ AX, ret+8(FP)
RET
TEXT ·sizeOfTextStruct(SB),NOSPLIT,$0-8
MOVQ $Text__size, AX // 保存結(jié)構(gòu)體的大小到 AX 寄存器
MOVQ AX, ret+0(FP)
RET
DATA x+0(SB)/8, $10 // 初始化全局變量 x, 賦值為 10
GLOBL x(SB), RODATA, $8 // 聲明全局變量 x
常用命令
Go匯編的學(xué)習(xí)需要時間,不是天才、沒有牢固的匯編基礎(chǔ)的話,看一篇教程,花一天時間是不能立即熟練掌握的。
但是熟練使用工具能夠使我們有效地學(xué)習(xí)Go匯編。
編譯生成匯編
這是Go語言自帶的功能,通過以下命令即可查看。當(dāng)然還可以指定各種參數(shù)進(jìn)行詳細(xì)的研究,此處不再贅述。
- 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環(huán)境中一個通用的反編譯工具,不僅僅適用于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<
網(wǎng)站題目:Go語言匯編快速指南
文章出自:http://www.dlmjj.cn/article/cdsphoc.html


咨詢
建站咨詢
