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

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

このコミットは、Go言語のリンカである5l-v(verbose)オプションの出力から、不要な情報を削減することを目的としています。具体的には、リンカのベンチマーク時に出力される、重複シンボルに関するメッセージがノイズとなるため、これらをコメントアウトすることで出力を整理しています。

コミット

  • コミットハッシュ: 94b796133b3a236530f933362a3feb90af1fcbf2
  • 作者: Shenghou Ma minux.ma@gmail.com
  • コミット日時: 2012年1月31日 火曜日 10:59:29 -0500
  • コミットメッセージ:
    5l: make -v option output less nonessential clutter
            5l -v is for benchmarking various parts of the loader, but this code in
            obj.c will clutter the output. I only comment them out, because this is
            on par with 8l/6l.
    
    R=golang-dev
    CC=golang-dev
    https://golang.org/cl/5600046
    

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

https://github.com/golang/go/commit/94b796133b3a236530f933362a3feb90af1fcbf2

元コミット内容

5l: make -v option output less nonessential clutter
        5l -v is for benchmarking various parts of the loader, but this code in
        obj.c will clutter the output. I only comment them out, because this is
        on par with 8l/6l.

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

変更の背景

この変更の背景には、Go言語のツールチェーンにおけるリンカのデバッグおよびベンチマークの効率化があります。5lはGo言語のARMアーキテクチャ向けリンカであり、-vオプションは通常、詳細なデバッグ情報や処理の進行状況を出力するために使用されます。しかし、リンカの特定の処理(この場合は重複シンボルのスキップ)に関するメッセージが、ベンチマークの際に大量に出力され、本来のベンチマーク結果の分析を妨げる「ノイズ」となっていました。

コミットメッセージにある「5l -v is for benchmarking various parts of the loader」という記述から、開発者がリンカのパフォーマンス特性を詳細に分析するために-vオプションを利用していたことが伺えます。この文脈において、不要な出力は分析の妨げとなるため、それらを抑制する必要がありました。

また、「this is on par with 8l/6l」という記述は、他のアーキテクチャ(8lはx86-64、6lはx86-32)向けのリンカでも同様の出力抑制が行われていることを示唆しており、5lもそれに合わせて一貫性を持たせる意図があったと考えられます。これは、Goツールチェーン全体でのデバッグ出力の標準化の一環とも言えるでしょう。

前提知識の解説

このコミットを理解するためには、以下のGo言語のツールチェーンおよびC言語の基本的な概念に関する知識が必要です。

  • Go言語のリンカ (5l, 6l, 8l): Go言語のビルドプロセスにおいて、コンパイルされたオブジェクトファイル(.oファイル)を結合し、実行可能なバイナリを生成する役割を担うのがリンカです。Goのリンカは、伝統的なUnix系のリンカ(ldなど)とは異なり、Go言語のランタイムやガベージコレクタ、スケジューラなどの特殊な要件に対応するために独自に実装されています。

    • 5l: ARMアーキテクチャ向けのリンカです。Goのソースコードでは、アーキテクチャごとに異なるリンカが用意されており、5lはその一つです。
    • 6l: x86-32アーキテクチャ向けのリンカです。
    • 8l: x86-64アーキテクチャ向けのリンカです。 これらのリンカは、それぞれ対応するアーキテクチャのオブジェクトファイルを処理し、最終的な実行ファイルを生成します。
  • debug['v']: これは、Go言語のツールチェーン内でよく見られるデバッグフラグのパターンです。debugは通常、コマンドラインオプションや環境変数によって設定されるデバッグレベルを保持するマップまたは配列のような構造体です。debug['v']は、リンカが詳細な(verbose)出力を生成するかどうかを制御するブール値として機能します。このフラグがtrueの場合、通常はより多くの情報が標準出力またはエラー出力に表示されます。

  • Bprint(&bso, ...): Bprintは、C言語で書かれたGoツールチェーンのコードベースでよく使用される、バッファリングされた出力関数です。bsoは通常、標準出力(stdout)または標準エラー出力(stderr)に関連付けられたバッファリングされたストリームオブジェクトです。この関数は、指定されたフォーマット文字列と引数を使用して、bsoにデータを書き込みます。バッファリングにより、I/O操作のオーバーヘッドを削減し、パフォーマンスを向上させることができます。

  • s->dupok: sはシンボル(Sym構造体)へのポインタであり、dupokはそのシンボルが重複を許容するかどうかを示すフラグです。リンカは、複数のオブジェクトファイルから同じ名前のシンボルが定義されている場合、通常はエラーを報告します。しかし、一部のシンボル(例えば、弱いシンボルや特定のセクションのシンボル)は重複が許容される場合があります。dupokフラグは、リンカがそのようなシンボルを検出した際に、エラーとせずにスキップして処理を続行すべきかどうかを判断するために使用されます。

  • goto loop;: C言語におけるgoto文は、プログラムの実行フローを特定のラベルにジャンプさせるために使用されます。このコンテキストでは、重複が許容されるシンボルが検出された場合、現在のシンボル処理をスキップして、次のシンボルを処理するためのループの先頭に戻るために使用されています。

技術的詳細

このコミットは、Go言語のリンカ5lのソースコードsrc/cmd/5l/obj.c内の特定のデバッグ出力行をコメントアウトすることで、-vオプション使用時の出力を削減しています。

リンカの処理において、複数のオブジェクトファイルから同じ名前のシンボルが定義されている場合、通常はリンケージエラーとなります。しかし、Go言語のリンカでは、特定のシンボルに対してdupok(duplicate OK)フラグが設定されている場合、そのシンボルが重複していてもエラーとせず、最初の定義を採用し、後続の重複定義をスキップするロジックが存在します。

変更前のコードでは、このdupokフラグが設定されたシンボルをスキップする際に、debug['v']true(つまり、-vオプションが有効)であれば、「skipping %s in %s: dupok\n」(%sはシンボル名とファイル名)というメッセージをBprint関数を使って出力していました。このメッセージは、リンカがどのシンボルを重複としてスキップしたかを示すもので、通常のデバッグ時には有用な情報です。

しかし、リンカのパフォーマンスをベンチマークする際には、この「スキップ」メッセージが大量に出力されることがあり、特に大規模なプロジェクトや多数の重複シンボルが存在する場合には、出力が膨大になり、ベンチマーク結果の解析を困難にしていました。コミットメッセージが示唆するように、5l -vはリンカの各部分のベンチマークを目的としているため、このような「非本質的な雑多な出力(nonessential clutter)」は排除されるべきでした。

この変更は、これらのBprint呼び出しをC言語のコメントアウト構文//で無効化することで、-vオプションが有効であっても、重複シンボルスキップ時のメッセージが出力されないようにしています。これにより、ベンチマーク実行時の出力がクリーンになり、開発者はより本質的なパフォーマンスデータに集中できるようになります。

このアプローチは、8l6lといった他のアーキテクチャ向けリンカでも同様の出力抑制が行われていることと「同等(on par)」であるとされており、Goツールチェーン全体でのデバッグ出力の一貫性を保つ意図も含まれています。

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

変更はsrc/cmd/5l/obj.cファイルに対して行われました。

--- a/src/cmd/5l/obj.c
+++ b/src/cmd/5l/obj.c
@@ -558,8 +558,8 @@ loop:
 		// redefinitions.
 		s = p->from.sym;
 		if(s->dupok) {
-\t\t\tif(debug['v'])\n-\t\t\t\tBprint(&bso, \"skipping %s in %s: dupok\\n\", s->name, pn);\n
+//\t\t\tif(debug['v'])\n+//\t\t\t\tBprint(&bso, \"skipping %s in %s: dupok\\n\", s->name, pn);\n
 		\tgoto loop;\n
 		}\n
 		if(s->file == nil)\n

コアとなるコードの解説

変更されたコードブロックは、リンカがシンボルを処理するループ(loop:ラベル)の中にあります。

  1. s = p->from.sym;: 現在処理しているプログラム要素pから、関連するシンボルsを取得しています。
  2. if(s->dupok) { ... }: この条件文は、取得したシンボルsdupokフラグ(重複を許容するフラグ)を持っているかどうかをチェックしています。
  3. 変更前:
    if(debug['v'])
        Bprint(&bso, "skipping %s in %s: dupok\n", s->name, pn);
    
    debug['v']trueの場合(つまり、-vオプションが有効な場合)、Bprint関数を使って「skipping %s in %s: dupok\n」というメッセージを出力していました。s->nameはスキップされるシンボルの名前、pnはそのシンボルが定義されているファイルの名前です。
  4. 変更後:
    //		if(debug['v'])
    //			Bprint(&bso, "skipping %s in %s: dupok\n", s->name, pn);
    
    元のif文とその中のBprint呼び出しが、C言語の単一行コメント//によって完全にコメントアウトされています。これにより、debug['v']trueであっても、このメッセージは一切出力されなくなりました。
  5. goto loop;: dupokシンボルが検出された場合、メッセージの出力有無にかかわらず、現在のシンボル処理をスキップして、リンカのメインループの先頭に戻り、次のシンボルの処理に進みます。

この変更は、リンカの機能的な動作には影響を与えず、-vオプション使用時の出力内容のみを変更するものです。これにより、リンカのベンチマークやデバッグ作業において、よりクリーンで関連性の高い情報のみが得られるようになります。

関連リンク

参考にした情報源リンク

  • Go言語のリンカに関する一般的な情報:
    • Go linker and object files (Go公式ドキュメントのAssemblerのセクションにリンカの概要が含まれています)
    • The Go linker (Russ CoxによるGoリンカに関するブログ記事)
  • C言語のgoto文:
  • Go言語のツールチェーンにおけるデバッグフラグの慣習:
    • Go言語のソースコードを検索することで、debug['v']のようなパターンが他のツールでも使用されていることが確認できます。
  • Bprint関数に関する情報:
    • Go言語のツールチェーンのC言語ソースコード内でBprintの定義を検索することで、その機能と使用法を理解できます。
    • 例: src/cmd/internal/obj/util.go (Goのツールチェーン内のユーティリティ関数)
  • dupokシンボルに関する情報:
    • Go言語のリンカのソースコード(例: src/cmd/link/internal/ld/sym.goなど)でdupokフラグの定義と使用箇所を検索することで、その目的と動作を詳細に理解できます。