如何检查 Golang 二进制文件是否使用 “–ldflags=”-s -w”” 进行编译?

huangapple go评论92阅读模式
英文:

how to check whether golang binary is compiled with --ldflags="-s -w"

问题

我知道--ldflags="-s -w"可以使Go二进制文件的大小变小,但是如果没有与没有使用ldflags="-s -w"编译的二进制文件进行比较,我们怎么知道Go二进制文件是使用还是没有使用ldflags="-s -w"编译的呢?

英文:

i know --ldflags="-s -w" will make Go binary size smaller, but without comparing to the one without ldflags, how do we know whether Go binary compiled with or without ldflags="-s -w" ?

答案1

得分: 12

免责声明:我不是编译工具链和可执行文件格式的专家。我会尽量避免说愚蠢的话,但如果你发现任何错误,请纠正我!

我在一台安装了x86_64架构的ArchLinux笔记本上运行了这些测试。Go版本是1.8.1。

首先,我们需要知道这些标志实际上在哪里使用:

$ go help build
...
-ldflags 'flag list'
    传递给每个go工具链接调用的参数
...

显然,这些标志只是传递给go tool link调用。查看帮助信息,我们可以得到更多信息:

$ go tool link
...
-s	禁用符号表
...
-w	禁用DWARF生成
...

从我在这里找到的ELF简介中摘录的内容,这是关于符号表的头部文本:

对象文件的符号表保存了定位和重定位程序符号定义和引用所需的信息。

至于DWARF,这是一种用于调试数据的格式。

从这里开始,我们如何知道一个二进制文件是否具有符号表或启用了DWARF?答案在ELF节中。可能还有其他方法,但这是我找到的一种简单易行的检查方法。以下是我用来确定Golang二进制文件是否使用了-ldflags='-s'-ldflags='-w'的规则:

  • 如果一个Go二进制文件具有符号表,则存在.symtab节。
  • 如果一个Go二进制文件具有DWARF调试信息,则存在.debug_info节。该节不是唯一存在的节,但它作为一个指示器。

在Linux上,有一些工具可以读取节名称以提取这些信息。readelfnm就是其中的例子,但可能还有其他工具。

事实上,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("没有符号表:使用了-ldflags='-s'")
    }

    debugInfo := fp.Section(".debug_info")
    if debugInfo == nil {
        fmt.Println("没有DWARF数据:使用了-ldflags='-w'")
    }
}

我使用这个程序对基本的Golang Hello World进行了测试,分别使用了无标志、仅使用-s标志、仅使用-w标志以及同时使用-s -w标志。我注意到,仅使用-s进行编译时,它也会删除DWARF数据,但我没有深究原因。除此之外,结果如预期。

尽管ELF是重点格式,但同样的方法也适用于Windows可执行文件(Golang中有一个debug/pe包)。

英文:

Disclaimer first: I'm no expert of compilation toolchains and executable file formats. I'll try not to say stupid things, but correct me if you see any mistake !

I ran those tests on an ArchLinux laptop, with x86_64 architecture. Go version is 1.8.1.

First, we need to know where those flags are actually used:

$ go help build
...
-ldflags 'flag list'
	arguments to pass on each go tool link invocation
...

Apparently, flags are merely passed to the go tool link invocation. Looking at the help, we have a bit more information:

$ go tool link
...
-s	disable symbol table
...
-w	disable DWARF generation
...

Taken from the short introduction to ELF that I found here, here is the header text concerning the Symbol Table:

> An object file’s symbol table holds information needed to locate and
> relocate a program’s symbolic definitions and references.

As for DWARF, this is a format for debugging data.

From there, how do we know if a binary has a symbol table, or DWARF enabled ? The answer lies in ELF sections. There are probably other ways, but it is the one I found and is easy to check for. Here are the rules that I've used to determine if a Golang binary has been compiled with -ldflags='-s' or -ldflags='-w':

  • If a Go binary has a symbol table, the section .symtab is present
  • If a Go binary has DWARF debug, the section .debug_info is present. This section is not the only one to be present, but serves as an indicator.

On Linux, there are some tools which can read section names to extract those informations. readelf and nm are examples, yet probably more exist.

It also turns out that Go provide a debug/elf package which can be used to get those informations. Here is a sample program that does this job:

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'")
	}
}

I tested this program against the basic Golang Hello World, using no flags, only the -s flag, only the -w flag and both -s -w flags. I noted that while compiling with -s only, it also removed DWARF data, but I did not search why. Aside from that, the results were as expected.

Though ELF was the focus format, the same method can be applied for Windows executables (there is a debug/pe package in Golang).

huangapple
  • 本文由 发表于 2017年5月24日 11:28:16
  • 转载请务必保留本文链接:https://go.coder-hub.com/44148449.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定