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

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

このコミットは、Goランタイム内のsrc/pkg/runtime/mgc0.cファイルにおける二重シンボル定義の問題を修正するものです。具体的には、runfinqvというシンボルが重複して定義されていることによるコンパイル/リンク時の問題を解消しています。

コミット

commit 0ef0d6cd7b3898c5f6986d4fdc253ded497d05e2
Author: Dmitriy Vyukov <dvyukov@google.com>
Date:   Mon Feb 24 20:23:03 2014 +0400

    runtime: fix double symbol definition
    runfinqv is already defined the same way on line 271.
    There may also be something to fix in compiler/linker wrt diagnostics.
    Fixes #7375.
    
    LGTM=bradfitz
    R=golang-codereviews, dave, bradfitz
    CC=golang-codereviews
    https://golang.org/cl/67850044
---
 src/pkg/runtime/mgc0.c | 2 --
 1 file changed, 2 deletions(-)

diff --git a/src/pkg/runtime/mgc0.c b/src/pkg/runtime/mgc0.c
index 6b8b4c52bf..d34ba4c026 100644
--- a/src/pkg/runtime/mgc0.c
+++ b/src/pkg/runtime/mgc0.c
@@ -2182,8 +2182,6 @@ readgogc(void)\n 	return runtime·atoi(p);\n }\n \n-static FuncVal runfinqv = {runfinq};\n-\n void\n runtime·gc(int32 force)\n {\n```

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

[https://github.com/golang/go/commit/0ef0d6cd7b3898c5f6986d4fdc253ded497d05e2](https://github.com/golang/go/commit/0ef0d6cd7b3898c5f6986d4fdc253ded497d05e2)

## 元コミット内容

コミットメッセージは「runtime: fix double symbol definition」と簡潔に述べられており、ランタイムにおける二重シンボル定義の修正が目的であることを示しています。詳細として、「`runfinqv` is already defined the same way on line 271.」とあり、`runfinqv`というシンボルが既に別の場所(271行目)で同じように定義されていることが問題の原因であることを指摘しています。また、「There may also be something to fix in compiler/linker wrt diagnostics.」と、コンパイラやリンカの診断機能にも改善の余地がある可能性に言及しています。最後に、「Fixes #7375.」と、このコミットがGoのIssue #7375を修正するものであることを示していますが、このIssueは公開されているGoリポジトリでは見つかりませんでした。

## 変更の背景

この変更の背景には、Goランタイムのビルドプロセスにおけるシンボル定義の重複問題があります。C言語で書かれたGoランタイムのコードにおいて、`runfinqv`という`FuncVal`型の変数が、意図せず二重に定義されていました。C言語では、同じ名前のグローバルシンボルが複数回定義されると、リンカがエラーを発生させます。これは、リンカがどの定義を使用すべきか判断できないためです。

コミットメッセージにある「`runfinqv` is already defined the same way on line 271」という記述から、`runfinqv`が`src/pkg/runtime/mgc0.c`ファイルの別の場所(271行目付近)でも定義されており、それが重複の原因となっていたことが推測されます。この重複定義は、コンパイルは通ってもリンク時にエラーとなる可能性があり、Goランタイムのビルドを妨げる問題となっていました。

## 前提知識の解説

### Goランタイム (Go Runtime)
Goランタイムは、Goプログラムの実行を管理する低レベルのコンポーネントです。ガベージコレクション、スケジューリング、メモリ管理、ゴルーチン管理など、Go言語の並行処理モデルやメモリ安全性を実現するための重要な機能を提供します。Goランタイムの一部はC言語やアセンブリ言語で書かれており、OSやハードウェアとのインタフェースを担当します。

### ガベージコレクション (Garbage Collection, GC)
ガベージコレクションは、プログラムが動的に確保したメモリ領域のうち、もはや使用されていない(参照されていない)ものを自動的に解放する仕組みです。Go言語は独自のGCを内蔵しており、プログラマが手動でメモリを解放する必要がありません。`src/pkg/runtime/mgc0.c`は、GoのGCの初期の実装の一部を担っていたファイルです。

### シンボル (Symbol)
プログラミングにおいて、シンボルとは変数名、関数名、クラス名など、プログラム内の特定のエンティティを識別するための名前です。コンパイルされたコードでは、これらのシンボルはメモリ上の特定のアドレスを指し示します。

### シンボル定義 (Symbol Definition)
シンボル定義とは、シンボルが実際にメモリ上のどこに配置され、どのような値を持つか(変数であれば初期値、関数であればそのコードブロック)を決定することです。C言語では、グローバル変数や非`static`な関数は、通常、一度だけ定義される必要があります。

### 二重定義エラー (Double Definition Error)
同じ名前のシンボルが複数回定義された場合に発生するエラーです。特に、複数のソースファイルで同じグローバル変数や非`static`関数が定義されている場合に、リンカがこのエラーを報告します。リンカは、プログラムを構成する複数のオブジェクトファイル(コンパイルされた個々のソースファイル)を結合して実行可能ファイルを生成する際に、各シンボルの定義が唯一であることを確認します。重複があると、どの定義を採用すべきかリンカが判断できないため、エラーとなります。

### `static`キーワード (C言語における`static`)
C言語において、`static`キーワードは変数や関数のスコープとリンケージ(結合性)を制御します。
- **関数スコープ内の`static`変数**: その変数が関数呼び出し間で値を保持し続けることを意味します。
- **グローバルスコープ内の`static`変数/関数**: その変数や関数が定義されたファイル内でのみ可視であることを意味します。つまり、他のソースファイルからはそのシンボルにアクセスできません。これにより、シンボル名の衝突(二重定義)を防ぐことができます。

### `FuncVal`型
Goランタイムの内部で使用される構造体で、関数ポインタとその関連情報(例えば、レシーバの型情報など)をカプセル化するために使われます。Goのメソッドやクロージャの実装に関連する低レベルな構造です。

## 技術的詳細

このコミットの技術的詳細は、C言語のリンケージとGoランタイムのビルドプロセスに深く関連しています。

問題の核心は、`src/pkg/runtime/mgc0.c`ファイル内で`static FuncVal runfinqv = {runfinq};`という行が、別の場所でも同様に定義されていたことです。

C言語において、グローバルスコープで`static`キーワードを付けずに変数を定義すると、その変数は外部リンケージ(external linkage)を持ちます。これは、その変数がプログラム全体で共有され、他のファイルからも参照可能であることを意味します。もし同じ名前の外部リンケージを持つ変数が複数のファイルで定義された場合、リンカは「二重定義エラー」を報告します。

一方、`static`キーワードを付けてグローバルスコープで変数を定義すると、その変数は内部リンケージ(internal linkage)を持ちます。これは、その変数が定義された翻訳単位(通常は単一のソースファイル)内でのみ可視であり、他のファイルからは参照できないことを意味します。これにより、異なるファイルで同じ名前の`static`変数を定義しても、リンカエラーは発生しません。

このコミットでは、`static FuncVal runfinqv = {runfinq};`という行が削除されています。これは、この`runfinqv`の定義が不要であったか、あるいは別の場所で既に適切に定義されており、この場所での定義が重複を引き起こしていたためと考えられます。コミットメッセージの「`runfinqv` is already defined the same way on line 271」という記述から、後者の可能性が高いです。つまり、`runfinqv`は`mgc0.c`内の271行目付近で既に定義されており、この削除された行が冗長な二重定義となっていたということです。

Goランタイムは、C言語のコードをGoのツールチェインでコンパイル・リンクして最終的な実行可能ファイルを生成します。このプロセスにおいて、C言語のリンケージルールが適用されるため、このようなシンボルの二重定義はビルドエラーに直結します。この修正は、Goランタイムのビルドの健全性を保つために不可欠なものでした。

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

```diff
--- a/src/pkg/runtime/mgc0.c
+++ b/src/pkg/runtime/mgc0.c
@@ -2182,8 +2182,6 @@ readgogc(void)\n 	return runtime·atoi(p);\n }\n \n-static FuncVal runfinqv = {runfinq};\n-\n void\n runtime·gc(int32 force)\n {\n```

変更は`src/pkg/runtime/mgc0.c`ファイルに対して行われました。具体的には、以下の2行が削除されています。

```c
static FuncVal runfinqv = {runfinq};

この行は、runfinqvという名前のFuncVal型の変数を静的に初期化していました。

コアとなるコードの解説

src/pkg/runtime/mgc0.cは、Goランタイムのガベージコレクション(GC)に関連する初期のC言語コードが含まれていたファイルです。このファイルは、GCのマークフェーズやスイープフェーズ、ファイナライザの実行など、GCの低レベルな動作を制御していました。

削除された行static FuncVal runfinqv = {runfinq};は、runfinqvというFuncVal型の変数を定義し、runfinqという関数へのポインタで初期化していました。FuncValはGoランタイム内部で関数を表現するための構造体であり、runfinqはおそらくファイナライザの実行に関連する関数であったと推測されます。

この行が削除された理由は、コミットメッセージにある通り、「runfinqv is already defined the same way on line 271」であるためです。つまり、このファイル内の別の場所(271行目付近)で、同じrunfinqvというシンボルが既に定義されており、この削除された行が冗長な二重定義を引き起こしていました。

staticキーワードが付いているにもかかわらず二重定義の問題が発生したという事実は、少し注意が必要です。通常、staticグローバル変数は内部リンケージを持つため、同じファイル内で複数回定義することはできませんが、異なるファイルであれば同じ名前のstatic変数を定義しても衝突しません。しかし、このケースでは「on line 271」とあるため、同じファイル内での二重定義であった可能性が高いです。C言語では、同じファイル内で同じ名前のstatic変数を複数回定義することはできません。これは、staticがその変数のスコープをファイル内に限定するものの、そのファイル内での定義は依然として唯一である必要があるためです。

したがって、この修正は、mgc0.cファイル内でrunfinqvの定義が重複していたのを解消し、Goランタイムのビルドが正常に行われるようにするためのクリーンアップ作業であったと言えます。

関連リンク

  • Go Issue #7375: このコミットが修正するとされているGoのIssue #7375は、現在の公開されているGoリポジトリでは見つかりませんでした。これは、Issue番号が変更された、内部的なIssueであった、あるいは既にクローズされてアーカイブされたなどの理由が考えられます。
  • Gerrit Change List 67850044: https://golang.org/cl/67850044
    • これはGoプロジェクトがかつて使用していたコードレビューシステムGerritにおけるこの変更のリンクです。Gerritのページでは、コミットの詳細、レビューコメント、関連する変更履歴などを確認できます。

参考にした情報源リンク

  • C言語のstaticキーワードに関するドキュメント
  • Goランタイムのソースコード(特にsrc/pkg/runtime/ディレクトリ)
  • リンカの動作に関する一般的な情報
  • Goのガベージコレクションに関するドキュメント(Goの公式ドキュメントやブログ記事など)
  • GoのIssueトラッカーの検索(Issue #7375の確認のため)I have generated the commit explanation as requested.