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

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

このコミットは、Goコンパイラのcmd/5c (ARM), cmd/6c (x86-64), cmd/8c (x86) の各バックエンドが、共通のリンカライブラリであるliblinkを使用するように変更するものです。これは、Go 1.3のリンカの大規模な再構築(golang.org/s/go13linkerで計画された作業)に向けた準備の一環として行われました。この変更により、各アーキテクチャ固有のコンパイラから重複するリンカ関連のコードが削除され、共通のliblinkインターフェースを通じてリンカ機能が提供されるようになります。

コミット

76a8c873cf06cfc42e3c306ac3f18e62795253d3

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

https://github.com/golang/go/commit/76a8c873cf06cfc42e3c306ac3f18e62795253d3

元コミット内容

cmd/5c, cmd/6c, cmd/8c: use liblink

Preparation for golang.org/s/go13linker work.

This CL does not build by itself. It depends on 35740044
and 35790044 and will be submitted at the same time.

R=iant
CC=golang-dev
https://golang.org/cl/34580044

変更の背景

このコミットは、Go 1.3のリンカの大規模な再構築プロジェクト(golang.org/s/go13linker)の一環として実施されました。当時のGoのツールチェインでは、各アーキテクチャ(ARM, x86-64, x86など)のコンパイラ(cmd/5c, cmd/6c, cmd/8c)がそれぞれリンカの一部機能を独自に実装していました。これにより、コードの重複やメンテナンスの複雑さが増していました。

go13linkerプロジェクトの目的は、リンカのパフォーマンスを向上させ、その機能をよりモジュール化することでした。そのために、リンカの機能をliblinkという共通ライブラリに集約し、コンパイラからこのliblinkを呼び出す形に移行する計画が立てられました。

このコミットは、その移行の第一歩として、各コンパイラがliblinkを使用するようにコードベースを調整するものです。コミットメッセージにもあるように、この変更単体ではビルドが通らず、他の関連する変更(3574004435790044)と同時に適用されることを前提としていました。これにより、リンカの命令選択フェーズがコンパイラ側に移動し、リンカの機能が再編成されることになります。

前提知識の解説

  • Goコンパイラ (cmd/5c, cmd/6c, cmd/8c): Go言語のソースコードを機械語に変換するプログラムです。5cはARMアーキテクチャ向け、6cはx86-64アーキテクチャ向け、8cはx86アーキテクチャ向けのコンパイラを指します。これらはGo 1.5以前のコンパイラであり、現在はcmd/compileに統合されています。
  • Goリンカ: コンパイラによって生成されたオブジェクトファイルやライブラリを結合し、実行可能なバイナリを生成するプログラムです。
  • liblink: Go 1.3のリンカ再構築プロジェクトで導入された共通リンカライブラリです。リンカの共通機能をカプセル化し、コンパイラや他のツールから利用できるように設計されました。これにより、リンカのコードベースが整理され、重複が排除されました。
  • golang.org/s/go13linker: Russ Coxによって2013年11月に公開された「Go 1.3 Linker Overhaul」というドキュメントを指します。このドキュメントでは、Goリンカのパフォーマンス改善とモジュール化のための詳細な計画が述べられており、liblinkの導入もその一環でした。
  • Adr (Address) 構造体: 以前のGoコンパイラで使用されていた、メモリアドレスやレジスタ、定数などのオペランドを表すための構造体です。
  • Prog (Program) 構造体: 以前のGoコンパイラで使用されていた、単一の機械語命令を表すための構造体です。
  • Sym (Symbol) / LSym (Linker Symbol): プログラム内の変数、関数、ラベルなどのシンボル情報を表す構造体です。LSymliblink導入後にリンカが管理するシンボルを表すために導入されました。

技術的詳細

このコミットの主要な技術的変更点は、各アーキテクチャ固有のコンパイラ(cmd/5c, cmd/6c, cmd/8c)から、リンカ関連のコードを削除し、共通のliblinkライブラリが提供する機能に置き換えることです。

具体的には、以下の変更が行われています。

  1. AdrおよびProg構造体の削除とAddrへの移行:
    • src/cmd/5c/gc.h, src/cmd/6c/gc.h, src/cmd/8c/gc.hなどのヘッダファイルから、AdrおよびProg構造体の定義が削除されています。
    • これらの構造体を使用していた箇所は、liblinkで定義されているAddr構造体(またはその概念)に置き換えられています。これにより、コンパイラとリンカ間のデータ構造が共通化され、インターフェースが簡素化されます。
    • 例えば、typedef struct Adr Adr;typedef struct Prog Prog; の行が削除され、#define A ((Addr*)0) のようにAddrが使われるようになっています。
  2. リンカ関連のユーティリティ関数の削除:
    • src/cmd/5c/swt.c, src/cmd/6c/swt.c, src/cmd/8c/swt.cなどから、オブジェクトファイルの書き出しやシンボル名の管理など、リンカが担当していた多くのユーティリティ関数(例: zwrite, outhist, zname, zaddr)が削除されています。
    • これらの機能はliblink内部で処理されるようになり、コンパイラはlinkouthistlinkwritefuncsといったliblinkのAPIを呼び出す形に変更されています。
  3. シンボル管理の変更 (SymからLSymへ):
    • src/cmd/5c/gc.h, src/cmd/6c/gc.h, src/cmd/8c/gc.hにおいて、Var構造体内のシンボルポインタがSym*からLSym*に変更されています。これは、リンカが管理するシンボルがLSym型で表現されるようになったためです。
    • naddr関数など、シンボルを扱う関数内でlinksym(n->sym)のようにliblinkのシンボル変換関数が使用されるようになっています。
  4. 浮動小数点定数と文字列定数の扱い:
    • src/cmd/5c/list.c, src/cmd/6c/list.c, src/cmd/8c/list.cなどにおいて、浮動小数点定数(D_FCONST)や文字列定数(D_SCONST)の内部表現がa->dvala->svalからa->u.dvala->u.svalに変更されています。これは、Addr構造体内で共用体(union)が使用されるようになったためと考えられます。
  5. firstpの削除とPlistの導入:
    • src/cmd/5c/txt.c, src/cmd/6c/txt.c, src/cmd/8c/txt.cにおいて、命令リストの先頭を指すfirstpグローバル変数が削除されています。
    • 代わりに、linknewplist(ctxt)を呼び出してPlist構造体を取得し、そのfirstpcフィールドに命令リストの先頭を設定する形に変更されています。これは、liblinkが命令リストの管理を行うようになったことを示しています。
  6. アーキテクチャ固有のリンカアーキテクチャ設定:
    • src/cmd/5c/txt.c, src/cmd/6c/txt.c, src/cmd/8c/txt.cにおいて、LinkArch *thelinkarch = &linkarm; のように、各アーキテクチャに対応するLinkArch構造体へのポインタが設定されています。これにより、liblinkが現在のコンパイル対象アーキテクチャを認識できるようになります。

これらの変更は、コンパイラとリンカの間の責任分担を明確にし、リンカのコードベースをよりクリーンでメンテナンスしやすいものにするための重要なステップでした。

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

このコミットでは、主に以下のファイル群が変更されています。

  • src/cmd/5c/gc.h, src/cmd/6c/gc.h, src/cmd/8c/gc.h: 各アーキテクチャのコンパイラのヘッダファイル。AdrProg構造体の削除、Var構造体のSym*からLSym*への変更、および関連する関数のプロトタイプ変更。
  • src/cmd/5c/list.c, src/cmd/6c/list.c, src/cmd/8c/list.c: 命令リストの出力に関するファイル。AdrからAddrへの型変更、シンボルがnilかどうかのチェック、浮動小数点定数や文字列定数のアクセス方法の変更。
  • src/cmd/5c/peep.c, src/cmd/6c/peep.c, src/cmd/8c/peep.c: 命令の最適化(peephole optimization)に関するファイル。AdrからAddrへの型変更。
  • src/cmd/5c/reg.c, src/cmd/6c/reg.c, src/cmd/8c/reg.c: レジスタ割り当てに関するファイル。AdrからAddrへの型変更、Sym*からLSym*への変更。
  • src/cmd/5c/swt.c, src/cmd/6c/swt.c, src/cmd/8c/swt.c: スイッチ文の処理やオブジェクトファイルの書き出しに関するファイル。リンカ関連のユーティリティ関数(zwrite, outhist, zname, zaddr)の削除と、liblinkのAPI呼び出しへの置き換え。文字列定数のアクセス方法の変更。
  • src/cmd/5c/txt.c, src/cmd/6c/txt.c, src/cmd/8c/txt.c: テキストセクションの生成に関するファイル。firstpの削除とPlistの導入、naddr関数でのlinksymの使用、thelinkarchの設定。
  • src/cmd/cc/cc.h, src/cmd/cc/lex.c, src/cmd/cc/macbody, src/cmd/cc/pswt.c, src/cmd/cc/sub.c: Cコンパイラ関連のファイル。一部のリンカ関連の定義やコードが削除されています。

これらの変更は、各コンパイラからリンカの低レベルな実装詳細を抽象化し、liblinkという共通インターフェースを通じてリンカ機能を利用するようにするためのものです。

コアとなるコードの解説

このコミットの核心は、Goコンパイラのバックエンド(cmd/5c, cmd/6c, cmd/8c)が、リンカとの連携方法を根本的に変更した点にあります。

  1. データ構造の共通化: 以前は各コンパイラが独自にAdrProgといった命令やアドレスを表す構造体を持っていましたが、このコミットでこれらが削除され、liblinkが提供する共通のAddr構造体を使用するようになりました。これにより、コンパイラとリンカの間で命令やオペランドの表現が統一され、データの受け渡しがより効率的かつ安全になります。例えば、naddr関数(ノードからアドレス構造体を生成する関数)の引数がAdr*からAddr*に変更されています。
  2. リンカ機能の委譲: オブジェクトファイルの書き出し(outcode関数内)やシンボル情報の管理(zname, zaddrなど)といった、以前はコンパイラが直接行っていた多くのリンカ関連の処理が削除され、liblinkのAPI(linkouthist, linkwritefuncsなど)に委譲されるようになりました。これにより、コンパイラは命令生成に専念し、リンカはオブジェクトファイルの最終的な生成と結合に専念するという、役割分担が明確化されました。
  3. シンボル解決の一元化: SymからLSymへの移行は、リンカがプログラム全体のシンボル情報を一元的に管理するための基盤を強化します。コンパイラはlinksymのような関数を通じて、ローカルなシンボルをリンカが認識できるグローバルなシンボルに変換するようになりました。
  4. モジュール性の向上: これらの変更により、Goのツールチェイン全体のモジュール性が大幅に向上しました。リンカの機能がliblinkにカプセル化されたことで、将来的にリンカの実装を変更したり、新しいアーキテクチャをサポートしたりする際に、コンパイラ側の変更を最小限に抑えることができるようになりました。これは、Go 1.3のリンカ再構築の主要な目標の一つでした。

このコミットは、Goのビルドシステムがより堅牢でスケーラブルになるための重要な基盤を築いたと言えます。

関連リンク

参考にした情報源リンク