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

Go:符號(hào)表是什么?如何使用?

???本文基于 Go 1.13 ,原文及譯者信息在文末。

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

符號(hào)表

Go 編譯的所有二進(jìn)制文件默認(rèn)內(nèi)嵌了符號(hào)表。我們來舉一個(gè)例子并研究它。下面是代碼:

var?AppVersion?string

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

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

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

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

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

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

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

自定義變量

當(dāng)執(zhí)行命令?go build?時(shí),經(jīng)過了兩個(gè)階段:編譯和構(gòu)建。構(gòu)建階段通過編譯過程中生成的對象文件生成了一個(gè)可執(zhí)行文件。為了實(shí)現(xiàn)這個(gè)階段,構(gòu)建器把符號(hào)表中的符號(hào)重定向到最終的二進(jìn)制文件。

在 Go 中我們可以用?-X?來重寫一個(gè)符號(hào)定義,-X?兩個(gè)入?yún)ⅲ好Q和值。下面是承接前面的代碼的例子:

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

構(gòu)建并運(yùn)行程序,現(xiàn)在會(huì)展示在命令行中定義的版本:

Version:?v1.0.0

運(yùn)行?nm?命令會(huì)看到變量已被初始化:

1170a90?D?main.AppVersion

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

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,它們都是被構(gòu)建器自動(dòng)設(shè)置的。我們來看一下運(yùn)行時(shí)這些符號(hào)的意義。

調(diào)試

符號(hào)表的存在是為了確保標(biāo)識(shí)符在使用之前已被聲明。這意味著當(dāng)程序被構(gòu)建后,它就不再需要這個(gè)表了。然而,默認(rèn)情況下符號(hào)表是被嵌入到了 Go 的二進(jìn)制文件以便調(diào)試。我們先來理解如何利用它,之后再來看怎么把它從二進(jìn)制文件中刪除。

我會(huì)用?gdb?來調(diào)試。只需要執(zhí)行?gdb ex?就可以加載二進(jìn)制文件。現(xiàn)在程序已被加載,我們用?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?初始化的第一步是讀取符號(hào)表,為了提取程序中函數(shù)和符號(hào)的信息。我們現(xiàn)在可以用?-ldflags=-s?參數(shù)不把符號(hào)表編譯進(jìn)程序。下面是新的輸出:

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.

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

二進(jìn)制文件的大小

去掉符號(hào)表后會(huì)讓調(diào)試器用起來很困難,但是會(huì)減少二進(jìn)制文件的大小。下面是有無符號(hào)表的二進(jìn)制文件的區(qū)別:

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

沒有符號(hào)表比有符號(hào)表會(huì)小 25%。下面是編譯?cmd/go?源碼的另一個(gè)例子:

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

這里沒有符號(hào)表和 DWARF 信息,也小了 25%。

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

作者:Vincent Blanchon?譯者:lxbwolf??校對:polaris1119

本文由?GCTT??原創(chuàng)編譯,Go 中文網(wǎng)?榮譽(yù)推出

相關(guān)新聞

歷經(jīng)多年發(fā)展,已成為國內(nèi)好評如潮的Linux云計(jì)算運(yùn)維、SRE、Devops、網(wǎng)絡(luò)安全、云原生、Go、Python開發(fā)專業(yè)人才培訓(xùn)機(jī)構(gòu)!

    1. 主站蜘蛛池模板: 龙海市| 洮南市| 大兴区| 内乡县| 清苑县| 永修县| 凤台县| 寿阳县| 深水埗区| 报价| 会泽县| 武宁县| 洪雅县| 白沙| 盱眙县| 仁寿县| 景洪市| 历史| 图们市| 昭苏县| 平湖市| 焦作市| 施秉县| 勐海县| 玛纳斯县| 怀柔区| 左贡县| 辉县市| 合肥市| 渭南市| 昌图县| 布拖县| 杭州市| 仁化县| 延长县| 从江县| 绵阳市| 合川市| 工布江达县| 闵行区| 门源|