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

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

このコミットは、Go言語のランタイムにおけるCgo(C言語との連携機能)のARMアーキテクチャ向けビルドに関する修正です。具体的には、グローバルな検索置換作業中に、大文字の.S拡張子を持つアセンブリファイルが対象から漏れていたために発生したビルドエラーを修正しています。

コミット

commit 83c5d07c0e940b0ff3f9da23920f047c4dd6e6fe
Author: Russ Cox <rsc@golang.org>
Date:   Fri Mar 1 00:30:19 2013 -0500

    runtime/cgo: fix arm build
    
    During my global search and replace I forgot to open *.S (capital).
    
    R=golang-dev
    TBR=golang-dev
    CC=golang-dev
    https://golang.org/cl/7415047

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

https://github.com/golang/go/commit/83c5d07c0e940b0ff3f9da23920f047c4dd6e6fe

元コミット内容

このコミットの目的は、GoランタイムのCgo部分におけるARMアーキテクチャ向けのビルド問題を修正することです。コミットメッセージによると、以前行われたグローバルな検索置換操作において、大文字の.S拡張子を持つアセンブリファイル(src/pkg/runtime/cgo/gcc_arm.S)が処理対象から漏れてしまったことが原因で、ビルドが失敗するようになっていました。このコミットでは、その漏れを修正し、適切な関数名に置換することで、ARMビルドが再び正常に行われるようにしています。

変更の背景

Go言語のランタイムは、様々なアーキテクチャやオペレーティングシステムに対応するために、多くのプラットフォーム固有のコードを含んでいます。Cgoは、GoプログラムからC言語の関数を呼び出すためのメカニズムであり、その実装には低レベルのアセンブリコードが関与することがあります。

このコミットが行われた2013年3月1日という時期は、Go言語がまだ活発に開発され、様々なアーキテクチャへの対応が強化されていた時期にあたります。コミットメッセージにある「global search and replace(グローバルな検索置換)」は、おそらくGoランタイム内の特定のAPIや内部関数の命名規則の変更、あるいはリファクタリングの一環として行われたものと推測されます。

この検索置換作業において、ファイル名のパターンマッチングが不完全であったため、小文字の.s拡張子を持つファイルは適切に処理されたものの、大文字の.S拡張子を持つファイル(特にgcc_arm.S)が見落とされてしまいました。その結果、gcc_arm.Sファイル内の古い関数名が残ってしまい、ビルド時に未定義シンボルエラーなどが発生し、ARMアーキテクチャ向けのビルドが失敗するようになったと考えられます。

このコミットは、この見落としを修正し、GoランタイムのCgo部分がARM環境で正しく動作するようにするためのものです。

前提知識の解説

このコミットを理解するためには、以下の前提知識が必要です。

  1. Goランタイム (Go Runtime): Goプログラムは、Goランタイムと呼ばれる軽量な実行環境上で動作します。ランタイムは、ガベージコレクション、スケジューリング(goroutineの管理)、メモリ管理、Cgoとの連携など、Goプログラムの実行に必要な低レベルな機能を提供します。

  2. Cgo (C Foreign Function Interface): Cgoは、GoプログラムからC言語の関数を呼び出したり、C言語のコードからGoの関数を呼び出したりするためのGo言語の機能です。これにより、既存のCライブラリをGoから利用したり、パフォーマンスが重要な部分をCで記述したりすることが可能になります。Cgoの内部では、GoとCのスタックフレームの切り替えや、スレッドローカルストレージ(TLS)を介したGoランタイムの状態(gm)の保存・復元など、低レベルな処理が行われます。

  3. ARMアーキテクチャ: ARM(Advanced RISC Machine)は、モバイルデバイスや組み込みシステムで広く使用されているRISC(Reduced Instruction Set Computer)ベースのCPUアーキテクチャです。Go言語はARMアーキテクチャもサポートしており、そのためにARM固有のアセンブリコードがランタイムに含まれています。

  4. アセンブリ言語 (.Sファイル): .Sまたは.s拡張子を持つファイルは、アセンブリ言語のソースコードファイルです。Goランタイムのパフォーマンスが重要な部分や、OS/アーキテクチャ固有の低レベルな処理(例: コンテキストスイッチ、システムコール、Cgoのスタック切り替え)は、アセンブリ言語で記述されることがあります。これらのファイルは、Goのツールチェーンによってコンパイルされ、最終的なバイナリに組み込まれます。大文字の.Sは、通常、Cプリプロセッサによって処理されるアセンブリファイルを指すことが多いですが、この文脈では単にファイル拡張子のケースの違いが問題となっています。

  5. Goランタイムのgm: Goランタイムには、g(goroutine)とm(machine/thread)という重要な概念があります。

    • g: Go言語の並行処理の単位であるgoroutineを表す構造体です。各goroutineは独自のスタックを持ちます。
    • m: オペレーティングシステムのスレッド(OSスレッド)を表す構造体です。Goランタイムは、複数のgを少数のm上でスケジューリングして実行します。 Cgo呼び出しが行われる際、Goランタイムは現在のgmの情報を保存し、Cコードの実行中はOSスレッドがCのスタックで動作するように切り替えます。Cコードの実行が完了し、Goコードに戻る際には、保存されたgmの情報を復元する必要があります。
  6. TLS (Thread Local Storage): スレッドローカルストレージ(TLS)は、各スレッドがそれぞれ独立したデータを保持できるメモリ領域です。Cgoの文脈では、Goランタイムは現在のgmのポインタをTLSに保存することがあります。これにより、CコードからGoコードにコールバックする際や、Cgo呼び出しの前後で、正しいgmのコンテキストを復元することが可能になります。

  7. ARMアセンブリ命令 bl: blは"Branch with Link"の略で、ARMアセンブリにおける関数呼び出し命令です。指定されたアドレスにジャンプし、同時に現在のプログラムカウンタ(PC)の次の命令のアドレスをリンクレジスタ(LR)に保存します。これにより、関数呼び出し後に元の場所に戻ることができます。

技術的詳細

このコミットは、src/pkg/runtime/cgo/gcc_arm.Sファイル内の2つのアセンブリ命令の変更に焦点を当てています。

変更前:

bl EXT(cgo_tls_set_gm) // save current g and m into TLS variable

変更後:

bl EXT(x_cgo_save_gm) // save current g and m into TLS variable

変更前:

bl EXT(cgo_tls_get_gm) // set up g and m from TLS

変更後:

bl EXT(x_cgo_load_gm) // set up g and m from TLS

この変更は、cgo_tls_set_gmcgo_tls_get_gmという関数名が、それぞれx_cgo_save_gmx_cgo_load_gmにリネームされたことを示しています。

  • cgo_tls_set_gm -> x_cgo_save_gm: この関数は、現在のgoroutine (g) とOSスレッド (m) の情報をスレッドローカルストレージ(TLS)に保存する役割を担っていました。Cgo呼び出しの直前、GoランタイムのコンテキストをCコードが破壊しないように、この情報が保存されます。新しい名前のx_cgo_save_gmは、その役割をより明確に示しています。x_プレフィックスは、Goランタイムの内部的な、特にクロスコンパイルやCgoのような特殊なコンテキストで使用される関数であることを示唆している可能性があります。

  • cgo_tls_get_gm -> x_cgo_load_gm: この関数は、TLSに保存されたgmの情報を読み込み、Goランタイムのコンテキストを復元する役割を担っていました。Cコードの実行が終わり、Goコードに戻る際に、この関数が呼び出されます。新しい名前のx_cgo_load_gmも、その役割をより明確にしています。

これらの関数は、CgoがGoとCの間でスタックを切り替え、Goランタイムの重要な状態(gm)を維持するために不可欠な低レベルのルーチンです。グローバルな検索置換作業でこれらの関数名が変更されたにもかかわらず、gcc_arm.Sファイルがその対象から漏れたため、古い関数名が残ってしまい、ビルドエラーを引き起こしていました。このコミットは、その不整合を解消するものです。

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

diff --git a/src/pkg/runtime/cgo/gcc_arm.S b/src/pkg/runtime/cgo/gcc_arm.S
index fc6d34cae9..d788d42488 100644
--- a/src/pkg/runtime/cgo/gcc_arm.S
+++ b/src/pkg/runtime/cgo/gcc_arm.S
@@ -24,7 +24,7 @@ EXT(crosscall_arm2):
  	mov r10, r1 // g
  	mov r9, r2 // m
  	mov r3, r0 // save r0, cgo_tls_set_gm will clobber it
-	bl EXT(cgo_tls_set_gm) // save current g and m into TLS variable
+	bl EXT(x_cgo_save_gm) // save current g and m into TLS variable
  	mov lr, pc
  	mov pc, r3
  	pop {r4, r5, r6, r7, r8, r9, r10, r11, ip, pc}
@@ -45,7 +45,7 @@ EXT(crosscall2):
  *  nevertheless.
  */
  	push {r0, r1, r2, r4, r5, r6, r7, r8, r9, r10, r11, ip, lr}
-	bl EXT(cgo_tls_get_gm) // set up g and m from TLS
+	bl EXT(x_cgo_load_gm) // set up g and m from TLS
  	mov lr, pc
  	ldr pc, [sp, #0]
  	pop {r0, r1, r2, r4, r5, r6, r7, r8, r9, r10, r11, ip, pc}

コアとなるコードの解説

この変更は、src/pkg/runtime/cgo/gcc_arm.Sファイル内の2つの異なるアセンブリ関数(crosscall_arm2crosscall2)内で発生しています。これらの関数は、Cgo呼び出しの際にGoとCのコンテキストを切り替えるためのアセンブリルーチンの一部です。

  1. crosscall_arm2関数内:

    • mov r10, r1 // gmov r9, r2 // m: これは、現在のgoroutine (g) とOSスレッド (m) のポインタをレジスタr10r9にそれぞれ移動していることを示しています。
    • mov r3, r0 // save r0, cgo_tls_set_gm will clobber it: レジスタr0の値をr3に一時的に保存しています。これは、次に呼び出す関数cgo_tls_set_gm(またはx_cgo_save_gm)がr0を上書きする可能性があるためです。
    • - bl EXT(cgo_tls_set_gm) // save current g and m into TLS variable
    • + bl EXT(x_cgo_save_gm) // save current g and m into TLS variable ここが変更点です。bl命令は関数呼び出しを行います。EXT()マクロは、外部シンボルへの参照を解決するために使用されます。この行は、現在のgmの情報をTLSに保存するための関数を呼び出しています。古い関数名cgo_tls_set_gmが、新しい関数名x_cgo_save_gmに修正されました。
  2. crosscall2関数内:

    • push {r0, r1, r2, r4, r5, r6, r7, r8, r9, r10, r11, ip, lr}: 複数のレジスタをスタックにプッシュして保存しています。これは、関数呼び出しの規約に従い、呼び出し元が使用するレジスタの値を保護するためです。
    • - bl EXT(cgo_tls_get_gm) // set up g and m from TLS
    • + bl EXT(x_cgo_load_gm) // set up g and m from TLS ここも変更点です。この行は、TLSからgmの情報を読み込み、Goランタイムのコンテキストを復元するための関数を呼び出しています。古い関数名cgo_tls_get_gmが、新しい関数名x_cgo_load_gmに修正されました。
    • mov lr, pcldr pc, [sp, #0]: これは、スタックに保存された戻りアドレスをロードし、関数から戻るための一般的なアセンブリパターンです。
    • pop {r0, r1, r2, r4, r5, r6, r7, r8, r9, r10, r11, ip, pc}: 保存したレジスタをスタックからポップして復元しています。

これらの変更は、Goランタイムの内部的な関数名のリファクタリングに追従するためのものであり、CgoがARMアーキテクチャ上で正しく動作するために不可欠な修正です。アセンブリコードレベルでの関数名の不一致は、リンカエラーや実行時エラーを引き起こす可能性があります。

関連リンク

参考にした情報源リンク