Go build したバイナリには何がはいっているのか

Go がバイナリのみで動く理由


Posted on 2020年 1月 27日 (月)
Tags golang, binary
golang, binary

Go build したバイナリの中身を知りたい

Go は go build すると実行可能なシングルバイナリが生成される。これは、各OS別にビルドしていて、サイズは小さくとも数MBになる(Go 1.13)。

What is included in a Golang binary? - Quora にてすでに簡単な答えがある。

1Go のバイナリには
21. Go の runtime
32. goroutine scheduler
43. kernel とのインターフェース
54. reflection で利用する runtime の型情報
65. ファイルや行などスタックトレースに使われる情報

では、実際にその割合は見られるのだろうか。

go tool nm でバイナリを解析する

nm - The Go Programming Language という tool を使う(name の略だろうか)。

 1Nm lists the symbols defined or used by an object file, archive, or executable.
 2
 3T text (code) segment symbol
 4t static text segment symbol
 5R read-only data segment symbol
 6r static read-only data segment symbol
 7D data segment symbol
 8d static data segment symbol
 9B bss segment symbol
10b static bss segment symbol
11C constant address
12U referenced but undefined symbol

hello world のみのバイナリの内訳を見てみた。

1package main
2
3import (
4    "fmt"
5)
6
7func main() {
8    fmt.Println("Hello Go!")
9}
 1$ ls
 22.0M  1 20 00:13 simple*
 3
 4$ go tool nm -size -sort size simple | head -n 100
 5           16781312 U _mach_absolute_time
 6           16781312 U _usleep
 7           16781312 U _sysctl
 8           16781312 U _stat64
 9           16781312 U _sigaltstack
10           16781312 U _sigaction
11           16781312 U _setitimer
12           16781312 U _readdir_r$INODE64
13           16781312 U _read
14           16781312 U _raise
15           16781312 U _pthread_sigmask
16           16781312 U _pthread_mutex_unlock
17           16781312 U _pthread_mutex_lock
18           ...
19           16781312 U _mach_timebase_info
20           16781312 U _exit
21           16781312 U _pthread_attr_init
22
23 10ee080     481753 R runtime.pclntab
24 1099560     223232 R runtime.types
25 1099560     223232 R type.*
26 1099560     223232 R runtime.rodata
27 10d7123      68357 R go.func.*
28 1183840      65744 B runtime.trace
29 10cfd60      29635 R go.string.*
30 1169380      25920 D runtime.firstmoduledata
31 1066600      20080 T unicode.init
32 117f980      16064 B runtime.semtable
33 1171dc0      14720 D fmt.ppFree
34 1096890      10224 T fmt.(*pp).printValue
35 117d280       9984 B runtime.mheap_
36 1083f60       8336 T time.Time.AppendFormat
37 117b280       8192 B runtime.timers
38 1179300       8064 B runtime.cpuprof
39 1047940       6720 T runtime.gentraceback
40 116f8c0       6712 D strconv.powersOfTen
41 11947a0       5992 B runtime.memstats
42 107deb0       5264 T internal/fmtsort.compare
43 1087070       4640 T time.LoadLocationFromTZData
44 10823d0       4464 T time.nextStdChunk
45 1176fa0       4112 D runtime.itabTableInit
46 104ca30       3936 T runtime.typesEqual
47 10e7c28       3835 R runtime.gcbits.*
48 103ee30       3344 T runtime.newstack
49 10ed300       3328 R runtime.typelink
50 1088440       3312 T time.loadTzinfoFromZip
51 1070fd0       3088 T reflect.FuncOf
52 105b6a0       3056 T internal/reflectlite.haveIdenticalUnderlyingType
53 106ffb0       3056 T reflect.haveIdenticalUnderlyingType
54 10ec5e0       3050 R runtime.findfunctab
55 102fba0       3024 T runtime.findrunnable
56 1072450       2928 T reflect.funcLayout
57 1017b80       2896 T runtime.gcMarkTermination
58 10620c0       2880 T strconv.appendEscapedRune
59 108db30       2848 T os.Getwd

pclntab とはなにか

src/debug/gosym/pclntab.go - The Go Programming Language

このデータは go のプログラムがクラッシュしたときに stack trace を生成するためのもの。

Program Counter Line Table の略語のようだ。関数がふえるとこのシンボルは増加するため、大規模な Go プログラムは pclntab が大きくなる。

Go1.2 からもともと圧縮していた文字列を展開した状態でバイナリに同梱されるというのだ。

なぜ変えたのかというと、Go 1.1 ではバイナリ起動時に圧縮した文字列を展開するのに時間がかかっていた。 そこで、圧縮を止めてバイナリの起動を速くしたということだそうだ。

参考

Share


See also