深入了解 Go ELF 信息

本文深入探讨了Go二进制文件中的ELF格式,包括ELF头、程序头和节头。通过实例展示了如何获取Go版本和模块信息,并详细解释了Linux系统中ELF文件的结构。此外,还介绍了readelf和objdump工具的使用,以及Go代码中实现这些功能的原理。
摘要由CSDN通过智能技术生成

大家好,我是张晋涛。

我们用 Go 构建的二进制文件中默认包含了很多有用的信息。例如,可以获取构建用的 Go 版本:

(这里我使用我一直参与的一个开源项目 KIND[1] 为例)

➜  kind git:(master) ✗ go version ./bin/kind 
./bin/kind: go1.16

或者也可以获取该二进制所依赖的模块信息:

➜  kind git:(master) ✗ go version -m ./bin/kind
./bin/kind: go1.16
        path    sigs.k8s.io/kind
        mod     sigs.k8s.io/kind        (devel)
        dep     github.com/BurntSushi/toml      v0.3.1
        dep     github.com/alessio/shellescape  v1.4.1
        dep     github.com/evanphx/json-patch/v5        v5.2.0
        dep     github.com/mattn/go-isatty      v0.0.12
        dep     github.com/pelletier/go-toml    v1.8.1  h1:1Nf83orprkJyknT6h7zbuEGUEjcyVlCxSUGTENmNCRM=
        dep     github.com/pkg/errors   v0.9.1
        dep     github.com/spf13/cobra  v1.1.1
        dep     github.com/spf13/pflag  v1.0.5
        dep     golang.org/x/sys        v0.0.0-20210124154548-22da62e12c0c      h1:VwygUrnw9jn88c4u8GD3rZQbqrP/tgas88tPUbBxQrk=
        dep     gopkg.in/yaml.v2        v2.2.8
        dep     gopkg.in/yaml.v3        v3.0.0-20210107192922-496545a6307b      h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
        dep     k8s.io/apimachinery     v0.20.2
        dep     sigs.k8s.io/yaml        v1.2.0

查看 KIND 代码仓库中的 go.mod文件,都包含在内了。

其实 Linux 系统中二进制文件包含额外的信息并非 Go 所特有的,下面我将具体介绍其内部原理和实现。当然,用 Go 构建的二进制文件仍是本文的主角。

Linux ELF 格式

ELF 是 Executable and Linkable Format 的缩写,是一种用于可执行文件、目标文件、共享库和核心转储(core dump)的标准文件格式。ELF 文件 通常 是编译器之类的输出,并且是二进制格式。以 Go 编译出的可执行文件为例,我们使用 file 命令即可看到其具体类型 ELF 64-bit LSB executable

➜  kind git:(master) ✗ file ./bin/kind 
./bin/kind: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, not stripped

本文中我们来具体看看 64 位可执行文件使用的 ELF 文件格式的结构和 Linux 内核源码中对它的定义。

使用 ELF 文件格式的可执行文件是由 ELF 头(ELF Header) 开始,后跟 程序头(Program Header) 或 节头(Section Header) 或两者均有组成的。

ELF 头

ELF 头始终位于文件的零偏移(zero offset)处(即:起点位置),同时在 ELF 头中还定义了程序头和节头的偏移量。

我们可以通过 readelf 命令查看可执行文件的 ELF 头,如下:

➜  kind git:(master) ✗ readelf -h ./bin/kind 
ELF Header:
  Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 
  Class:                             ELF64
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              EXEC (Executable file)
  Machine:                           Advanced Micro Devices X86-64
  Version:                           0x1
  Entry point address:               0x46c460
  Start of program headers:          64 (bytes into file)
  Start of section headers:          400 (bytes into file)
  Flags:                             0x0
  Size of this header:               64 (bytes)
  Size of program headers:           56 (bytes)
  Number of program headers:         6
  Size of section headers:           64 (bytes)
  Number of section headers:         15
  Section header string table index: 3

从上面的输出我们可以看到,ELF 头是以某个 Magic 开始的,此 Magic 标识了有关文件的信息,即:前四个 16 进制数,表示这是一个 ELF 文件。具体来说,将它们换算成其对应的 ASCII 码即可:

45 = E 

4c = L 

46 = F

7f 是其前缀,当然,也可以直接在 Linux 内核源码[2]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

张晋涛-MoeLove

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值