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

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

このコミットは、Go言語のリンカ (cmd/ld) におけるデバッグ情報生成の挙動を修正するものです。具体的には、外部リンカを使用する場合に、ELF (Executable and Linkable Format) 形式以外のターゲットに対しては DWARF デバッグ情報を生成しないように変更が加えられました。これにより、リンカの効率化と、特定のプラットフォームでのデバッグ情報の互換性問題の回避が図られています。

コミット

commit 2a1ca145cf0489160ca284e08eeca4673563c007
Author: Rob Pike <r@golang.org>
Date:   Tue Apr 30 14:22:28 2013 -0700

    cmd/ld: when linking externally, only generate dwarf info for ELF

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

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

https://github.com/golang/go/commit/2a1ca145cf0489160ca284e08eeca4673563c007

元コミット内容

cmd/ld: when linking externally, only generate dwarf info for ELF

(外部リンカを使用する場合、ELF形式に対してのみ DWARF 情報を生成する)

変更の背景

Go言語のビルドプロセスでは、Go独自のリンカを使用することも、C/C++コードなどと連携するためにシステムにインストールされている外部のCリンカ(例: gcc)を使用することも可能です。このコミットが行われた背景には、外部リンカを使用する際に、ELF形式以外の実行可能ファイルフォーマット(例えばWindowsのPE形式やmacOSのMach-O形式など)に対してDWARFデバッグ情報を生成することが、以下のいずれかの問題を引き起こしていた可能性があります。

  1. 不要なデバッグ情報の生成: ELF以外のフォーマットでは、Goが生成するDWARF情報が適切に利用されない、または全く不要である場合。
  2. 互換性の問題: 外部リンカやターゲットOSのツールチェインが、Goが生成するDWARF情報を正しく解釈できない、または競合を引き起こす場合。
  3. ビルド時間の増加/バイナリサイズの肥大化: 不要なデバッグ情報を生成することで、ビルド時間が長くなったり、最終的なバイナリサイズが不必要に大きくなったりする問題。

この変更は、これらの問題を解決し、リンカの挙動をより効率的かつ堅牢にするために導入されました。

前提知識の解説

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

  • Goリンカ (cmd/ld): Go言語のコンパイラツールチェインの一部であり、Goのソースコードから生成されたオブジェクトファイルや、C/C++など他の言語のオブジェクトファイルを結合して、最終的な実行可能バイナリを生成する役割を担います。Goプログラムのビルドにおける最終段階であり、非常に重要なコンポーネントです。

  • DWARF (Debugging With Attributed Record Formats): プログラムのデバッグ情報を格納するための標準的なフォーマットです。ソースコードの行番号、変数名、型情報、関数名、スタックフレームの構造など、デバッガがソースレベルでプログラムをステップ実行したり、変数の値を検査したりするために必要なあらゆる情報が含まれています。DWARF情報は通常、実行可能ファイル内の専用のセクションに埋め込まれるか、別のファイルとして提供されます。

  • ELF (Executable and Linkable Format): Unix系オペレーティングシステム(Linux、BSD、Solarisなど)で広く使用されている、実行可能ファイル、オブジェクトファイル、共有ライブラリ、コアダンプなどの標準ファイルフォーマットです。ELFは、プログラムのコード、データ、デバッグ情報などをどのように配置するかを定義しています。

  • 外部リンカ (External Linker): Goのビルドシステムは、GoコードのリンクにGo独自のリンカを使用するのが一般的ですが、Cgo(GoとCの相互運用機能)を使用する場合や、特定のビルドフラグ(例: -ldflags="-linkmode=external")が指定された場合などには、システムにインストールされている外部のCリンカ(通常は gccclang)を呼び出して最終的なリンク処理を行わせることがあります。これは、Go以外の言語で書かれたライブラリとのリンクや、特定のシステムライブラリへの依存がある場合に必要となります。

技術的詳細

このコミットは、src/cmd/ld/dwarf.c ファイル内の dwarfemitdebugsections 関数に修正を加えています。

dwarfemitdebugsections 関数は、Goリンカが実行可能ファイルにDWARFデバッグ情報を埋め込む処理を担当しています。この関数は、デバッグ情報が有効になっている場合に、ソースコードとバイナリの対応付け、変数や関数の情報などを記述したDWARFセクションを生成します。

追加されたコードは以下の条件分岐です。

if(linkmode == LinkExternal && !iself)
	return;

この条件式は、以下の2つの条件が同時に真である場合に dwarfemitdebugsections 関数の残りの処理(DWARFデバッグ情報の生成)をスキップし、関数を即座に終了させます。

  1. linkmode == LinkExternal: 現在のリンクモードが「外部リンカを使用する」モードであること。これは、Goリンカが最終的なバイナリ生成のために gcc などの外部ツールに依存している状態を指します。
  2. !iself: 生成される実行可能ファイルのフォーマットがELF形式ではないこと。iself は、ターゲットプラットフォームがELF形式のバイナリを生成するかどうかを示す内部フラグです。したがって !iself は、ターゲットがWindows (PE) や macOS (Mach-O) など、ELF以外のフォーマットであることを意味します。

この変更により、Goリンカは、外部リンカを使用し、かつターゲットがELF形式ではない場合に、DWARFデバッグ情報を生成しないように制御されます。これは、これらの特定の組み合わせにおいて、Goが生成するDWARF情報が不要であるか、または外部リンカやターゲットOSのデバッガとの間で互換性の問題を引き起こす可能性があるためです。結果として、リンカの処理が最適化され、不必要なデバッグ情報の生成が抑制されます。

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

変更は src/cmd/ld/dwarf.c ファイルの dwarfemitdebugsections 関数内で行われました。具体的には、既存の if(debug['w']) チェックの直後に以下の3行が追加されています。

--- a/src/cmd/ld/dwarf.c
+++ b/src/cmd/ld/dwarf.c
@@ -2262,6 +2262,9 @@ dwarfemitdebugsections(void)
 	if(debug['w'])  // disable dwarf
 		return;

+	if(linkmode == LinkExternal && !iself)
+		return;
+
 	// For diagnostic messages.
 	newattr(&dwtypes, DW_AT_name, DW_CLS_STRING, strlen("dwtypes"), "dwtypes");

コアとなるコードの解説

追加されたコードブロックは、GoリンカがDWARFデバッグ情報を生成する前に、特定の条件をチェックするためのガード節として機能します。

  • if(linkmode == LinkExternal && !iself): この行は、論理AND (&&) 演算子で結合された2つの条件を評価します。

    • linkmode == LinkExternal: これは、Goリンカが現在、Go独自のリンカではなく、システムにインストールされている外部のCリンカ(例: gcc)を使用して最終的な実行可能ファイルを生成しているかどうかをチェックします。Goのビルドシステムでは、go build -ldflags="-linkmode=external" のように指定することで外部リンカの使用を強制できます。
    • !iself: これは、生成される実行可能ファイルのフォーマットがELF形式ではないかどうかをチェックします。iself は、GoリンカがターゲットとするプラットフォームがELF形式のバイナリを生成するかどうかを示す内部フラグです。したがって、!iself は、ターゲットがWindows (PE形式) や macOS (Mach-O形式) など、ELF以外のバイナリフォーマットであることを意味します。
  • return;: 上記の2つの条件(外部リンカを使用しており、かつターゲットがELF形式ではない)が両方とも真である場合、この return; ステートメントが実行されます。これにより、dwarfemitdebugsections 関数の残りの処理(DWARFデバッグ情報の生成ロジック)がスキップされ、関数が即座に終了します。

この変更の意図は、外部リンカを使用し、かつターゲットがELF形式ではない場合に、GoリンカがDWARFデバッグ情報を生成しないようにすることです。これは、これらの特定の組み合わせにおいて、Goが生成するDWARF情報が不要であるか、または外部リンカやターゲットOSのデバッガとの間で互換性の問題を引き起こす可能性があるためです。この最適化により、リンカの効率が向上し、不必要なデバッグ情報の生成が抑制されます。

関連リンク

参考にした情報源リンク

  • Go言語のソースコード (特に src/cmd/ld ディレクトリ): https://github.com/golang/go
  • Goのリンカに関する議論やドキュメント (GoのIssueトラッカーやメーリングリストなど)
  • DWARFおよびELFフォーマットに関する一般的な技術文書
  • Goのビルドフラグに関するドキュメント (go help build など)