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

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

このコミットは、Go言語のツールチェインの一部である5lリンカ(ARM/ARM64アーキテクチャ向け)のsrc/cmd/5l/asm.cファイルから冗長なコードブロックを削除するものです。具体的には、テキストセグメント内の読み取り専用データを再度出力しようとしていた部分が削除されました。これは、当該データがリンカの別の場所ですでに適切に出力されていたため、重複した処理となっていたためです。この変更により、コードの簡潔性が向上し、潜在的な二重書き込みの問題が回避されます。

コミット

commit b24d1cb5ec707eee1bba219e1e09240f2433a2d2
Author: Shenghou Ma <minux.ma@gmail.com>
Date:   Mon Jan 16 19:29:54 2012 -0500

    5l: remove redundant code
            5l/asm.c: code in line 311-319 has already outputed segtext.sect->next;

    R=golang-dev, rsc
    CC=golang-dev
    https://golang.org/cl/5532048

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

https://github.com/golang/go/commit/b24d1cb5ec707eee1bba219e1e09240f2433a2d2

元コミット内容

5l: remove redundant code
        5l/asm.c: code in line 311-319 has already outputed segtext.sect->next;

R=golang-dev, rsc
CC=golang-dev
https://golang.org/cl/5532048

変更の背景

このコミットの背景には、Go言語のリンカである5lのコードベースにおける冗長性の排除と最適化があります。リンカは、コンパイルされたオブジェクトファイルやライブラリを結合し、実行可能なバイナリを生成する役割を担います。このプロセスでは、コード(テキストセグメント)やデータ(データセグメント、読み取り専用データセグメントなど)をメモリ上の適切な位置に配置し、ファイルに書き出す作業が行われます。

コミットメッセージによると、src/cmd/5l/asm.cの特定の行(311-319行目)のコードが、segtext.sect->nextが指すセクション(テキストセグメントの次のセクション、おそらく読み取り専用データセグメントなど)をファイルに出力する処理を行っていました。しかし、このデータはリンカの別の場所で既に適切に出力済みであったため、この部分のコードは完全に冗長であり、二重に同じデータを書き込もうとしていました。

このような冗長なコードは、実行ファイルのサイズを不必要に大きくしたり、リンカの処理時間をわずかに増加させたり、最悪の場合、ファイル構造の整合性に問題を引き起こす可能性がありました。したがって、このコミットは、コードのクリーンアップ、効率性の向上、および潜在的なバグの回避を目的としています。

前提知識の解説

このコミットを理解するためには、以下の概念を把握しておく必要があります。

  • Goツールチェイン: Go言語のプログラムを開発・ビルドするために必要な一連のツール群です。これには、コンパイラ(go tool compile)、アセンブラ(go tool asm)、リンカ(go tool link、またはアーキテクチャ固有の5l, 6l, 8lなど)が含まれます。
  • リンカ (Linker): コンパイラやアセンブラによって生成された複数のオブジェクトファイル(機械語コードとデータを含む)やライブラリを結合し、単一の実行可能なプログラム(バイナリファイル)を生成するソフトウェアです。リンカは、シンボル解決(関数や変数の参照を実際のメモリアドレスに解決する)や、コードとデータをメモリ上の適切なセグメントに配置する役割を担います。
  • 5l: Go言語の初期のリンカの一つで、特にARM/ARM64アーキテクチャ向けのリンカを指します。Goのツールチェインは、Plan 9オペレーティングシステムのツールチェインに由来しており、その命名規則(例: 5l for ARM, 6l for AMD64, 8l for x86)を受け継いでいます。現在では、go tool linkがアーキテクチャを自動的に判別して適切なリンカを呼び出すため、直接5lと呼ぶことは少なくなっていますが、内部的にはこれらのリンカが使用されています。
  • 実行ファイルの構造: 実行ファイルは通常、複数の論理的な「セグメント」に分割されています。
    • テキストセグメント (Text Segment): プログラムの実行可能な機械語コードが格納される領域です。通常、読み取り専用としてマークされます。
    • データセグメント (Data Segment): 初期化されたグローバル変数や静的変数が格納される領域です。読み書き可能です。
    • BSSセグメント (BSS Segment): 初期化されていないグローバル変数や静的変数が格納される領域です。実行時にゼロで初期化されます。
    • 読み取り専用データセグメント (Read-Only Data Segment): 定数文字列やその他の変更されないデータが格納される領域です。テキストセグメントの一部として扱われることもあります。
  • asm.c: このファイルは、5lリンカのバックエンドの一部であり、アセンブリコードの生成や、最終的な実行ファイルの構造を構築する低レベルな処理を担当しています。
  • cseekdatblk: これらは、Plan 9系のツールチェインでよく見られる低レベルなファイルI/O操作です。
    • cseek(offset): ファイルポインタを指定されたオフセットに移動させます。
    • datblk(vaddr, len): 指定された仮想アドレスvaddrからlenバイトのデータを読み取り、現在のファイルポインタ位置に書き込みます。これは、メモリ上のデータをファイルにダンプする操作に相当します。
  • segtext.sect->next: リンカの内部データ構造において、segtextはテキストセグメントに関する情報を保持しています。segtext.sectはそのセグメントの最初のセクションを指し、->nextはその次のセクション(例えば、テキストセグメントの直後に配置される読み取り専用データセグメントなど)を指します。

技術的詳細

このコミットは、src/cmd/5l/asm.cファイル内のasmb関数に焦点を当てています。asmb関数は、リンカの最終段階で、すべてのセグメントを結合し、実行ファイルをディスクに書き出す主要な役割を担っています。

削除されたコードブロックは以下の通りです。

-	/* output read-only data in text segment */
-	sect = segtext.sect->next;
-	cseek(sect->vaddr - segtext.vaddr + segtext.fileoff);
-	datblk(sect->vaddr, sect->len);

このブロックは、コメント/* output read-only data in text segment */が示すように、テキストセグメント内の読み取り専用データを出力することを意図していました。

  1. sect = segtext.sect->next;: segtext.sect->nextが指すセクション(テキストセグメントの次のセクション、通常は読み取り専用データなど)を取得しています。
  2. cseek(sect->vaddr - segtext.vaddr + segtext.fileoff);: ファイルポインタを、このセクションがファイル内で配置されるべきオフセットに移動させています。sect->vaddrはセクションの仮想アドレス、segtext.vaddrはテキストセグメントの仮想アドレス、segtext.fileoffはテキストセグメントのファイルオフセットです。これにより、相対的な位置を計算しています。
  3. datblk(sect->vaddr, sect->len);: 取得したセクションの仮想アドレスsect->vaddrからsect->lenバイトのデータを読み取り、現在のファイルポインタ位置(つまり、計算されたファイルオフセット)に書き込んでいます。

コミットメッセージが明確に述べているように、この一連の操作は冗長でした。つまり、このsectが指すデータは、asmb関数内の別の場所、またはリンカの処理のより早い段階で既にファイルに書き込まれていました。リンカの設計上、各セグメントやセクションは一度だけ正確な位置に書き込まれるべきです。二重書き込みは、無駄な処理であるだけでなく、ファイルの内容が意図しない形で上書きされたり、破損したりするリスクをはらんでいます。

この削除は、リンカのコードベースをよりクリーンで効率的に保つための保守作業の一環です。

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

--- a/src/cmd/5l/asm.c
+++ b/src/cmd/5l/asm.c
@@ -325,11 +325,6 @@ asmb(void)\n  \tcseek(segdata.fileoff);\n  \tdatblk(segdata.vaddr, segdata.filelen);\n  \n    -/* output read-only data in text segment */\n    -sect = segtext.sect->next;\n    -cseek(sect->vaddr - segtext.vaddr + segtext.fileoff);\n    -datblk(sect->vaddr, sect->len);\n    -\n  \tif(iself) {\n  \t\t/* index of elf text section; needed by asmelfsym, double-checked below */\n  \t\t/* !debug['d'] causes extra sections before the .text section */

コアとなるコードの解説

上記の差分が示すように、asmb関数内から5行のコードが削除されました。

削除された行は、以下の処理を行っていました。

  1. /* output read-only data in text segment */ というコメントで、このブロックの目的が「テキストセグメント内の読み取り専用データを出力する」ことであると示されています。
  2. sect = segtext.sect->next; で、テキストセグメントの次のセクションへのポインタを取得しています。これは通常、読み取り専用データセグメントや、テキストセグメントに続く他のセクションを指します。
  3. cseek(...)datblk(...) の呼び出しで、取得したセクションのデータをファイル内の適切なオフセットに書き込んでいました。

このコードブロックが削除された理由は、コミットメッセージに明記されている通り、「コードの311-319行目(削除された部分)は、segtext.sect->nextを既にファイルに出力している」ためです。これは、リンカの他の部分で、この読み取り専用データが既に正しく処理され、最終的な実行ファイルに書き込まれていることを意味します。したがって、このブロックは冗長であり、削除することでコードの重複をなくし、リンカの動作をより正確かつ効率的にすることができます。

関連リンク

参考にした情報源リンク

  • Go言語の公式ドキュメント (Go toolchain, linkerに関する情報)
  • Plan 9 from Bell Labs (Goツールチェインのルーツに関する情報)
  • ELFファイルフォーマットに関する一般的な情報 (セグメント、セクションの概念)
  • Go言語のリンカのソースコード (特にsrc/cmd/5l/ディレクトリ)
  • Go言語のIssueトラッカーやメーリングリスト (関連する議論や背景情報)