$30 off During Our Annual Pro Sale. View Details »

ログから学ぶgo build

nasa
September 28, 2023

ログから学ぶgo build

nasa

September 28, 2023
Tweet

More Decks by nasa

Other Decks in Technology

Transcript

  1. © 2023 Wantedly, Inc.
    ログから学ぶgo build
    golang.tokyo #33
    Sep. 29 2023 - nasa

    View Slide

  2. 今日のテーマ
    © 2023 Wantedly, Inc.

    View Slide

  3. テーマ
    go buildのログを元に
    ソースコードが実行ファイルにな
    るまでを理解する
    © 2023 Wantedly, Inc.

    View Slide

  4. 準備
    © 2023 Wantedly, Inc.

    View Slide

  5. 準備
    package main
    import "fmt"
    func main() {
    fmt.Println("Hello World")
    }
    © 2023 Wantedly, Inc.
    利用するコード (main.go)

    View Slide

  6. 準備
    go buildコマンド
    © 2023 Wantedly, Inc.
    go build -x -p 1 -work main.go

    View Slide

  7. 準備
    go buildコマンド
    © 2023 Wantedly, Inc.
    go build -x -p 1 -work main.go
    -xオプションによりgo buildに呼び出されるコマンドを表示

    View Slide

  8. go buildコマンド
    © 2023 Wantedly, Inc.
    go build -x -p 1 -work main.go
    -pオプションは並列数
    ログの読み取りやすさのために1並列で実行
    準備

    View Slide

  9. go buildコマンド
    © 2023 Wantedly, Inc.
    go build -x -p 1 -work main.go
    -workは作業ディレクトリを残すオプション
    ビルド中に吐かれる中間生成物を残しといて調査に使う
    準備

    View Slide

  10. では実行してみよう
    © 2023 Wantedly, Inc.

    View Slide

  11. © 2023 Wantedly, Inc.
    $ go build -x -p 1 -work main.go
    WORK=/var/folders/xx/xxxxxxxxxxxxx/T/go-buildxxxxxxxx
    mkdir -p $WORK/b005/
    cat >/var/folders/xx/xxxxxxxxxxxxx/T/go-buildxxxxxxxx/b005/importcfg << 'EOF' # internal
    # import config
    EOF
    cd /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 -buildid
    M8znE3RFNIIsfAk_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 # internal
    cp $WORK/b005/_pkg_.a /Users/xxxxx/Library/Caches/go-build/8c/8cf7915e43e6ec3a1ceac20e15009d87c0d26d4aa40409e5dc8b2e935d6d1014-d # internal
    mkdir -p $WORK/b006/
    cat >/var/folders/xx/xxxxxxxxxxxxx/T/go-buildxxxxxxxx/b006/importcfg << 'EOF' # internal
    # import config
    EOF
    /usr/local/go/pkg/tool/xxxxxxxx/compile -o $WORK/b006/_pkg_.a -trimpath "$WORK/b006=>" -p internal/unsafeheader -std -complete -buildid
    sD4mccwa9DUJsmqBZGxG/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

    View Slide

  12. © 2023 Wantedly, Inc.
    なんかいっぱい出た

    View Slide

  13. © 2023 Wantedly, Inc.
    発表を聞き終わった後にはこれが理解できる(はず)

    View Slide

  14. 全体像
    © 2023 Wantedly, Inc.

    View Slide

  15. © 2023 Wantedly, Inc.
    複数のビルドステップ
    全体像
    mkdirを境として複数のビルドステップが存在
    今回の例だとb001~b041

    View Slide

  16. 全体像
    © 2023 Wantedly, Inc.
    簡略化した全体像
    各ステップの出力ファイルの依存関係を表した図
    例えば、b040の出力がb031で使用される
    パッケージの依存関係に基づいてコンパイル
    最後のb001/execで実行ファイルが生成

    View Slide

  17. 全体像
    © 2023 Wantedly, Inc.
    下記のように名付けて話を進めます
    b001~b041全体をコンパイルプロセス
    b001/execをリンクプロセス

    View Slide

  18. 全体像
    © 2023 Wantedly, Inc.
    コンパイルプロセスでは利用するパッケージ毎に
    コンパイルする
    ソースコードが機械語へ
    リンクプロセスでは機械語をつなぎ合わせて実
    行ファイルにする

    View Slide

  19. 全体像
    © 2023 Wantedly, Inc.
    依存関係を考慮しないと下記

    View Slide

  20. 全体像
    © 2023 Wantedly, Inc.
    (余談) 簡略化しないとこうなる

    View Slide

  21. コンパイルプロセス
    © 2023 Wantedly, Inc.

    View Slide

  22. © 2023 Wantedly, Inc.
    パッケージ毎にソースコードを機械語に変換する
    コンパイルプロセス

    View Slide

  23. コンパイルプロセス
    1. importcfgの作成
    2. compile
    3. ビルドキャッシュの作成
    © 2023 Wantedly, Inc.
    mkdir -p $WORK/b002/
    # 1. importcfg
    cat >/var/folders/gb/0bh7j48d59n5fsy0wvpjd2fm0000gn/T/go-build3269867993/b002/importcfg << 'EOF' # internal
    # import config
    EOF
    # 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 # internal
    cp $WORK/b002/_pkg_.a
    /Users/Library/Caches/go-build/b6/b68267d8212b1d8b8e54044a24b10869a453ec4e4a25163833c4f5928bd66aa6-d # internal

    View Slide

  24. コンパイルプロセス
    © 2023 Wantedly, Inc.
    1. importcfg
    cat >/var/folders/gb/0bh7j48d59n5fsy0wvpjd2fm0000gn/T/go-build717416899/b033/importcfg << 'EOF' # internal
    # import config
    packagefile errors=/var/folders/gb/0bh7j48d59n5fsy0wvpjd2fm0000gn/T/go-build717416899/b003/_pkg_.a
    packagefile
    internal/syscall/unix=/var/folders/gb/0bh7j48d59n5fsy0wvpjd2fm0000gn/T/go-build717416899/b034/_pkg_.a
    (略)
    EOF
    コンパイル時に依存しているパッケージの情報が必要になる
    importcfgファイルに情報をまとめている

    View Slide

  25. © 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構築・型チェックに利用
    コンパイルプロセス

    View Slide

  26. © 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で個々のファイルを見ることが出来る
    コンパイルプロセス

    View Slide

  27. © 2023 Wantedly, Inc.
    2. compile
    $ go tool objdump _go_.o

    SUB $80, RSP, R17
    CMP R16, R17
    BLS 256(PC)
    __.PKGDEF
    パッケージ情報が詰まったファイル
    _go.o
    オブジェクトファイル
    プログラムの断片で機械語が書いてある
    go tool objdumpで人が読める形式に
    コンパイルプロセス

    View Slide

  28. © 2023 Wantedly, Inc.
    3. ビルドキャッシュ
    各ステップごとにキャッシュを作成
    ソースコードが変わってなければキャッシュを再利用
    mkdir -p $WORK/b005/
    (略)
    /usr/local/go/pkg/tool/xxxxxxxx/buildid -w $WORK/b005/_pkg_.a # internal
    cp $WORK/b005/_pkg_.a
    /Users/xxxxx/Library/Caches/go-build/8c/8cf7915e43e6ec3a1ceac20e15009d87c0d26d4aa40409e5dc8b2e935d6d10
    14-d # internal
    コンパイルプロセス

    View Slide

  29. (余裕があれば) 低レベルなパッケージの
    コンパイル
    © 2023 Wantedly, Inc.

    View Slide

  30. © 2023 Wantedly, Inc.
    標準パッケージを見てみると一部関数はアセンブリ言語で実装し
    てある
    こういった低レベルなパッケージは先程とはプロセスが異なる
    コンパイルプロセス

    View Slide

  31. コンパイルプロセス
    1. symabi
    2. 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

    View Slide

  32. コンパイルプロセス
    © 2023 Wantedly, Inc.
    1. symabis
    usr/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

    View Slide

  33. コンパイルプロセス
    © 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を利用

    View Slide

  34. コンパイルプロセス
    © 2023 Wantedly, Inc.
    1. compile
    /usr/local/go/pkg/tool/darwin_arm64/pack r $WORK/b028/_pkg_.a $WORK/b028/asm.o # internal
    最後に生成物をまとめる

    View Slide

  35. リンクプロセス
    © 2023 Wantedly, Inc.

    View Slide

  36. リンク
    © 2023 Wantedly, Inc.
    リンクって何?
    コンパイルプロセスで作ったオブジェクトファイル(.oファイル)をつなぎ合わせて実行ファイルを作

    View Slide

  37. リンク
    © 2023 Wantedly, Inc.
    アドレス情報を埋める
    オブジェクトファイルでは関数のアドレスを仮置きしている
    `R_CALLARM64`のように仮置きの場所がマーキングしてある
    $ go tool objdump b001/_pkg_.a
    TEXT main.main(SB) gofile../main.go
    print.go:314 0x13cc 94000000 CALL 0(PC) [0:4]R_CALLARM64:fmt.Fprintln
    余談: リロケーションタイプはsrc/cmd/internal/objabi/reloctype.goにまとまっている

    View Slide

  38. リンク
    © 2023 Wantedly, Inc.
    アドレス情報を埋める
    オブジェクトファイルと実行ファイルの差分を見てみる
    `R_CALL`が消え、0(PC)と適当な値だったがアドレス(ラベル)になっている

    View Slide

  39. リンク
    © 2023 Wantedly, Inc.
    実行ファイル
    macOSやLinuxなどターゲットに応じた実行形式をサポートしている
    macOSだったらMach-O
    linuxならELF
    $ file main
    main: Mach-O 64-bit executable arm64

    View Slide

  40. ということで
    実行ファイルが手に入った🎉
    © 2023 Wantedly, Inc.

    View Slide

  41. まとめ
    © 2023 Wantedly, Inc.

    View Slide

  42. まとめ
    © 2023 Wantedly, Inc.
    ● ログや生成ファイルをガチャガチャやるだけでも色々と分かる
    ● 豊富なデバッグオプション・デバッグツールが揃ってる

    View Slide

  43. まとめ
    © 2023 Wantedly, Inc.
    扱ったのはほんの一部

    View Slide

  44. 俺達の戦いはこれから?
    © 2023 Wantedly, Inc.

    View Slide

  45. 自己紹介
    © 2023 Wantedly, Inc.
    ● nasa (Asan Kondo)
    ● Wantedly,Inc.所属
    ● 推薦基盤の開発・運用
    ● ハンドルネームnasaが欲しい
    ○ GitHub: @k-nasa
    ○ X(Twitter): @nasa_desu

    View Slide

  46. ご清聴ありがとうございました
    © 2023 Wantedly, Inc.

    View Slide