Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

[インデックス 18236] ファイルの概要

このコミットは、Go言語のリンカ (cmd/link) における自動シンボル生成機能の実装とテストに関するものです。リンカがプログラムをビルドする際に、特定のシンボル(例えば、浮動小数点定数やセクションの開始/終了アドレスを示すシンボル)を自動的に生成し、それらを適切に配置・解決するメカニズムを導入しています。これにより、リンカの柔軟性と効率性が向上し、コンパイラやアセンブラが生成するコードとの連携がよりスムーズになります。

コミット

commit 7cecac3cbbd16baf80c9d15b92fc55444bf2870e
Author: Russ Cox <rsc@golang.org>
Date:   Mon Jan 13 23:07:57 2014 -0500

    cmd/link: implement and test automatic symbols
    
    Related changes included in this CL:
    
     - Add explicit start symbol to Prog.
     - Add omitRuntime bool to Prog.
     - Introduce p.Packages[""] to hold automatic symbols
     - Add SymOrder to Prog to preserve symbol order.
     - Add layout test (and fix bug that was putting everything in text section).
    
    R=iant
    CC=golang-codereviews
    https://golang.org/cl/51260045

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/7cecac3cbbd16baf80c9d15b92fc55444bf2870e

元コミット内容

このコミットの元の内容は、Goリンカにおける自動シンボルの実装とテストです。具体的には、以下の関連する変更が含まれています。

  • Prog構造体に明示的な開始シンボルを追加。
  • Prog構造体にomitRuntimeブール値を追加。
  • 自動生成シンボルを保持するためのp.Packages[""]を導入。
  • シンボル順序を保持するためのSymOrderProgに追加。
  • レイアウトテストを追加し、すべてのシンボルがテキストセクションに配置されるバグを修正。

変更の背景

Goリンカは、コンパイルされたオブジェクトファイルから実行可能ファイルを生成する役割を担っています。このプロセスにおいて、プログラムの実行に必要な様々な情報(コード、データ、メタデータなど)をメモリ上に適切に配置する必要があります。

以前のリンカでは、一部のシンボル(例えば、浮動小数点定数やセクションの境界を示すシンボル)が明示的に定義されていない場合、リンカがそれらを適切に処理できない、あるいは非効率な方法で処理する可能性がありました。特に、浮動小数点定数は、アセンブラの構文で直接表現することが難しく、リンカが自動的に適切なメモリ領域に配置し、そのアドレスを解決する必要がありました。

また、リンカがシンボルをメモリに配置する際の順序は、最終的な実行可能ファイルの構造やパフォーマンスに影響を与える可能性があります。特に、デバッグ情報やランタイムの内部構造を正確に表現するためには、シンボルの順序を保持することが重要でした。

このコミットは、これらの課題に対処し、リンカがより堅牢かつ効率的に動作するように、以下の目的で自動シンボル生成のメカニズムを導入しました。

  1. 浮動小数点定数の自動処理: $f64.$f32.といった形式の浮動小数点定数シンボルをリンカが自動的に認識し、適切なデータとしてメモリに配置できるようにする。これにより、コンパイラやアセンブラがこれらの定数をより柔軟に扱えるようになる。
  2. セクション境界シンボルの自動定義: text, data, bssなどのセクションの開始(text)と終了(etext)を示すシンボルをリンカが自動的に定義し、プログラムの構造をより明確にする。
  3. 弱いシンボルの解決: go.weak.プレフィックスを持つ弱いシンボルを導入し、リンカが実行時にそのシンボルが存在すれば解決し、存在しなければゼロアドレスに解決するメカニズムを提供する。これは、オプションの機能やプラットフォーム固有の機能の実装に役立つ。
  4. シンボル順序の保持: リンカがシンボルを処理する順序を明示的に保持するメカニズムを導入し、レイアウトの予測可能性とデバッグの容易性を向上させる。
  5. リンカの内部構造の改善: Prog構造体の拡張や、シンボル管理の改善を通じて、リンカの内部構造をより整理し、将来的な拡張性を高める。

これらの変更により、Goリンカはより複雑なプログラム構造や最適化に対応できるようになり、Goプログラムのビルドプロセス全体の信頼性と効率性が向上しました。

前提知識の解説

このコミットを理解するためには、以下のGo言語およびリンカに関する基本的な知識が必要です。

  1. Go言語のビルドプロセス:

    • Go言語のソースコードは、まずコンパイラ(go tool compile)によってオブジェクトファイル(.oファイル)にコンパイルされます。
    • オブジェクトファイルには、機械語コード、データ、シンボル情報、再配置情報などが含まれます。
    • 次に、リンカ(go tool link)がこれらのオブジェクトファイルを結合し、実行可能ファイル(またはライブラリ)を生成します。
    • リンカは、シンボル解決(未定義のシンボルを定義済みのシンボルに紐付ける)、再配置(アドレス依存のコードやデータを修正する)、セクションの配置(コードやデータをメモリ上の適切な位置に配置する)などの処理を行います。
  2. シンボル:

    • シンボルは、プログラム内の関数、変数、セクションなどのメモリ上の位置を識別するための名前です。
    • 例えば、main関数はmainというシンボルで表され、そのアドレスはリンカによって決定されます。
    • 定義済みシンボル: オブジェクトファイル内でアドレスが確定しているシンボル。
    • 未定義シンボル: オブジェクトファイル内で参照されているが、アドレスがまだ確定していないシンボル。リンカが他のオブジェクトファイルやライブラリから定義を探して解決します。
    • 弱いシンボル (Weak Symbols): 複数の定義が存在する場合でもエラーにならず、リンカが優先順位に基づいていずれかを選択するか、定義が存在しない場合はゼロアドレスに解決するシンボル。これは、オプションの機能や、特定のプラットフォームでのみ利用可能な機能の実装によく用いられます。
  3. セクション:

    • 実行可能ファイルは、異なる種類のデータやコードを格納するために複数のセクションに分割されます。一般的なセクションには以下のようなものがあります。
      • .text (または __TEXT): 実行可能な機械語コードが格納されます。
      • .data (または __DATA): 初期化された読み書き可能なデータ(グローバル変数など)が格納されます。
      • .rodata (または __RODATA): 読み取り専用データ(文字列リテラル、定数など)が格納されます。
      • .bss (または __BSS): 初期化されていない読み書き可能なデータ(グローバル変数など)が格納されます。実行時にゼロで初期化されます。
      • .noptrdata / .noptrbss: ポインタを含まないデータセクション。ガベージコレクタがスキャンする必要がないため、GCの効率化に寄与します。
      • .pclntab: Goランタイムのプログラムカウンタと行番号の対応テーブル(スタックトレースやプロファイリングに利用)。
      • .functab: 関数テーブル。
      • .typelink: 型情報へのリンク。
    • セグメント: 複数の関連するセクションをまとめたもので、メモリ保護の単位となります。例えば、.text.rodataは通常、読み取り専用のセグメントにまとめられます。
  4. 再配置 (Relocation):

    • オブジェクトファイル内のコードやデータには、まだ最終的なアドレスが確定していない他のシンボルへの参照が含まれることがあります。
    • リンカは、これらの参照を、最終的な実行可能ファイル内の正しいアドレスに修正する「再配置」処理を行います。
    • 例えば、ある関数が別の関数を呼び出す場合、呼び出し命令には呼び出される関数のアドレスが必要ですが、コンパイル時にはそのアドレスは不明です。リンカが最終的なアドレスを決定し、呼び出し命令を修正します。
  5. debug/goobjパッケージ:

    • Goのオブジェクトファイル(.oファイル)の構造を定義し、読み書きするためのパッケージです。
    • goobj.SymIDはシンボルを一意に識別するためのIDです。
    • goobj.SymKindはシンボルの種類(テキスト、データ、BSSなど)を表します。
  6. Mach-O (macOS/iOSの実行可能ファイル形式):

    • macOSやiOSで使用される実行可能ファイル形式です。ELF(Linuxなど)やPE(Windows)とは異なる構造を持ちます。
    • Mach-Oでは、rodataセグメントがサポートされていないため、読み取り専用データは通常textセグメントに配置されます。

これらの概念を理解することで、コミットがリンカのどの部分に影響を与え、どのような問題を解決しようとしているのかを深く把握することができます。

技術的詳細

このコミットは、Goリンカのシンボル管理とメモリレイアウトのメカニズムに大きな変更を加えています。主要な技術的詳細は以下の通りです。

  1. 自動シンボル生成 (auto.goの導入):

    • src/cmd/link/auto.goが新しく追加され、リンカが自動的に生成するシンボルに関するロジックがカプセル化されました。
    • 浮動小数点定数: $f64.{16 hex digits}(64ビット)や$f32.{8 hex digits}(32ビット)という形式のシンボルを認識し、対応するIEEEビットパターンを持つバイト列としてSRODATA(読み取り専用データ)セクションに配置します。これにより、コンパイラやアセンブラが直接浮動小数点定数を埋め込むのではなく、リンカに解決を委ねることで、より柔軟なコード生成が可能になります。
    • 弱いシンボル: go.weak.プレフィックスを持つシンボルを処理します。これは、リンカがgo.weak.symというシンボルを見つけた場合、symという実際のシンボルが存在すればそのアドレスに解決し、存在しなければゼロアドレス(nil)に解決するメカニズムを提供します。これは、オプションの機能や、特定の環境でのみ利用可能な機能の実装に役立ちます。
    • リンカ定義シンボル: linkerDefinedマップに、bss, data, text, endなどのリンカが内部的に使用するセクション境界シンボルを定義しています。これらのシンボルは、isAuto関数によって自動生成シンボルとして識別されます。
  2. Prog構造体の拡張 (prog.go):

    • Prog構造体はリンカの全体的な状態を保持する中心的な構造体です。このコミットで以下のフィールドが追加・変更されました。
      • StartSym string: プログラムの実行開始点となるシンボルの名前を明示的に指定できるようになりました。以前はハードコードされた_rt0_goでした。
      • omitRuntime bool: ランタイムパッケージのロードを省略するかどうかを制御するフラグ。テストなどでランタイムなしのバイナリを生成する際に便利です。
      • Packages map[string]*Package: パッケージ情報を保持するマップですが、このコミットではp.Packages[""]というエントリが導入され、内部的に生成される自動シンボルを保持するための「匿名パッケージ」として機能します。
      • SymOrder []*Sym: シンボルがスキャンされた順序を保持するスライスです。これにより、リンカがシンボルを処理する際の順序が保証され、レイアウトの予測可能性が向上します。特に、layout.goでのセクション配置において、この順序が利用されます。
      • arch struct: ターゲットアーキテクチャに依存する設定(バイトオーダーやポインタサイズ)をカプセル化するための構造体。これにより、リンカのアーキテクチャ依存部分がより明確になります。
    • linkメソッド内で、p.autoData()p.autoConst()が呼び出されるようになり、自動シンボル生成がリンカの主要な処理フローに組み込まれました。
    • initメソッドでは、StartSymが設定されていない場合にデフォルトのランタイム開始シンボル(例: _rt0_amd64_darwin)を生成するロジックが追加されました。
  3. メモリレイアウトの改善 (layout.go):

    • layout配列が変更され、セクションの順序がより明確に定義されました。特に、rodataセクションがtextセクションの直後に配置されるようになりました。
    • layoutByKindマップの初期化ロジックが修正され、layout配列の各エントリへのポインタを正しく保持するようになりました。
    • p.layout()関数が、p.SymOrderを使用してシンボルを処理するようになりました。これにより、シンボルがスキャンされた順序でセクションに割り当てられることが保証されます。
    • シンボルのデータサイズが0でもsym.Bytesにデータがある場合にsect.InFile = trueを設定する条件が追加されました。これは、自動生成シンボルがsym.Bytesフィールドに直接データを持つ場合に対応するためです。
    • Mach-O(Darwin)の場合、rodataセグメントが存在しないため、rodataセクションをtextセグメントに配置する特殊な処理が追加されました。
    • セクションの開始アドレスと終了アドレスを示すシンボル(例: text, etext, data, edataなど)が、p.defineConstを使って自動的に定義されるようになりました。これにより、プログラム内でこれらのセクション境界をシンボルとして参照できるようになります。
  4. シンボル解決とスキャン処理の強化 (scan.go):

    • scan関数において、未解決のシンボルが存在し、かつomitRuntimefalseの場合にruntimeパッケージをスキャンするロジックが追加されました。
    • 未解決のシンボルを報告する際に、自動生成シンボル(p.isAuto(sym))は除外されるようになりました。
    • scanFile関数において、再配置シンボルや関数データシンボルがp.Missingマップに追加される際のチェックが強化されました。
    • 重複シンボル定義の処理が改善されました。
      • 両方がBSS(データなし)の場合、サイズの最大値を取る。
      • 一方がBSSで他方がデータを持つ場合、データを持つ方を優先する。
      • DupOK(重複が許容される)とマークされているシンボルは、最初に見つかった方を保持する。
      • それ以外の場合はエラーとして報告する。
    • addSymヘルパー関数が導入され、シンボルをp.Symspkg.Symsp.SymOrderに一貫して追加するようになりました。また、内部生成シンボルを保持するための匿名パッケージp.Packages[""]が利用されます。
  5. ロード処理の変更 (load.go):

    • loadPackage関数が、ファイルを持たないパッケージ(つまり、内部生成シンボルのみを含む匿名パッケージp.Packages[""])を処理できるようになりました。これらのシンボルはsym.Bytesフィールドに直接データを持つため、ファイルからの読み込みは不要です。
    • シンボルにセクションが割り当てられていない場合の内部エラーチェックが追加されました。
    • 再配置処理において、binary.LittleEndianの代わりにp.byteorderを使用するよう変更され、リンカがターゲットアーキテクチャのバイトオーダーを正しく扱うようになりました。
  6. Mach-Oフォーマットの調整 (macho.go):

    • Mach-Oヘッダーのエンコード時に、バイトオーダーをp.byteorderから取得するよう変更されました。これにより、リンカがターゲットアーキテクチャのバイトオーダー設定を尊重するようになります。

これらの変更は、Goリンカの内部動作をより洗練させ、特に低レベルのメモリレイアウトとシンボル管理において、より柔軟で正確な制御を可能にしています。

コアとなるコードの変更箇所

このコミットにおけるコアとなるコードの変更箇所は、主に以下のファイルと関数に集中しています。

  1. src/cmd/link/auto.go (新規ファイル):

    • linkerDefinedマップ: リンカが内部的に定義するシンボル(セクション境界など)のリスト。
    • isAuto(sym goobj.SymID) bool: シンボルが自動生成されたデータまたは定数シンボルであるかを報告する関数。go.weak., $f64., $f32.プレフィックス、およびlinkerDefinedマップ内のシンボルをチェックします。
    • autoData(): 浮動小数点定数($f64., $f32.)を解析し、対応するバイト列をSRODATAシンボルとして生成するロジック。
    • autoConst(): 弱いシンボル(go.weak.)を解決し、対応する定数シンボルを生成するロジック。
    • defineConst(name string, addr Addr): 指定された名前とアドレスで新しい定数シンボルを定義するヘルパー関数。
  2. src/cmd/link/prog.go:

    • Prog構造体へのフィールド追加:
      type Prog struct {
          // ...
          StartSym string
          // ...
          arch
          formatter   formatter
          startSym    goobj.SymID
          pkgdir      string
          omitRuntime bool // do not load runtime package
          // ...
          Packages   map[string]*Package  // loaded packages, by import path
          Syms       map[goobj.SymID]*Sym // defined symbols, by symbol ID
          Missing    map[goobj.SymID]bool // missing symbols
          Dead       map[goobj.SymID]bool // symbols removed as dead
          SymOrder   []*Sym               // order syms were scanned
          // ...
      }
      
    • linkメソッド内でのautoData()autoConst()の呼び出し:
      func (p *Prog) link(w io.Writer, mainFile string) {
          // ...
          p.dead()
          p.runtime()
          p.autoData() // <-- 追加
          p.layout()
          p.autoConst() // <-- 追加
          // ...
      }
      
    • initメソッドでのStartSymarchの初期化ロジック。
  3. src/cmd/link/layout.go:

    • layout配列の変更:
      var layout = []layoutSection{
          {Segment: "text", Section: "text", Kind: goobj.STEXT},
          {Segment: "rodata", Section: "rodata", Kind: goobj.SRODATA}, // <-- 順序変更
          {Segment: "rodata", Section: "functab", Kind: goobj.SPCLNTAB}, // <-- 順序変更
          {Segment: "rodata", Section: "typelink", Kind: goobj.STYPELINK}, // <-- 順序変更
          {Segment: "data", Section: "noptrdata", Kind: goobj.SNOPTRDATA}, // <-- 順序変更
          {Segment: "data", Section: "data", Kind: goobj.SDATA},
          {Segment: "data", Section: "bss", Kind: goobj.SBSS}, // <-- 順序変更
          {Segment: "data", Section: "noptrbss", Kind: goobj.SNOPTRBSS}, // <-- 順序変更
          // ...
      }
      
    • p.layout()関数内でのp.SymOrderの使用:
      func (p *Prog) layout() {
          // ...
          // Assign symbols to sections using index, creating sections as needed.
          // Could keep sections separated by type during input instead.
          for _, sym := range p.SymOrder { // <-- p.Symsからp.SymOrderに変更
              // ...
          }
          // ...
          // Define symbols for section names.
          var progEnd Addr
          for i, sect := range sections {
              name := layout[i].Section
              var start, end Addr
              if sect != nil {
                  start = sect.VirtAddr
                  end = sect.VirtAddr + sect.Size
              }
              p.defineConst(name, start) // <-- セクション開始シンボルの定義
              p.defineConst("e"+name, end) // <-- セクション終了シンボルの定義
              progEnd = end
          }
          p.defineConst("end", progEnd) // <-- プログラム終了シンボルの定義
      }
      
    • Mach-O (darwin) でのrodataセグメントの特別処理。
  4. src/cmd/link/scan.go:

    • initScan()でのp.Missing[p.startSym] = trueへの変更。
    • scan関数でのp.isAuto(sym)による未解決シンボルのフィルタリング。
    • scanFile関数での重複シンボル定義のより詳細な処理ロジック。
    • addSym(s *Sym)ヘルパー関数の追加:
      func (p *Prog) addSym(s *Sym) {
          pkg := s.Package
          if pkg == nil {
              pkg = p.Packages[""] // <-- 匿名パッケージの利用
              if pkg == nil {
                  pkg = &Package{}
                  p.Packages[""] = pkg
              }
              s.Package = pkg
          }
          pkg.Syms = append(pkg.Syms, s)
          p.Syms[s.SymID] = s
          p.SymOrder = append(p.SymOrder, s) // <-- SymOrderへの追加
      }
      
  5. src/cmd/link/load.go:

    • loadPackage関数でのpkg.File == ""(内部生成シンボルのみのパッケージ)の特別処理。
    • relocateSym関数でのp.byteorderの使用。

これらの変更は、リンカのシンボル管理、メモリレイアウト、およびアーキテクチャ依存の処理方法を根本的に改善しています。

コアとなるコードの解説

src/cmd/link/auto.go

このファイルは、リンカが自動的に生成するシンボルに関するロジックをカプセル化しています。

  • linkerDefinedマップ:

    var linkerDefined = map[string]bool{
        "bss":        true,
        "data":       true,
        "ebss":       true,
        "edata":      true,
        "efunctab":   true,
        "end":        true,
        "enoptrbss":  true,
        "enoptrdata": true,
        "erodata":    true,
        "etext":      true,
        "etypelink":  true,
        "functab":    true,
        "gcbss":      true,
        "gcdata":     true,
        "noptrbss":   true,
        "noptrdata":  true,
        "pclntab":    true,
        "rodata":     true,
        "text":       true,
        "typelink":   true,
    }
    

    このマップは、リンカが内部的に定義するセクションの開始/終了アドレスを示すシンボル(例: text, etext, data, edataなど)を列挙しています。これらのシンボルは、プログラムのメモリレイアウトを明確にし、他のコードから参照できるようにするために自動的に生成されます。

  • isAuto(sym goobj.SymID) bool:

    func (p *Prog) isAuto(sym goobj.SymID) bool {
        return strings.HasPrefix(sym.Name, "go.weak.") ||
            strings.HasPrefix(sym.Name, "$f64.") ||
            strings.HasPrefix(sym.Name, "$f32.") ||
            linkerDefined[sym.Name]
    }
    

    この関数は、与えられたシンボルがリンカによって自動的に生成されるべきシンボルであるかどうかを判定します。具体的には、弱いシンボル(go.weak.)、浮動小数点定数シンボル($f64., $f32.)、およびlinkerDefinedマップに登録されているセクション境界シンボルを自動シンボルとして識別します。これにより、リンカはこれらのシンボルを特別に扱い、未定義エラーとして報告しないようにできます。

  • autoData():

    func (p *Prog) autoData() {
        for sym := range p.Missing {
            switch {
            case strings.HasPrefix(sym.Name, "$f64."), strings.HasPrefix(sym.Name, "$f32."):
                // ... 浮動小数点定数の処理 ...
            }
        }
    }
    

    この関数は、リンカが未解決のシンボルの中から浮動小数点定数シンボル($f64., $f32.)を見つけ、それらを実際のデータとして生成します。シンボル名からIEEE 754形式のビットパターンを抽出し、それをバイト列に変換してSRODATA(読み取り専用データ)セクションに配置される新しいシンボルとしてp.addSymで追加します。これにより、コンパイラやアセンブラは浮動小数点定数を直接埋め込む代わりに、リンカにその解決を委ねることができます。

  • autoConst():

    func (p *Prog) autoConst() {
        for sym := range p.Missing {
            switch {
            case strings.HasPrefix(sym.Name, "go.weak."):
                // ... 弱いシンボルの処理 ...
            }
        }
    }
    

    この関数は、リンカが未解決のシンボルの中から弱いシンボル(go.weak.)を見つけ、それらを解決します。go.weak.symというシンボルは、symという実際のシンボルが存在すればそのアドレスに解決され、存在しなければゼロアドレスに解決されます。これは、オプションの機能や、特定のプラットフォームでのみ利用可能な機能の実装に役立ちます。

src/cmd/link/prog.go

Prog構造体はリンカの全体的な状態を保持する中心的な構造体です。

  • Prog構造体の変更: StartSym, omitRuntime, SymOrder, archなどのフィールドが追加されました。 SymOrderは、リンカがシンボルをスキャンした順序を保持する重要なフィールドです。これにより、リンカがシンボルを処理する際の順序が保証され、特にメモリレイアウトの決定において予測可能性が向上します。

  • linkメソッド:

    func (p *Prog) link(w io.Writer, mainFile string) {
        // ...
        p.autoData()
        p.layout()
        p.autoConst()
        // ...
    }
    

    linkメソッドはリンカの主要な処理フローを定義しています。このコミットにより、p.autoData()p.autoConst()p.layout()の前後で呼び出されるようになりました。これは、自動生成シンボルがメモリレイアウトの前に生成され、その後にレイアウトが適用され、最後に定数シンボルが解決されるという論理的な順序を保証します。

src/cmd/link/layout.go

このファイルは、プログラムのメモリレイアウトを決定するロジックを含んでいます。

  • layout配列:

    var layout = []layoutSection{
        {Segment: "text", Section: "text", Kind: goobj.STEXT},
        {Segment: "rodata", Section: "rodata", Kind: goobj.SRODATA},
        {Segment: "rodata", Section: "functab", Kind: goobj.SPCLNTAB},
        // ...
    }
    

    この配列は、異なる種類のシンボルがどのセグメントとセクションに配置されるべきかを定義しています。このコミットでは、セクションの順序が調整され、より論理的なメモリ配置が実現されました。

  • p.layout()関数:

    func (p *Prog) layout() {
        // ...
        for _, sym := range p.SymOrder { // <-- p.SymOrderを使用
            // ...
        }
        // ...
        // Define symbols for section names.
        // ...
        p.defineConst(name, start)
        p.defineConst("e"+name, end)
        // ...
    }
    

    p.layout()関数は、p.SymOrder(シンボルがスキャンされた順序)を使用して、各シンボルを適切なセクションに割り当てます。これにより、リンカはシンボルを予測可能な順序でメモリに配置できます。また、この関数は、text, data, bssなどの各セクションの開始アドレスと終了アドレスを示すシンボル(例: text, etext)を自動的に定義し、プログラムの構造をより明確にします。Mach-O(Darwin)プラットフォームでは、rodataセグメントが存在しないため、rodataセクションがtextセグメントに配置されるように特別に処理されます。

src/cmd/link/scan.go

このファイルは、オブジェクトファイルをスキャンし、シンボル情報を収集するロジックを含んでいます。

  • addSym(s *Sym)関数:
    func (p *Prog) addSym(s *Sym) {
        pkg := s.Package
        if pkg == nil {
            pkg = p.Packages[""] // <-- 匿名パッケージの利用
            if pkg == nil {
                pkg = &Package{}
                p.Packages[""] = pkg
            }
            s.Package = pkg
        }
        pkg.Syms = append(pkg.Syms, s)
        p.Syms[s.SymID] = s
        p.SymOrder = append(p.SymOrder, s) // <-- SymOrderへの追加
    }
    
    このヘルパー関数は、新しいシンボルをリンカの内部データ構造に一貫して追加するために導入されました。特に、p.Packages[""]という匿名パッケージが導入され、リンカが内部的に生成するシンボル(例えば、自動生成された浮動小数点定数やセクション境界シンボル)を保持するために使用されます。また、p.SymOrderスライスにシンボルを追加することで、シンボルがスキャンされた順序が保持されます。

これらのコアとなるコードの変更は、Goリンカがシンボルを管理し、実行可能ファイルを構築する方法を大幅に改善し、より複雑なシナリオや最適化に対応できるようにしています。

関連リンク

  • Go言語のリンカに関する公式ドキュメント(該当する時期のものが直接見つからないため、一般的なリンカの概念を理解するためのリソースを推奨)
  • Go言語のソースコードリポジトリ: https://github.com/golang/go
  • Go言語のIssue Tracker: https://github.com/golang/go/issues

参考にした情報源リンク

  • コミットハッシュ: 7cecac3cbbd16baf80c9d15b92fc55444bf2870e
  • Go言語のコードレビューシステム: https://golang.org/cl/51260045 (このリンクは古いGoのコードレビューシステムのものであり、現在はGerritに移行しています。しかし、コミットメッセージに記載されているため参照しました。)
  • Go言語のリンカの一般的な概念に関する情報(Goの公式ドキュメントやGoのソースコードを読み解くためのブログ記事など)
    • Goのリンカの仕組みに関する一般的な解説記事やGoのソースコード(src/cmd/linkディレクトリ)自体が主な情報源となります。
    • Goのリンカの進化に関する議論や設計ドキュメント(もし公開されていれば)も参考になります。
    • debug/goobjパッケージのドキュメント(Goの標準ライブラリの一部)

(注: 2014年当時のGoリンカの内部実装に関する詳細な公開ドキュメントは限られているため、主にコミット内容とGoのソースコード自体から情報を抽出しました。)