我知道
--ldflags="-s -w"
会让 Go 二进制文件的大小更小,但是如果不与没有 ldflags 的二进制文件进行比较,我们如何知道 Go 二进制文件是否使用 ldflags="-s -w"
进行编译?
首先声明:我不是编译工具链和可执行文件格式的专家。我会尽量不说蠢话,但如果您发现任何错误,请纠正我!
我在具有 x86_64 架构的 ArchLinux 笔记本电脑上运行了这些测试。 Go版本是1.8.1.
首先,我们需要知道这些标志实际使用在哪里:
$ go help build
...
-ldflags 'flag list'
arguments to pass on each go tool link invocation
...
显然,标志仅传递给
go tool link
调用。查看帮助,我们有更多信息:
$ go tool link
...
-s disable symbol table
...
-w disable DWARF generation
...
取自我在here找到的 ELF 简短介绍,这里是有关符号表的标题文本:
目标文件的符号表包含定位和查找所需的信息 重新定位程序的符号定义和引用。
对于DWARF,这是一种用于调试数据的格式。
从那里,我们如何知道二进制文件是否具有符号表或启用了 DWARF?答案就在 ELF 部分。可能还有其他方法,但这是我找到的并且很容易检查的方法。以下是我用来确定 Golang 二进制文件是否已使用
-ldflags='-s'
或 -ldflags='-w'
进行编译的规则:
.symtab
部分.debug_info
部分。此部分不是唯一存在的部分,而是作为一个指标。在 Linux 上,有一些工具可以读取节名称来提取这些信息。
readelf
和 nm
是示例,但可能还存在更多。
事实证明,Go 提供了一个
debug/elf
包,可用于获取这些信息。这是完成这项工作的示例程序:
package main
import "fmt"
import "os"
import "debug/elf"
func main() {
fileName := "path/to/main"
fp, err := elf.Open(fileName)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
symtab := fp.Section(".symtab")
if symtab == nil {
fmt.Println("No Symbol Table : compiled with -ldflags='-s'")
}
debugInfo := fp.Section(".debug_info")
if debugInfo == nil {
fmt.Println("No DWARF data : compiled with -ldflags='-w'")
}
}
我针对基本的 Golang Hello World 测试了这个程序,没有使用任何标志,仅使用
-s
标志,仅使用 -w
标志以及两个 -s -w
标志。我注意到,在仅使用 -s
进行编译时,它还删除了 DWARF 数据,但我没有搜索原因。除此之外,结果正如预期的那样。
虽然 ELF 是焦点格式,但同样的方法也适用于 Windows 可执行文件(Golang 中有一个
debug/pe
包)。
选项之一 -
readelf -p .go.buildinfo app | grep ldflags
你会得到类似
build^I-ldflags="-s -w"\n
的东西,或者什么也没有。