久久国产乱子伦精品免费M,亚洲一区二区三区91,欧美国产在线视频,国产精品视频久久

詳述 Golang 的符號表

???本文基于 Go 1.13。

符號表是由編譯器生成和維護的,保存了與程序相關的信息,如函數和全局變量。理解符號表能幫助我們更好地與之交互和利用它。

符號表

Go 編譯的所有二進制文件默認內嵌了符號表。我們來舉一個例子并研究它。下面是代碼:

var?AppVersion?string

func?main()?{
?fmt.Println(`Version:?`+AppVersion)
}

可以通過命令?nm?來展示符號表;下面是從?OSX?的結果中提取的部分信息:

0000000001177220?b?io.ErrUnexpectedEOF
[...]
0000000001177250?b?main.AppVersion
00000000010994c0?t?main.main
[...]
0000000001170b00?d?runtime.buildVersion

用?b(全稱為?bss)標記的符號是未初始化的數據。由于我們前面的變量?AppVersion?沒有初始化,因此它屬于?b。符號?d?表示已初始化的數據,t?表示文本符號, 函數屬于其中之一。

Go 也封裝了?nm?命令,可以用命令?go tool nm?來使用它,也能生成相同的結果:

1177220?B?io.ErrUnexpectedEOF
[...]
1177250?B?main.AppVersion
10994c0?T?main.main
[...]
1170b00?D?runtime.buildVersion

當我們知道了暴露的變量的名字后,我們就可以與之交互。

自定義變量

當執行命令?go build?時,經過了兩個階段:編譯和構建。構建階段通過編譯過程中生成的對象文件生成了一個可執行文件。為了實現這個階段,構建器把符號表中的符號重定向到最終的二進制文件。

在 Go 中我們可以用?-X?來重寫一個符號定義,-X?兩個入參:名稱和值。下面是承接前面的代碼的例子:

go?build?-o?ex?-ldflags="-X?main.AppVersion=v1.0.0"

構建并運行程序,現在會展示在命令行中定義的版本:

Version:?v1.0.0

運行?nm?命令會看到變量已被初始化:

1170a90?D?main.AppVersion

投建器賦予了我們重寫數據符號(類型?b?或?d)的能力,現在它們有了 Go 中的?string?類型。下面是那些符號列表:

D?runtime.badsystemstackMsg
D?runtime.badmorestackgsignalMsg
D?runtime.badmorestackg0Msg
B?os.executablePath
B?os.initCwd
B?syscall.freebsdConfArch
D?runtime/internal/sys.DefaultGoroot
B?runtime.modinfo
B?main.AppVersion
D?runtime.buildVersion

在列表中我們看到了之前的變量和?DefaultGoroot,它們都是被構建器自動設置的。我們來看一下運行時這些符號的意義。

調試

符號表的存在是為了確保標識符在使用之前已被聲明。這意味著當程序被構建后,它就不再需要這個表了。然而,默認情況下符號表是被嵌入到了 Go 的二進制文件以便調試。我們先來理解如何利用它,之后再來看怎么把它從二進制文件中刪除。

我會用?gdb?來調試。只需要執行?gdb ex?就可以加載二進制文件。現在程序已被加載,我們用?list?命令來展示源碼。下面是輸出:

GNU?gdb?(GDB)?8.3.1
[...]
Reading?symbols?from?ex...
Loading?Go?Runtime?support.
(gdb)?list?10
6
7??var?AppVersion?string
8
9??func?main()?{
10????fmt.Println(`Version:?`+AppVersion)
11?}
12
(gdb)

gdb?初始化的第一步是讀取符號表,為了提取程序中函數和符號的信息。我們現在可以用?-ldflags=-s?參數不把符號表編譯進程序。下面是新的輸出:

GNU?gdb?(GDB)?8.3.1
[...]
Reading?symbols?from?ex...
(No?debugging?symbols?found?in?ex)
(gdb)?list
No?symbol?table?is?loaded.??Use?the?"file"?command.

現在調試器由于找不到符號表不能展示源碼。我們應該留意到使用?-s?參數去掉了符號表的同時,也去掉了對調試器很有用的?[DWARF](https://golang.org/pkg/debug/dwarf/ "DWARF")?調試信息。

二進制文件的大小

去掉符號表后會讓調試器用起來很困難,但是會減少二進制文件的大小。下面是有無符號表的二進制文件的區別:

2,0M??7?f?é?v?15:59?ex
1,5M??7?f?é?v?15:22?ex-s

沒有符號表比有符號表會小 25%。下面是編譯?cmd/go?源碼的另一個例子:

14M??7?f?é?v?16:58?go
11M??7?f?é?v?16:58?go-s

這里沒有符號表和 DWARF 信息,也小了 25%。

如果你想了解為什么二進制文件會變小,我推薦你閱讀 WebKit 團隊的?Benjamin Poulain的文章“不尋常的加速:二進制文件大小”。

鏈接:https://medium.com/a-journey-with-go/go-how-to-take-advantage-of-the-symbols-table-360dd52269e5

(版權歸原作者所有,侵刪)

相關新聞

歷經多年發展,已成為國內好評如潮的Linux云計算運維、SRE、Devops、網絡安全、云原生、Go、Python開發專業人才培訓機構!

    1. 主站蜘蛛池模板: 克东县| 织金县| 道孚县| 黔西县| 松潘县| 南雄市| 垦利县| 武平县| 盐亭县| 怀化市| 宜昌市| 阳城县| 百色市| 临西县| 股票| 白水县| 策勒县| 夏津县| 沙坪坝区| 来宾市| 娱乐| 霍山县| 大方县| 卓尼县| 河西区| 高碑店市| 苍山县| 常山县| 宝应县| 翼城县| 九台市| 吉木乃县| 措美县| 秦安县| 名山县| 柳江县| 介休市| 南乐县| 张家界市| 英吉沙县| 广河县|