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

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

このコミットは、Go言語のリンカーであるcmd/ldcmd/8lにおいて、OpenBSD上でのビルド問題を修正するものです。具体的には、OpenBSD環境ではスレッドローカルストレージ(TLS)セクションを生成しないように変更することで、ビルドが正常に完了するようにします。

コミット

commit 8d4f381f5cead4ad4e2009173b9c42879a25eed2
Author: Ian Lance Taylor <iant@golang.org>
Date:   Wed Mar 27 15:00:11 2013 -0700

    cmd/ld, cmd/8l: Fix OpenBSD build.
    
    Don't generate TLS sections on OpenBSD.
    
    R=golang-dev, r
    CC=golang-dev
    https://golang.org/cl/8059043

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

https://github.com/golang/go/commit/8d4f381f5cead4ad4e2009173b9c42879a25eed2

元コミット内容

cmd/ld, cmd/8l: Fix OpenBSD build. Don't generate TLS sections on OpenBSD.

変更の背景

このコミットの背景には、Go言語のコンパイラおよびリンカーがOpenBSD上で実行ファイルをビルドする際に発生していた問題があります。Goは通常、スレッドローカルストレージ(TLS)を利用して、各スレッドが独立したデータを持つことを可能にします。これは、マルチスレッドプログラミングにおいて非常に重要な機能です。

しかし、OpenBSDのような特定のオペレーティングシステムでは、TLSの実装や、リンカーがTLSセクションを扱う方法に違いがある場合があります。Goのリンカーが、OpenBSDのリンカーが期待しない形式でTLSセクションを生成しようとすると、ビルドエラーや実行時エラーが発生する可能性があります。

このコミットは、OpenBSD環境でのビルドの安定性を確保するために、GoのリンカーがOpenBSDをターゲットとする場合にTLSセクションの生成を抑制するという、プラットフォーム固有の調整を行うものです。これにより、OpenBSDユーザーがGoプログラムを問題なくビルドできるようになります。

前提知識の解説

スレッドローカルストレージ (TLS: Thread Local Storage)

TLSは、マルチスレッド環境において、各スレッドがそれぞれ独立したデータを持つためのメカニズムです。通常、グローバル変数や静的変数はプロセス内のすべてのスレッドで共有されますが、TLSを使用すると、同じ変数名であっても各スレッドが独自のコピーを持つことができます。これにより、スレッド間のデータの競合を防ぎ、スレッドセーフなプログラミングを容易にします。TLSは、スレッドID、エラーコード、スレッド固有のコンテキスト情報などを格納するためによく使用されます。

Go言語のリンカー (cmd/ld, cmd/8l)

Go言語のビルドプロセスにおいて、リンカーはコンパイルされたオブジェクトファイル(.oファイル)を結合し、実行可能なバイナリを生成する役割を担います。

  • cmd/ld: Go言語の汎用リンカーです。様々なアーキテクチャやOSに対応しています。
  • cmd/8l: Go言語のリンカーの一つで、特に386(x86 32-bit)アーキテクチャ向けのリンカーです。Goのツールチェーンは、ターゲットアーキテクチャに応じて適切なリンカーを選択します。

これらのリンカーは、Goのランタイムや標準ライブラリ、ユーザーが記述したコードを結合し、最終的な実行ファイルを生成します。この過程で、TLSセクションのような特殊なセクションも適切に配置する必要があります。

ELF (Executable and Linkable Format)

ELFは、Unix系オペレーティングシステム(Linux, BSD, Solarisなど)で広く使用されている、実行可能ファイル、オブジェクトファイル、共有ライブラリの標準ファイル形式です。ELFファイルは、プログラムコード、データ、シンボルテーブル、リロケーション情報、デバッグ情報など、実行可能プログラムを構成する様々なセクションを含んでいます。TLSセクションもELF形式の一部として定義され、リンカーによって適切に処理されます。

外部リンキング (LinkExternal)

Go言語のビルドでは、通常、Go独自の内部リンカーを使用します。しかし、C言語で書かれたライブラリ(Cgoを使用する場合など)をリンクする必要がある場合や、特定のシステムリンカーの機能を利用したい場合には、「外部リンキング」を使用することがあります。外部リンキングでは、Goのツールチェーンが生成したオブジェクトファイルを、システムのCリンカー(例えば、GCCが使用するldコマンド)に渡して最終的な実行ファイルを生成させます。このモードでは、Goのリンカーはシステムリンカーが理解できる形式で中間ファイルを生成する必要があります。

HEADTYPE

HEADTYPEは、Goのビルドシステム内で使用される内部的な変数で、ターゲットとなるオペレーティングシステムの種類を識別するために使われます。例えば、HopenbsdはOpenBSDを、HlinuxはLinuxを、HdarwinはmacOSをそれぞれ指します。リンカーは、このHEADTYPEの値に基づいて、ターゲットOSに特有の処理や最適化を行います。

STLSBSS

STLSBSSは、ELFファイルにおけるシンボルタイプの一つで、スレッドローカルストレージのBSS(Block Started by Symbol)セクションに属するシンボルを示します。BSSセクションは、初期化されていないグローバル変数や静的変数を格納するために使用され、実行ファイル内では領域のみが確保され、実際のデータは実行時にゼロ初期化されます。TLS BSSは、スレッドごとに初期化されていないTLS変数を格納する領域を指します。

技術的詳細

このコミットの技術的詳細な変更は、GoのリンカーがTLSセクションを生成する条件に、HEADTYPE != Hopenbsdという条件を追加した点に集約されます。

Goのリンカーは、ELF形式の実行ファイルを生成する際に、スレッドローカルストレージ(TLS)に関連するセクション(例えば、.tdata.tbss)を配置します。これらのセクションは、スレッド固有のデータを効率的に管理するために必要です。

しかし、OpenBSDのリンカーやランタイム環境は、Goのリンカーが生成する特定のTLSセクションの構造や、それらのセクションがどのように扱われるかについて、他のOS(例えばLinux)とは異なる期待を持っている可能性があります。もしGoのリンカーがOpenBSDの期待に合わないTLSセクションを生成すると、以下のような問題が発生する可能性があります。

  1. リンカーエラー: システムのリンカーがGoが生成したTLSセクションを認識できない、または不正な形式と判断し、リンク処理が失敗する。
  2. 実行時エラー: プログラムが起動しても、TLSデータへのアクセスが正しく行われず、セグメンテーション違反や未定義の動作を引き起こす。
  3. パフォーマンス問題: 不適切なTLSセクションの生成が、実行時のオーバーヘッドを増加させる。

このコミットは、これらの問題を回避するために、OpenBSDをターゲットとするビルド(HEADTYPE == Hopenbsdの場合)では、TLSセクションの生成を完全にスキップするようにリンカーのロジックを変更しました。これにより、OpenBSDのリンカーがTLSセクションの存在を前提としない、またはGoが生成するTLSセクションの形式をサポートしない場合でも、Goプログラムが正常にビルドされ、実行できるようになります。

この変更は、主に外部リンキング(linkmode == LinkExternal)を使用する場合に影響します。外部リンキングでは、Goのリンカーが生成した中間ファイルがシステムのリンカーに渡されるため、システムリンカーとの互換性が特に重要になります。

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

src/cmd/8l/span.c

--- a/src/cmd/8l/span.c
+++ b/src/cmd/8l/span.c
@@ -689,7 +689,7 @@ putrelv:
 	\tr = addrel(cursym);\
 	\t*r = rel;\
 	\tr->off = curp->pc + andptr - and;\
-\t} else if(iself && linkmode == LinkExternal && istls(a)) {\
+\t} else if(iself && linkmode == LinkExternal && istls(a) && HEADTYPE != Hopenbsd) {\
 	\tReloc *r;\
 	\tSym *s;\
 

src/cmd/ld/data.c

--- a/src/cmd/ld/data.c
+++ b/src/cmd/ld/data.c
@@ -1206,7 +1206,7 @@ dodata(void)\
 	sect->len = datsize - sect->vaddr;\
 	lookup("end", 0)->sect = sect;\
 	\n
-\tif(iself && linkmode == LinkExternal && s != nil && s->type == STLSBSS) {\
+\tif(iself && linkmode == LinkExternal && s != nil && s->type == STLSBSS && HEADTYPE != Hopenbsd) {\
 	\tsect = addsection(&segdata, ".tbss", 06);\
 	\tsect->align = PtrSize;\
 	\tsect->vaddr = 0;\

src/cmd/ld/elf.c

--- a/src/cmd/ld/elf.c
+++ b/src/cmd/ld/elf.c
@@ -887,7 +887,7 @@ doelf(void)\
 	addstring(shstrtab, ".data");\
 	addstring(shstrtab, ".bss");\
 	addstring(shstrtab, ".noptrbss");\
-\tif(linkmode == LinkExternal)\
+\tif(linkmode == LinkExternal && HEADTYPE != Hopenbsd)\
 	\taddstring(shstrtab, ".tbss");\
 	\tif(HEADTYPE == Hnetbsd)\
 	\taddstring(shstrtab, ".note.netbsd.ident");\

コアとなるコードの解説

上記の3つのファイルにおける変更は、すべて既存の条件式に&& HEADTYPE != Hopenbsdという条件を追加するものです。

  1. src/cmd/8l/span.c:

    • このファイルは、リンカーがシンボルやリロケーション(再配置)情報を処理する部分に関連しています。
    • 変更箇所は、iself && linkmode == LinkExternal && istls(a)という条件に&& HEADTYPE != Hopenbsdが追加されています。
    • これは、ELF形式で外部リンキングを使用し、かつシンボルがTLSに関連する場合に特定の処理を行うロジックです。この変更により、OpenBSDをターゲットとするビルドでは、このTLS関連の処理がスキップされるようになります。具体的には、TLS関連のリロケーションの追加を抑制していると考えられます。
  2. src/cmd/ld/data.c:

    • このファイルは、リンカーがデータセクションを処理する部分に関連しています。
    • 変更箇所は、iself && linkmode == LinkExternal && s != nil && s->type == STLSBSSという条件に&& HEADTYPE != Hopenbsdが追加されています。
    • これは、ELF形式で外部リンキングを使用し、かつシンボルがSTLSBSS(TLSのBSSセクション)タイプである場合に、.tbssセクション(TLSのBSSセクション)を追加するロジックです。この変更により、OpenBSDをターゲットとするビルドでは、.tbssセクションの追加が抑制されます。
  3. src/cmd/ld/elf.c:

    • このファイルは、リンカーがELFファイルの構造を構築する部分に関連しています。
    • 変更箇所は、if(linkmode == LinkExternal)という条件に&& HEADTYPE != Hopenbsdが追加されています。
    • これは、外部リンキングを使用する場合に、ELFファイルのセクションヘッダ文字列テーブルに.tbss(TLSのBSSセクション)という文字列を追加するロジックです。この文字列は、リンカーがセクションを識別するために使用されます。この変更により、OpenBSDをターゲットとするビルドでは、.tbssセクションの文字列が追加されなくなり、結果として.tbssセクション自体がELFファイルに存在しないことを示唆します。

これらの変更は一貫して、OpenBSDをターゲットとするGoのビルドにおいて、TLS関連のセクション(特に.tbss)の生成と、それに関連するリンカーの処理を無効にすることで、OpenBSDのリンカーとの互換性問題を解決しています。

関連リンク

参考にした情報源リンク

  • ELF (Executable and Linkable Format) の仕様に関する一般的な情報
  • スレッドローカルストレージ (TLS) に関する一般的な情報
  • Go言語のリンカーの動作に関する一般的な情報 (Goのソースコードやドキュメント)
  • OpenBSDのTLS実装に関する情報 (必要に応じて検索)
  • Go言語のHEADTYPEに関する情報 (Goのソースコードやドキュメント)
  • Go言語の外部リンキングに関する情報 (Goのドキュメント)
  • Go言語のcmd/ldおよびcmd/8lのソースコード
  • Go言語のSTLSBSSシンボルタイプに関する情報 (Goのソースコード)
  • Go言語のgolang.org/clの仕組みに関する情報# [インデックス 15974] ファイルの概要

このコミットは、Go言語のリンカーであるcmd/ldcmd/8lにおいて、OpenBSD上でのビルド問題を修正するものです。具体的には、OpenBSD環境ではスレッドローカルストレージ(TLS)セクションを生成しないように変更することで、ビルドが正常に完了するようにします。

コミット

commit 8d4f381f5cead4ad4e2009173b9c42879a25eed2
Author: Ian Lance Taylor <iant@golang.org>
Date:   Wed Mar 27 15:00:11 2013 -0700

    cmd/ld, cmd/8l: Fix OpenBSD build.
    
    Don't generate TLS sections on OpenBSD.
    
    R=golang-dev, r
    CC=golang-dev
    https://golang.org/cl/8059043

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

https://github.com/golang/go/commit/8d4f381f5cead4ad4e2009173b9c42879a25eed2

元コミット内容

cmd/ld, cmd/8l: Fix OpenBSD build. Don't generate TLS sections on OpenBSD.

変更の背景

このコミットの背景には、Go言語のコンパイラおよびリンカーがOpenBSD上で実行ファイルをビルドする際に発生していた問題があります。Goは通常、スレッドローカルストレージ(TLS)を利用して、各スレッドが独立したデータを持つことを可能にします。これは、マルチスレッドプログラミングにおいて非常に重要な機能です。

しかし、OpenBSDのような特定のオペレーティングシステムでは、TLSの実装や、リンカーがTLSセクションを扱う方法に違いがある場合があります。Goのリンカーが、OpenBSDのリンカーが期待しない形式でTLSセクションを生成しようとすると、ビルドエラーや実行時エラーが発生する可能性があります。

このコミットは、OpenBSD環境でのビルドの安定性を確保するために、GoのリンカーがOpenBSDをターゲットとする場合にTLSセクションの生成を抑制するという、プラットフォーム固有の調整を行うものです。これにより、OpenBSDユーザーがGoプログラムを問題なくビルドできるようになります。

前提知識の解説

スレッドローカルストレージ (TLS: Thread Local Storage)

TLSは、マルチスレッド環境において、各スレッドがそれぞれ独立したデータを持つためのメカニズムです。通常、グローバル変数や静的変数はプロセス内のすべてのスレッドで共有されますが、TLSを使用すると、同じ変数名であっても各スレッドが独自のコピーを持つことができます。これにより、スレッド間のデータの競合を防ぎ、スレッドセーフなプログラミングを容易にします。TLSは、スレッドID、エラーコード、スレッド固有のコンテキスト情報などを格納するためによく使用されます。

Go言語のリンカー (cmd/ld, cmd/8l)

Go言語のビルドプロセスにおいて、リンカーはコンパイルされたオブジェクトファイル(.oファイル)を結合し、実行可能なバイナリを生成する役割を担います。

  • cmd/ld: Go言語の汎用リンカーです。様々なアーキテクチャやOSに対応しています。
  • cmd/8l: Go言語のリンカーの一つで、特に386(x86 32-bit)アーキテクチャ向けのリンカーです。Goのツールチェーンは、ターゲットアーキテクチャに応じて適切なリンカーを選択します。

これらのリンカーは、Goのランタイムや標準ライブラリ、ユーザーが記述したコードを結合し、最終的な実行ファイルを生成します。この過程で、TLSセクションのような特殊なセクションも適切に配置する必要があります。

ELF (Executable and Linkable Format)

ELFは、Unix系オペレーティングシステム(Linux, BSD, Solarisなど)で広く使用されている、実行可能ファイル、オブジェクトファイル、共有ライブラリの標準ファイル形式です。ELFファイルは、プログラムコード、データ、シンボルテーブル、リロケーション情報、デバッグ情報など、実行可能プログラムを構成する様々なセクションを含んでいます。TLSセクションもELF形式の一部として定義され、リンカーによって適切に処理されます。

外部リンキング (LinkExternal)

Go言語のビルドでは、通常、Go独自の内部リンカーを使用します。しかし、C言語で書かれたライブラリ(Cgoを使用する場合など)をリンクする必要がある場合や、特定のシステムリンカーの機能を利用したい場合には、「外部リンキング」を使用することがあります。外部リンキングでは、Goのツールチェーンが生成したオブジェクトファイルを、システムのCリンカー(例えば、GCCが使用するldコマンド)に渡して最終的な実行ファイルを生成させます。このモードでは、Goのリンカーはシステムリンカーが理解できる形式で中間ファイルを生成する必要があります。

HEADTYPE

HEADTYPEは、Goのビルドシステム内で使用される内部的な変数で、ターゲットとなるオペレーティングシステムの種類を識別するために使われます。例えば、HopenbsdはOpenBSDを、HlinuxはLinuxを、HdarwinはmacOSをそれぞれ指します。リンカーは、このHEADTYPEの値に基づいて、ターゲットOSに特有の処理や最適化を行います。

STLSBSS

STLSBSSは、ELFファイルにおけるシンボルタイプの一つで、スレッドローカルストレージのBSS(Block Started by Symbol)セクションに属するシンボルを示します。BSSセクションは、初期化されていないグローバル変数や静的変数を格納するために使用され、実行ファイル内では領域のみが確保され、実際のデータは実行時にゼロ初期化されます。TLS BSSは、スレッドごとに初期化されていないTLS変数を格納する領域を指します。

技術的詳細

このコミットの技術的詳細な変更は、GoのリンカーがTLSセクションを生成する条件に、&& HEADTYPE != Hopenbsdという条件を追加した点に集約されます。

Goのリンカーは、ELF形式の実行ファイルを生成する際に、スレッドローカルストレージ(TLS)に関連するセクション(例えば、.tdata.tbss)を配置します。これらのセクションは、スレッド固有のデータを効率的に管理するために必要です。

しかし、OpenBSDのリンカーやランタイム環境は、Goのリンカーが生成する特定のTLSセクションの構造や、それらのセクションがどのように扱われるかについて、他のOS(例えばLinux)とは異なる期待を持っている可能性があります。もしGoのリンカーがOpenBSDの期待に合わないTLSセクションを生成すると、以下のような問題が発生する可能性があります。

  1. リンカーエラー: システムのリンカーがGoが生成したTLSセクションを認識できない、または不正な形式と判断し、リンク処理が失敗する。
  2. 実行時エラー: プログラムが起動しても、TLSデータへのアクセスが正しく行われず、セグメンテーション違反や未定義の動作を引き起こす。
  3. パフォーマンス問題: 不適切なTLSセクションの生成が、実行時のオーバーヘッドを増加させる。

このコミットは、これらの問題を回避するために、OpenBSDをターゲットとするビルド(HEADTYPE == Hopenbsdの場合)では、TLSセクションの生成を完全にスキップするようにリンカーのロジックを変更しました。これにより、OpenBSDのリンカーがTLSセクションの存在を前提としない、またはGoが生成するTLSセクションの形式をサポートしない場合でも、Goプログラムが正常にビルドされ、実行できるようになります。

この変更は、主に外部リンキング(linkmode == LinkExternal)を使用する場合に影響します。外部リンキングでは、Goのリンカーが生成した中間ファイルがシステムのリンカーに渡されるため、システムリンカーとの互換性が特に重要になります。

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

src/cmd/8l/span.c

--- a/src/cmd/8l/span.c
+++ b/src/cmd/8l/span.c
@@ -689,7 +689,7 @@ putrelv:
 	\tr = addrel(cursym);\
 	\t*r = rel;\
 	\tr->off = curp->pc + andptr - and;\
-\t} else if(iself && linkmode == LinkExternal && istls(a)) {\
+\t} else if(iself && linkmode == LinkExternal && istls(a) && HEADTYPE != Hopenbsd) {\
 	\tReloc *r;\
 	\tSym *s;\
 

src/cmd/ld/data.c

--- a/src/cmd/ld/data.c
+++ b/src/cmd/ld/data.c
@@ -1206,7 +1206,7 @@ dodata(void)\
 	sect->len = datsize - sect->vaddr;\
 	lookup("end", 0)->sect = sect;\
 	\n
-\tif(iself && linkmode == LinkExternal && s != nil && s->type == STLSBSS) {\
+\tif(iself && linkmode == LinkExternal && s != nil && s->type == STLSBSS && HEADTYPE != Hopenbsd) {\
 	\tsect = addsection(&segdata, ".tbss", 06);\
 	\tsect->align = PtrSize;\
 	\tsect->vaddr = 0;\

src/cmd/ld/elf.c

--- a/src/cmd/ld/elf.c
+++ b/src/cmd/ld/elf.c
@@ -887,7 +887,7 @@ doelf(void)\
 	addstring(shstrtab, ".data");\
 	addstring(shstrtab, ".bss");\
 	addstring(shstrtab, ".noptrbss");\
-\tif(linkmode == LinkExternal)\
+\tif(linkmode == LinkExternal && HEADTYPE != Hopenbsd)\
 	\taddstring(shstrtab, ".tbss");\
 	\tif(HEADTYPE == Hnetbsd)\
 	\taddstring(shstrtab, ".note.netbsd.ident");\

コアとなるコードの解説

上記の3つのファイルにおける変更は、すべて既存の条件式に&& HEADTYPE != Hopenbsdという条件を追加するものです。

  1. src/cmd/8l/span.c:

    • このファイルは、リンカーがシンボルやリロケーション(再配置)情報を処理する部分に関連しています。
    • 変更箇所は、iself && linkmode == LinkExternal && istls(a)という条件に&& HEADTYPE != Hopenbsdが追加されています。
    • これは、ELF形式で外部リンキングを使用し、かつシンボルがTLSに関連する場合に特定の処理を行うロジックです。この変更により、OpenBSDをターゲットとするビルドでは、このTLS関連の処理がスキップされるようになります。具体的には、TLS関連のリロケーションの追加を抑制していると考えられます。
  2. src/cmd/ld/data.c:

    • このファイルは、リンカーがデータセクションを処理する部分に関連しています。
    • 変更箇所は、iself && linkmode == LinkExternal && s != nil && s->type == STLSBSSという条件に&& HEADTYPE != Hopenbsdが追加されています。
    • これは、ELF形式で外部リンキングを使用し、かつシンボルがSTLSBSS(TLSのBSSセクション)タイプである場合に、.tbssセクション(TLSのBSSセクション)を追加するロジックです。この変更により、OpenBSDをターゲットとするビルドでは、.tbssセクションの追加が抑制されます。
  3. src/cmd/ld/elf.c:

    • このファイルは、リンカーがELFファイルの構造を構築する部分に関連しています。
    • 変更箇所は、if(linkmode == LinkExternal)という条件に&& HEADTYPE != Hopenbsdが追加されています。
    • これは、外部リンキングを使用する場合に、ELFファイルのセクションヘッダ文字列テーブルに.tbss(TLSのBSSセクション)という文字列を追加するロジックです。この文字列は、リンカーがセクションを識別するために使用されます。この変更により、OpenBSDをターゲットとするビルドでは、.tbssセクションの文字列が追加されなくなり、結果として.tbssセクション自体がELFファイルに存在しないことを示唆します。

これらの変更は一貫して、OpenBSDをターゲットとするGoのビルドにおいて、TLS関連のセクション(特に.tbss)の生成と、それに関連するリンカーの処理を無効にすることで、OpenBSDのリンカーとの互換性問題を解決しています。

関連リンク

参考にした情報源リンク

  • ELF (Executable and Linkable Format) の仕様に関する一般的な情報
  • スレッドローカルストレージ (TLS) に関する一般的な情報
  • Go言語のリンカーの動作に関する一般的な情報 (Goのソースコードやドキュメント)
  • OpenBSDのTLS実装に関する情報 (必要に応じて検索)
  • Go言語のHEADTYPEに関する情報 (Goのソースコードやドキュメント)
  • Go言語の外部リンキングに関する情報 (Goのドキュメント)
  • Go言語のcmd/ldおよびcmd/8lのソースコード
  • Go言語のSTLSBSSシンボルタイプに関する情報 (Goのソースコード)
  • Go言語のgolang.org/clの仕組みに関する情報