https://golangtokyo.connpass.com/event/293636/
© 2023 Wantedly, Inc.ログから学ぶgo buildgolang.tokyo #33Sep. 29 2023 - nasa
View Slide
今日のテーマ© 2023 Wantedly, Inc.
テーマgo buildのログを元にソースコードが実行ファイルになるまでを理解する© 2023 Wantedly, Inc.
準備© 2023 Wantedly, Inc.
準備package mainimport "fmt"func main() {fmt.Println("Hello World")}© 2023 Wantedly, Inc.利用するコード (main.go)
準備go buildコマンド© 2023 Wantedly, Inc.go build -x -p 1 -work main.go
準備go buildコマンド© 2023 Wantedly, Inc.go build -x -p 1 -work main.go-xオプションによりgo buildに呼び出されるコマンドを表示
go buildコマンド© 2023 Wantedly, Inc.go build -x -p 1 -work main.go-pオプションは並列数ログの読み取りやすさのために1並列で実行準備
go buildコマンド© 2023 Wantedly, Inc.go build -x -p 1 -work main.go-workは作業ディレクトリを残すオプションビルド中に吐かれる中間生成物を残しといて調査に使う準備
では実行してみよう© 2023 Wantedly, Inc.
© 2023 Wantedly, Inc.$ go build -x -p 1 -work main.goWORK=/var/folders/xx/xxxxxxxxxxxxx/T/go-buildxxxxxxxxmkdir -p $WORK/b005/cat >/var/folders/xx/xxxxxxxxxxxxx/T/go-buildxxxxxxxx/b005/importcfg << 'EOF' # internal# import configEOFcd /Users/xxxxx/lab/sandbox/playground_go/usr/local/go/pkg/tool/xxxxxxxx/compile -o $WORK/b005/_pkg_.a -trimpath "$WORK/b005=>" -p internal/goarch -std -+ -complete -buildidM8znE3RFNIIsfAk_eE8O/M8znE3RFNIIsfAk_eE8O -goversion go1.20.1 -c=8 -nolocalimports -importcfg $WORK/b005/importcfg -pack/usr/local/go/src/internal/goarch/goarch.go /usr/local/go/src/internal/goarch/goarch_amd64.go /usr/local/go/src/internal/goarch/zgoarch_amd64.go/usr/local/go/pkg/tool/xxxxxxxx/buildid -w $WORK/b005/_pkg_.a # internalcp $WORK/b005/_pkg_.a /Users/xxxxx/Library/Caches/go-build/8c/8cf7915e43e6ec3a1ceac20e15009d87c0d26d4aa40409e5dc8b2e935d6d1014-d # internalmkdir -p $WORK/b006/cat >/var/folders/xx/xxxxxxxxxxxxx/T/go-buildxxxxxxxx/b006/importcfg << 'EOF' # internal# import configEOF/usr/local/go/pkg/tool/xxxxxxxx/compile -o $WORK/b006/_pkg_.a -trimpath "$WORK/b006=>" -p internal/unsafeheader -std -complete -buildidsD4mccwa9DUJsmqBZGxG/sD4mccwa9DUJsmqBZGxG -goversion go1.20.1 -c=8 -nolocalimports -importcfg $WORK/b006/importcfg -pack/usr/local/go/src/internal/unsafeheader/unsafeheader.go/usr/local/go/pkg/tool/xxxxxxxx/buildid -w $WORK/b006/_pkg_.a # internal
© 2023 Wantedly, Inc.なんかいっぱい出た
© 2023 Wantedly, Inc.発表を聞き終わった後にはこれが理解できる(はず)
全体像© 2023 Wantedly, Inc.
© 2023 Wantedly, Inc.複数のビルドステップ全体像mkdirを境として複数のビルドステップが存在今回の例だとb001~b041
全体像© 2023 Wantedly, Inc.簡略化した全体像各ステップの出力ファイルの依存関係を表した図例えば、b040の出力がb031で使用されるパッケージの依存関係に基づいてコンパイル最後のb001/execで実行ファイルが生成
全体像© 2023 Wantedly, Inc.下記のように名付けて話を進めますb001~b041全体をコンパイルプロセスb001/execをリンクプロセス
全体像© 2023 Wantedly, Inc.コンパイルプロセスでは利用するパッケージ毎にコンパイルするソースコードが機械語へリンクプロセスでは機械語をつなぎ合わせて実行ファイルにする
全体像© 2023 Wantedly, Inc.依存関係を考慮しないと下記
全体像© 2023 Wantedly, Inc.(余談) 簡略化しないとこうなる
コンパイルプロセス© 2023 Wantedly, Inc.
© 2023 Wantedly, Inc.パッケージ毎にソースコードを機械語に変換するコンパイルプロセス
コンパイルプロセス1. importcfgの作成2. compile3. ビルドキャッシュの作成© 2023 Wantedly, Inc.mkdir -p $WORK/b002/# 1. importcfgcat >/var/folders/gb/0bh7j48d59n5fsy0wvpjd2fm0000gn/T/go-build3269867993/b002/importcfg << 'EOF' # internal# import configEOF# 2. compile/usr/local/go/pkg/tool/darwin_arm64/compile -o $WORK/b002/_pkg_.a -importcfg $WORK/b002/importcfg /usr/local/go/src/fmt/scan.go# 3. build cache/usr/local/go/pkg/tool/darwin_arm64/buildid -w $WORK/b002/_pkg_.a # internalcp $WORK/b002/_pkg_.a/Users/Library/Caches/go-build/b6/b68267d8212b1d8b8e54044a24b10869a453ec4e4a25163833c4f5928bd66aa6-d # internal
コンパイルプロセス© 2023 Wantedly, Inc.1. importcfgcat >/var/folders/gb/0bh7j48d59n5fsy0wvpjd2fm0000gn/T/go-build717416899/b033/importcfg << 'EOF' # internal# import configpackagefile errors=/var/folders/gb/0bh7j48d59n5fsy0wvpjd2fm0000gn/T/go-build717416899/b003/_pkg_.apackagefileinternal/syscall/unix=/var/folders/gb/0bh7j48d59n5fsy0wvpjd2fm0000gn/T/go-build717416899/b034/_pkg_.a(略)EOFコンパイル時に依存しているパッケージの情報が必要になるimportcfgファイルに情報をまとめている
© 2023 Wantedly, Inc.2. compile$ /usr/local/go/pkg/tool/darwin_arm64/compile \-o $WORK/b005/_pkg_.a \-importcfg $WORK/b005/importcfg \/usr/local/go/src/internal/goarch/goarch.go-o 出力ファイル-importcfg 先程作ったimportcfgはここで使う。AST構築・型チェックに利用コンパイルプロセス
© 2023 Wantedly, Inc.2. compile$ go tool pack t $WORK/b002/_pkg_.a # 中身の確認__.PKGDEF_go_.o$ go tool pack x $WORK/b002/_pkg_.a # 取り出すはたして何が作成されたのか?.aはアーカイブファイル(複数のファイルをまとめて一つのファイルへ変換したファイル)go tool packで個々のファイルを見ることが出来るコンパイルプロセス
© 2023 Wantedly, Inc.2. compile$ go tool objdump _go_.o…SUB $80, RSP, R17CMP R16, R17BLS 256(PC)__.PKGDEFパッケージ情報が詰まったファイル_go.oオブジェクトファイルプログラムの断片で機械語が書いてあるgo tool objdumpで人が読める形式にコンパイルプロセス
© 2023 Wantedly, Inc.3. ビルドキャッシュ各ステップごとにキャッシュを作成ソースコードが変わってなければキャッシュを再利用mkdir -p $WORK/b005/(略)/usr/local/go/pkg/tool/xxxxxxxx/buildid -w $WORK/b005/_pkg_.a # internalcp $WORK/b005/_pkg_.a/Users/xxxxx/Library/Caches/go-build/8c/8cf7915e43e6ec3a1ceac20e15009d87c0d26d4aa40409e5dc8b2e935d6d1014-d # internalコンパイルプロセス
(余裕があれば) 低レベルなパッケージのコンパイル© 2023 Wantedly, Inc.
© 2023 Wantedly, Inc.標準パッケージを見てみると一部関数はアセンブリ言語で実装してあるこういった低レベルなパッケージは先程とはプロセスが異なるコンパイルプロセス
コンパイルプロセス1. symabi2. compile© 2023 Wantedly, Inc./usr/local/go/pkg/tool/darwin_arm64/asm -p sync/atomic -gensymabis -o $WORK/b028/symabis ./asm.s/usr/local/go/pkg/tool/darwin_arm64/compile \-o $WORK/b028/_pkg_.a \-symabis $WORK/b028/symabis \-importcfg $WORK/b028/importcfg \-asmhdr $WORK/b028/go_asm.h \/usr/local/go/src/sync/atomic/value.go/usr/local/go/pkg/tool/darwin_arm64/asm -p sync/atomic -o $WORK/b028/asm.o ./asm.s/usr/local/go/pkg/tool/darwin_arm64/pack r $WORK/b028/_pkg_.a $WORK/b028/asm.o # internal
コンパイルプロセス© 2023 Wantedly, Inc.1. symabisusr/local/go/pkg/tool/darwin_arm64/asm -p sync/atomic -gensymabis -o $WORK/b028/symabis ./asm.sアセンブリのABIをファイルに書き出すABIは呼出規約を定めたもの引数のこの順番でスタック・レジスタに置きますね返り値はこの順番でスタック・レジスタに置きますねABIドキュメント: https://github.com/golang/go/blob/master/src/cmd/compile/abi-internal.mdソースコード: src/cmd/internal/obj/link.go
コンパイルプロセス© 2023 Wantedly, Inc.1. compile/usr/local/go/pkg/tool/darwin_arm64/compile -o $WORK/b028/_pkg_.a -p sync/atomic -symabis$WORK/b028/symabis -importcfg $WORK/b028/importcfg -pack -asmhdr $WORK/b028/go_asm.h \/usr/local/go/src/sync/atomic/doc.go \/usr/local/go/src/sync/atomic/type.go \/usr/local/go/src/sync/atomic/value.go/usr/local/go/pkg/tool/darwin_arm64/asm -p sync/atomic -o $WORK/b028/asm.o ./asm.sソースコードとアセンブリ言語を機械語に変換さっき生成したsymabisを利用
コンパイルプロセス© 2023 Wantedly, Inc.1. compile/usr/local/go/pkg/tool/darwin_arm64/pack r $WORK/b028/_pkg_.a $WORK/b028/asm.o # internal最後に生成物をまとめる
リンクプロセス© 2023 Wantedly, Inc.
リンク© 2023 Wantedly, Inc.リンクって何?コンパイルプロセスで作ったオブジェクトファイル(.oファイル)をつなぎ合わせて実行ファイルを作る
リンク© 2023 Wantedly, Inc.アドレス情報を埋めるオブジェクトファイルでは関数のアドレスを仮置きしている`R_CALLARM64`のように仮置きの場所がマーキングしてある$ go tool objdump b001/_pkg_.aTEXT main.main(SB) gofile../main.goprint.go:314 0x13cc 94000000 CALL 0(PC) [0:4]R_CALLARM64:fmt.Fprintln余談: リロケーションタイプはsrc/cmd/internal/objabi/reloctype.goにまとまっている
リンク© 2023 Wantedly, Inc.アドレス情報を埋めるオブジェクトファイルと実行ファイルの差分を見てみる`R_CALL`が消え、0(PC)と適当な値だったがアドレス(ラベル)になっている
リンク© 2023 Wantedly, Inc.実行ファイルmacOSやLinuxなどターゲットに応じた実行形式をサポートしているmacOSだったらMach-OlinuxならELF$ file mainmain: Mach-O 64-bit executable arm64
ということで実行ファイルが手に入った🎉© 2023 Wantedly, Inc.
まとめ© 2023 Wantedly, Inc.
まとめ© 2023 Wantedly, Inc.● ログや生成ファイルをガチャガチャやるだけでも色々と分かる● 豊富なデバッグオプション・デバッグツールが揃ってる
まとめ© 2023 Wantedly, Inc.扱ったのはほんの一部
俺達の戦いはこれから?© 2023 Wantedly, Inc.
自己紹介© 2023 Wantedly, Inc.● nasa (Asan Kondo)● Wantedly,Inc.所属● 推薦基盤の開発・運用● ハンドルネームnasaが欲しい○ GitHub: @k-nasa○ X(Twitter): @nasa_desu
ご清聴ありがとうございました© 2023 Wantedly, Inc.