Go1.18 新特性:編譯後的二進位制檔案,將包含更多資訊

煎魚發表於2022-01-24

大家好,我是煎魚。

我有一個朋友,,開開心心入職,想著施展拳腳,第一個任務就是對老舊的二進位制檔案進行研究。

他一看,這檔案,不知道是編譯器用什麼引數怎麼打出來的,環境不知道是什麼,更不知道來自什麼程式碼分支?

這除了是專案流程上的問題外,Go 在這塊也有類似的小問題,處理起來比較麻煩。

背景

日常中很難從 Go 二進位制檔案中檢索元資訊,要麼是資訊完全缺失,要麼提取需要對二進位制檔案進行大量解析。

包含的元資訊如下:

元資訊提取處
Go 構建版本符號表,通過全域性變數 runtime.buildVersion 來獲取
構建資訊,例如:模組和版本符號表,通過全域性變數 runtime/debug.modinfo 來獲取
編譯器選項,例如:構建模式、編譯器、gcflags、ldflags 等無法獲取
使用者定義的自定義資料,例如:應用程式版本等需在編譯時設定全域性字串變數,才可以獲取

關注到編譯器選項,也就是引數等都是無法得知的,也就是會提高獲取如何編譯出來的難度。

新提案

Michael Obermüller 提出了一個新的提案《cmd/go: add compiler flags, relevant env vars to 'go version -m' output》用於解決上述問題。

在提案中想要的是 JSON 格式的結構輸出:

{
    "version": "go1.13.4",
    "compileropts": {
        "compiler": "gc",
        "mode": "pie",
        "os": "linux",
        ...
    },
    "buildinfo": {
        "path": "腦子進煎魚了",
        "main": {
            "path": "HelloWorld",
            "version": "(devel)",
        },
        "deps": []
    },
    "user": {
        "customkey": "customval",
        ...
    }
}

Russ Cox 表示由於編譯資訊已有既有格式,並且預設使用 JSON 只會讓二進位制檔案變得更大。好處少,沒必要,改為了選項化的支援。

新的 Go1.18 版本中,可以通過既有的:

go version -m

檢視到提案所提到的資訊。

例如:

$ gotip version
go version devel go1.18-eba0e866fa Mon Oct 18 22:56:07 2021 +0000 darwin/amd64
$ gotip build ./
$ gotip version -m ko
...
    build    compiler    gc
    build    tags    goexperiment.regabiwrappers,goexperiment.regabireflect,goexperiment.regabiargs
    build    CGO_ENABLED    true
    build    CGO_CPPFLAGS    
    build    CGO_CFLAGS    
    build    CGO_CXXFLAGS    
    build    CGO_LDFLAGS    
    build    gitrevision    6447264ff8b5d48aff64000f81bb0847aefc7bac
    build    gituncommitted    true

若需要輸出 JSON 格式,也可以通過指定 go version -json 達到一樣的效果。

在上面的輸出中,現有的編譯器選項等都會包含在內,能夠讓大家對整體編譯後的二進位制檔案溯源有一個更好的認知。

總結

在今天這篇文章中,給大家介紹了 Go1.18 的一個新的變化。

新版本中,編譯器選項/引數、相關環境變數等,將會包含在編譯後的二進位制檔案中,能夠更便於後人排查和檢視資訊。

若有任何疑問歡迎評論區反饋和交流,最好的關係是互相成就,各位的點贊就是煎魚創作的最大動力,感謝支援。

文章持續更新,可以微信搜【腦子進煎魚了】閱讀,本文 GitHub github.com/eddycjy/blog 已收錄,學習 Go 語言可以看 Go 學習地圖和路線,歡迎 Star 催更。

相關文章