亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

在 Go 的上下文中,靜態和動態鏈接 wrt 可移植性

在 Go 的上下文中,靜態和動態鏈接 wrt 可移植性

Go
慕虎7371278 2023-06-01 17:08:38
讓我先把一些事實擺在桌面上進行事實核查,以免造成混淆:帶有動態部分的 ELF 二進制文件在編譯時會帶有一些未解析的符號。解析將在二進制文件執行期間的某個時間由鏈接器執行。動態鏈接有利也有弊。但是,如果您的二進制文件所需的目標庫不存在于系統中(在所需版本中),則二進制文件將不會運行。靜態鏈接緩解了這個問題,但在下層引入了一個新問題。通過靜態鏈接二進制文件,庫的可執行代碼嵌入到您的二進制文件中,因此二進制庫接口不再有問題。但是,現在庫-OS 界面可能會出現問題。那是對的嗎?這里可能會出現什么問題?現在讓我們在 Go 的上下文中討論這個問題。我注意到,如果我使用 構建一個二進制文件CGO_ENABLED=1 go build ...,我會得到一個帶有動態部分的二進制文件:david@x1 /tmp (git)-[master] % readelf -d rtloggerd.cgo1Dynamic section at offset 0x7a6140 contains 19 entries:  Tag        Type                         Name/Value 0x0000000000000004 (HASH)               0x914e40 0x0000000000000006 (SYMTAB)             0x915340 0x000000000000000b (SYMENT)             24 (bytes) 0x0000000000000005 (STRTAB)             0x915100 0x000000000000000a (STRSZ)              570 (bytes) 0x0000000000000007 (RELA)               0x914a38 0x0000000000000008 (RELASZ)             24 (bytes) 0x0000000000000009 (RELAENT)            24 (bytes) 0x0000000000000003 (PLTGOT)             0xba6000 0x0000000000000015 (DEBUG)              0x0 0x0000000000000001 (NEEDED)             Shared library: [libpthread.so.0] 0x0000000000000001 (NEEDED)             Shared library: [libc.so.6] 0x000000006ffffffe (VERNEED)            0x914de0 0x000000006fffffff (VERNEEDNUM)         2 0x000000006ffffff0 (VERSYM)             0x914d80 0x0000000000000014 (PLTREL)             RELA 0x0000000000000002 (PLTRELSZ)           816 (bytes) 0x0000000000000017 (JMPREL)             0x914a50 0x0000000000000000 (NULL)               0x0另一方面,如果 I 時CGO_ENABLED=0 go build ...沒有動態部分:130 david@x1 /tmp (git)-[master] % readelf -d rtloggerd.cgo0There is no dynamic section in this file.這是否意味著庫是靜態鏈接的?我想是的,但大小差異在我的機器上可以忽略不計(大約 72 kB),這讓我感到驚訝。關于跨 Linux 系統的可移植性,哪個更好,為什么?Go的標準庫是如何開展業務的呢?它實際上是在調用libc(在我的例子中)提供的 C 函數嗎?glibc我假設有一個本地系統調用接口。另一方面,我想在原生 Go 中重新實現整個 stdlib 會很困難。最后,我聽說“不能保證不同的發行版,甚至同一發行版的不同版本都兼容 ABI”。這是真的?我假設 ABI 主要是二進制可執行格式(Linux 上的 ELF 有一段時間),所以我假設這里沒有問題。這意味著什么?謝謝!
查看完整描述

1 回答

?
楊__羊羊

TA貢獻1943條經驗 獲得超7個贊

在 GNU/Linux 上,幾乎所有的 Go 可執行文件都屬于這些類別:

  1. 那些包括應用程序、Go 運行時和 glibc(的一部分)的靜態鏈接副本。

  2. 那些只包含應用程序和 Go 運行時的靜態鏈接,沒有 glibc。

  3. 那些只包括應用程序和 Go 運行時、靜態鏈接和動態鏈接到 glibc 的。

不幸的是,與 Go 相關的工具通常會混淆這些鏈接模式。依賴 glibc 的主要原因是應用程序使用主機名和用戶查找(功能如getaddrinfogetpwuid_r)。?CGO_ENABLED=0src/os/user/cgo_lookup_unix.go(使用 glibc)等實現切換到src/os/user/lookup_unix.go(不使用 glibc)。非 glibc 實現不使用 NSS,因此提供的功能有些有限(通常不會影響不在 LDAP/Active Directory 中存儲用戶信息的用戶)。

在您的情況下,設置CGO_ENABLED=0將您的應用程序從第三類移至第二類。(還有其他與 Go 相關的工具可以構建第一種應用程序。)非 NSS 查找代碼不是很大,因此二進制大小的增加并不顯著。由于 Go 運行時已經靜態鏈接,靜態鏈接減少的開銷甚至可能導致可執行文件大小的凈減少。

這里要考慮的最重要的問題是 NSS、線程和靜態鏈接在 glibc 中并不是那么好。所有的 Go 程序都是多線程的,(靜態)將 glibc 鏈接到 Go 程序中的原因正是訪問 NSS 函數。因此,將 Go 程序靜態鏈接到 glibc 始終是錯誤的做法。它基本上總是?有問題。即使 Go 程序不是多線程的,使用 NSS 函數的靜態鏈接程序在運行時也需要與構建時使用的 glibc版本完全相同,因此此類應用程序的靜態鏈接會降低可移植性。

所有這些都是第一類 Go 應用程序如此糟糕的原因。使用 生成靜態鏈接的應用程序CGO_ENABLED=0沒有這些問題,因為這些應用程序(第二類)不包含任何 glibc 代碼(以用戶/主機查找功能的功能減少為代價)。

如果你想創建一個需要 glibc 的可移植二進制文件,你需要動態鏈接你的應用程序(第三種),在你想要支持的最舊的 glibc 系統上。然后應用程序將在該 glibc 版本和所有更高版本上運行(目前,Go 沒有正確鏈接 libc,所以即使是 glibc 也沒有很強的兼容性保證)。發行版通常與 ABI 兼容,但它們具有不同版本的 glibc。glibc 竭盡全力確保動態鏈接到舊版本 glibc 的應用程序將繼續在新版本的 glibc 上運行,但反之則不然:一旦您將應用程序鏈接到特定版本的 glibc,它可能會獲得功能(符號)在舊版本上不可用,因此該應用程序將無法與那些舊版本一起使用。


查看完整回答
反對 回復 2023-06-01
  • 1 回答
  • 0 關注
  • 153 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號