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 ではバイナリ起動時に圧縮した文字列を展開するのに時間がかかっていた。 そこで、圧縮を止めてバイナリの起動を速くしたということだそうだ。