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

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

このコミットは、Go言語のランタイムにおけるNetBSD/ARMアーキテクチャ向けのビルドに関する修正を扱っています。具体的には、NetBSD上のARM環境でGoプログラムが正しく動作するために必要なレジスタ定義やシステムコール関連のコードが更新されています。

コミット

commit e7537157a53de8683167a512a67218bd3ea44e39
Author: Shenghou Ma <minux.ma@gmail.com>
Date:   Tue Mar 19 02:47:04 2013 +0800

    runtime: fix build for NetBSD/ARM
    
    R=golang-dev, jsing
    CC=golang-dev
    https://golang.org/cl/7597046

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

https://github.com/golang/go/commit/e7537157a53de8683167a512a67218bd3ea44e39

元コミット内容

runtime: fix build for NetBSD/ARM

変更の背景

Go言語はクロスプラットフォーム対応を重視しており、様々なオペレーティングシステムとアーキテクチャの組み合わせで動作するように設計されています。このコミットが行われた2013年当時、Go言語のNetBSD/ARM環境におけるビルドプロセスに問題があったと考えられます。特に、Goランタイムが低レベルなシステムコールやシグナルハンドリングを行う際に、OS固有のレジスタ定義や構造体のアライメント、システムコールの呼び出し規約などが正しく扱われていないことが原因で、ビルドエラーや実行時エラーが発生していた可能性があります。

この修正は、NetBSD上のARMアーキテクチャでGo言語が安定して動作するための基盤を固めることを目的としています。Goのランタイムは、ガベージコレクション、ゴルーチンのスケジューリング、システムコールインターフェースなど、OSと密接に連携する部分が多く、各プラットフォームに合わせた細かな調整が必要です。

前提知識の解説

  • Goランタイム (Go Runtime): Go言語のプログラムを実行するために必要な、低レベルな機能を提供する部分です。ガベージコレクタ、ゴルーチン(軽量スレッド)スケジューラ、メモリ管理、システムコールインターフェースなどが含まれます。Goプログラムは、OSの機能に直接アクセスする代わりに、ランタイムを介してこれらの機能を利用します。
  • NetBSD: オープンソースのUnix系オペレーティングシステムの一つで、非常に高い移植性を持つことで知られています。多くの異なるCPUアーキテクチャとハードウェアプラットフォームで動作します。
  • ARMアーキテクチャ: Advanced RISC Machineの略で、主にモバイルデバイスや組み込みシステムで広く使用されているCPUアーキテクチャです。低消費電力と高性能を両立しています。
  • cgo: Go言語とC言語のコードを相互に呼び出すためのツールです。GoプログラムからCライブラリの関数を呼び出したり、CプログラムからGoの関数を呼び出したりする際に使用されます。OS固有の構造体や定数をGoコードから利用するために、CヘッダファイルをGoの型定義に変換する役割も担います。
  • defs_netbsd_arm.go / defs_netbsd_arm.h: GoランタイムがNetBSD/ARM環境で動作するために必要な、OS固有の定数、構造体、レジスタ定義などをGoとCの間で共有するためのファイルです。cgoツールによって、defs_netbsd_arm.goからdefs_netbsd_arm.hが生成されます。
  • システムコール (System Call): オペレーティングシステムが提供するサービス(ファイルI/O、メモリ管理、プロセス制御など)を、ユーザープログラムが利用するためのインターフェースです。CPUのレジスタに引数を設定し、特定の命令(ARMではSWIなど)を実行することでOSカーネルに処理を依頼します。
  • レジスタ (Register): CPU内部にある高速な記憶領域で、プログラムの実行中にデータやアドレスを一時的に保持するために使われます。ARMアーキテクチャにはR0からR15までの汎用レジスタや、プログラムカウンタ(PC)、スタックポインタ(SP)、リンクレジスタ(LR)、プログラムステータスレジスタ(CPSR)などがあります。
  • McontextT / UcontextT: Unix系システムにおけるコンテキスト(CPUレジスタの状態、シグナルマスク、スタック情報など)を保持するための構造体です。シグナルハンドリングやスレッドのコンテキストスイッチなどで使用されます。

技術的詳細

このコミットの主要な目的は、NetBSD/ARM環境におけるGoランタイムのビルドと実行を修正することです。具体的には、以下の点が改善されています。

  1. defs_netbsd_arm.go の新規追加と cgo の統合:

    • src/pkg/runtime/defs_netbsd_arm.go が新規に作成されました。このファイルは、NetBSD/ARM固有のレジスタ定義(REG_R0からREG_CPSRまで)をGoの定数として定義しています。これらの定数は、C言語のヘッダファイル(<sys/types.h>, <machine/mcontext.h>) からcgoを介してインポートされたCの定数(C._REG_R0など)に対応付けられています。
    • src/pkg/runtime/defs_netbsd.go に、GOARCH=arm go tool cgo -cdefs defs_netbsd.go defs_netbsd_arm.go >defs_netbsd_arm.h という行が追加されました。これにより、Goのビルドプロセスにおいて、NetBSD/ARM向けのヘッダファイルdefs_netbsd_arm.hが正しく生成されるようになります。このヘッダファイルは、GoランタイムがCコードと連携する際に、ARMレジスタのオフセットなどを正しく認識するために不可欠です。
  2. os_netbsd_arm.c におけるレジスタアクセスの修正:

    • src/pkg/runtime/os_netbsd_arm.c 内のruntime·lwp_mcontext_init関数において、McontextT構造体のレジスタへのアクセス方法が変更されました。以前はmc->r15のように直接レジスタ名でアクセスしていましたが、修正後はmc->__gregs[REG_R15]のように、__gregs配列と新しく定義されたREG_Rxx定数を使用してアクセスするようになりました。これは、McontextT構造体におけるレジスタの配置が、特定のOSやアーキテクチャで配列として抽象化されている場合に、より汎用的で堅牢なアクセス方法を提供します。
  3. signal_netbsd_arm.h におけるシグナルレジスタマクロの修正:

    • src/pkg/runtime/signal_netbsd_arm.h 内で定義されているシグナルハンドリング関連のマクロ(SIG_R0, SIG_PCなど)が修正されました。以前はSIG_REGS(ctxt).__gregs[0]のように数値インデックスでレジスタにアクセスしていましたが、修正後はSIG_REGS(ctxt).__gregs[REG_R0]のように、defs_netbsd_arm.goで定義されたREG_Rxx定数を使用するようになりました。これにより、レジスタのインデックスが変更された場合でも、コードの可読性と保守性が向上します。また、SIG_CODE0SIG_CODE1という新しいマクロが追加され、シグナル情報構造体から追加のコード情報を抽出できるようになりました。
  4. sys_netbsd_arm.s におけるシステムコールラッパーの追加:

    • src/pkg/runtime/sys_netbsd_arm.s に、runtime·open, runtime·close, runtime·readといったシステムコールを呼び出すためのアセンブリ言語ラッパーが追加されました。これらのラッパーは、Goランタイムがファイル操作などのOSサービスを利用する際に、適切なシステムコール番号(SWI $0xa00005など)と引数をレジスタに設定し、SWI命令(Software Interrupt)を実行することでカーネルに処理を依頼します。これにより、GoランタイムがNetBSD上で基本的なI/O操作を正しく実行できるようになります。

これらの変更は、NetBSD/ARM環境におけるGoランタイムの低レベルなOSインターフェースを正確に定義し、システムコールやシグナルハンドリングが期待通りに機能するようにするためのものです。

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

このコミットで特に重要な変更は以下のファイルに集中しています。

  • src/pkg/runtime/defs_netbsd.go: defs_netbsd_arm.h生成のためのcgoコマンドが追加されました。
  • src/pkg/runtime/defs_netbsd_arm.go: NetBSD/ARM固有のレジスタ定数(REG_R0など)が新規に定義されました。
  • src/pkg/runtime/defs_netbsd_arm.h: cgoによって生成されるヘッダファイルで、GoとCの間でレジスタ定義を共有します。このコミットでは、このファイルの内容が更新されています。
  • src/pkg/runtime/os_netbsd_arm.c: runtime·lwp_mcontext_init関数内で、McontextT構造体へのレジスタアクセス方法が修正されました。
  • src/pkg/runtime/signal_netbsd_arm.h: シグナルレジスタマクロが、新しいREG_Rxx定数を使用するように変更されました。
  • src/pkg/runtime/sys_netbsd_arm.s: open, close, readシステムコールを呼び出すためのアセンブリ言語ラッパーが追加されました。

コアとなるコードの解説

src/pkg/runtime/defs_netbsd_arm.go (新規追加)

// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build ignore

/*
Input to cgo.

GOARCH=arm go tool cgo -cdefs defs_netbsd.go defs_netbsd_arm.go >defs_netbsd_arm.h
*/

package runtime

/*
#include <sys/types.h>
#include <machine/mcontext.h>
*/
import "C"

const (
	REG_R0   = C._REG_R0
	REG_R1   = C._REG_R1
	// ... (他のレジスタ定義)
	REG_R15  = C._REG_R15
	REG_CPSR = C._REG_CPSR
)

このファイルは、NetBSD/ARM環境におけるCPUレジスタのオフセットやインデックスをGoの定数として定義しています。import "C"とCヘッダのインクルードにより、cgoがC言語の_REG_R0などの定数をGoのコードから利用できるようにします。これにより、GoランタイムがCのコンテキスト構造体(mcontext_tなど)内のレジスタにアクセスする際に、ハードコードされた数値ではなく、意味のある定数を使用できるようになります。これは、コードの可読性と移植性を高める上で非常に重要です。

src/pkg/runtime/os_netbsd_arm.c の変更

// 変更前
// mc->r15 = (uint32)runtime·lwp_tramp;
// mc->r13 = (uint32)stack;
// mc->r0 = (uint32)mp;
// mc->r1 = (uint32)gp;
// mc->r2 = (uint32)fn;

// 変更後
mc->__gregs[REG_R15] = (uint32)runtime·lwp_tramp;
mc->__gregs[REG_R13] = (uint32)stack;
mc->__gregs[REG_R0] = (uint32)mp;
mc->__gregs[REG_R1] = (uint32)gp;
mc->__gregs[REG_R2] = (uint32)fn;

runtime·lwp_mcontext_init関数は、新しい軽量プロセス(LWP: Lightweight Process)のコンテキストを初期化する際に呼び出されます。この関数では、スタックポインタ(R13)、プログラムカウンタ(R15)、および関数の引数となるレジスタ(R0, R1, R2)に値を設定しています。変更前は直接レジスタ名でアクセスしていましたが、変更後は__gregs配列とREG_Rxx定数を使用しています。これは、mcontext_t構造体の内部表現が、レジスタを配列として管理している場合に、より正確でポータブルなアクセス方法を提供します。

src/pkg/runtime/signal_netbsd_arm.h の変更

// 変更前
// #define SIG_R0(info, ctxt) (SIG_REGS(ctxt).__gregs[0])
// ...
// #define SIG_PC(info, ctxt) (SIG_REGS(ctxt).__gregs[15])

// 変更後
#define SIG_R0(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_R0])
// ...
#define SIG_PC(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_R15])
#define SIG_CPSR(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_CPSR])

// 新規追加
#define SIG_CODE0(info, ctxt) ((info)->_code)
#define SIG_CODE1(info, ctxt) (*(uintptr*)&(info)->_reason[0])

このヘッダファイルは、シグナルハンドラ内でCPUレジスタの値を取得するためのマクロを定義しています。変更前はレジスタを数値インデックスで参照していましたが、変更後はdefs_netbsd_arm.goで定義されたREG_Rxx定数を使用することで、コードの意図がより明確になり、レジスタのインデックスが将来変更された場合でも、このマクロ定義のみを更新すればよくなります。また、SIG_CODE0SIG_CODE1の追加により、シグナル情報からより詳細なエラーコードや理由を取得できるようになり、デバッグやエラーハンドリングの精度が向上します。

src/pkg/runtime/sys_netbsd_arm.s の変更 (新規追加部分)

TEXT runtime·open(SB),7,$-8
	MOVW 0(FP), R0
	MOVW 4(FP), R1
	MOVW 8(FP), R2
	SWI $0xa00005
	RET

TEXT runtime·close(SB),7,$-8
	MOVW 0(FP), R0
	SWI $0xa00006
	RET

TEXT runtime·read(SB),7,$-8
	MOVW 0(FP), R0
	MOVW 4(FP), R1
	MOVW 8(FP), R2
	SWI $0xa00003
	RET

これらのアセンブリ言語コードは、GoランタイムがNetBSD上でopen, close, readといったシステムコールを呼び出すためのラッパーです。ARMアーキテクチャでは、システムコールの引数は通常R0からR6までのレジスタに渡され、システムコール番号は特定のレジスタ(通常はR7)に設定されるか、SWI命令のオペランドとして直接指定されます。NetBSD/ARMでは、SWI命令のオペランドとしてシステムコール番号が指定される形式が使われています(例: $0xa00005openシステムコールに対応)。これらのラッパーは、Goの関数呼び出し規約からOSのシステムコール呼び出し規約への変換を行い、GoプログラムがOSの機能を利用できるようにします。

関連リンク

参考にした情報源リンク

  • Go言語のソースコードリポジトリ (GitHub): https://github.com/golang/go
  • NetBSDのシステムコールに関するドキュメント (一般的な情報源): NetBSDのmanページや開発者向けドキュメント
  • ARMアーキテクチャのリファレンスマニュアル (一般的な情報源): ARM社の公式ドキュメント
  • Goのコードレビューシステム (Gerrit): https://go-review.googlesource.com/ (コミットメッセージに記載されているgolang.org/cl/7597046はこのシステムへのリンクです)
  • Goのメーリングリストやフォーラム (一般的な情報源): Goに関する議論や問題解決の履歴
  • GoのIssue Tracker (一般的な情報源): Goのバグ報告や機能要望の履歴
  • mcontext_t および ucontext_t 構造体に関するUnix系システムのドキュメント (一般的な情報源): manページ (例: getcontext(3), sigaction(2))