[インデックス 18423] ファイルの概要
このコミットは、Go言語のsyscall
パッケージにおいて、freebsd/arm
アーキテクチャ上でのビルドエラーを修正することを目的としています。具体的には、Timespec
およびTimeval
構造体にパディングフィールドを追加することで、C言語との相互運用(cgo)におけるアライメントの問題を解決し、将来的なcgoのFreeBSD/ARMサポートに向けた準備を進めています。
コミット
commit aa29cd98dcbc539f2517457a2cdfb8db3f9ff468
Author: Mikio Hara <mikioh.mikioh@gmail.com>
Date: Fri Feb 7 10:23:02 2014 +0900
syscall: fix build on freebsd/arm
This CL is in preparation to make cgo work on freebsd/arm.
It's just for fixing build fails on freebsd/arm, we still need to
update z-files later for fixing several package test fails.
How to generate z-files on freebsd/arm in the bootstrapping phase:
1. run freebsd on appropriate arm-eabi platforms
2. both syscall z-files and runtime def-files in the current tree are
broken about EABI padding, fix them by hand
3. run make.bash again to build $GOTOOLDIR/cgo
4. use $GOTOOLDIR/cgo directly
LGTM=iant
R=iant, dave
CC=golang-codereviews
https://golang.org/cl/59490052
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/aa29cd98dcbc539f2517457a2cdfb8db3f9ff468
元コミット内容
syscall: fix build on freebsd/arm
This CL is in preparation to make cgo work on freebsd/arm.
It's just for fixing build fails on freebsd/arm, we still need to
update z-files later for fixing several package test fails.
How to generate z-files on freebsd/arm in the bootstrapping phase:
1. run freebsd on appropriate arm-eabi platforms
2. both syscall z-files and runtime def-files in the current tree are
broken about EABI padding, fix them by hand
3. run make.bash again to build $GOTOOLDIR/cgo
4. use $GOTOOLDIR/cgo directly
LGTM=iant
R=iant, dave
CC=golang-codereviews
https://golang.org/cl/59490052
変更の背景
このコミットの主な背景は、Go言語がFreeBSDオペレーティングシステム上のARMアーキテクチャ(freebsd/arm
)でcgo(C言語との相互運用機能)を適切に動作させるための準備です。
Go言語は、異なるオペレーティングシステムやCPUアーキテクチャをサポートするために、各プラットフォーム固有のシステムコールやデータ構造を定義する必要があります。これらの定義は、通常、z-files
と呼ばれる自動生成されたファイルに含まれています。
FreeBSD/ARM環境では、Timespec
やTimeval
といった時間関連の構造体が、C言語のABI(Application Binary Interface)とGo言語のABIの間でアライメントの不一致を起こしていました。特に、ARMアーキテクチャで広く採用されているEABI(Embedded Application Binary Interface)のパディングルールが、この問題の根源でした。この不一致が原因で、GoプログラムがFreeBSD/ARM上でビルドする際にエラーが発生していました。
このコミットは、そのビルドエラーを修正するための第一歩であり、cgoがFreeBSD/ARMで機能するための前提条件を整えるものです。コミットメッセージにもあるように、この修正だけでは全てのパッケージテストがパスするわけではなく、後続のz-files
の更新が必要であることが示唆されています。
前提知識の解説
1. Go言語のsyscall
パッケージ
syscall
パッケージは、Goプログラムからオペレーティングシステムのシステムコールを直接呼び出すための機能を提供します。ファイル操作、ネットワーク通信、プロセス管理など、OSレベルの低レベルな操作を行う際に使用されます。このパッケージは、OSやアーキテクチャごとに異なるシステムコールの定義やデータ構造を扱うため、プラットフォーム固有の実装が多く含まれています。
2. z-files
Goのソースコードには、ztypes_*.go
やzerrors_*.go
といったファイルが多数存在します。これらは一般に「z-files」と呼ばれ、特定のOSやアーキテクチャにおけるシステムコール番号、エラーコード、データ構造の定義などが自動生成されたものです。これらのファイルは、Goのビルドプロセスの一部として、Cヘッダーファイルなどから情報を抽出し、Goのコードとして利用できるように変換されます。ABIの変更やOSのバージョンアップに伴い、これらのファイルも更新される必要があります。
3. cgo (C言語との相互運用)
cgoは、GoプログラムからC言語のコードを呼び出したり、C言語のコードからGoの関数を呼び出したりするためのGoの機能です。これにより、既存のCライブラリをGoプロジェクトで再利用したり、パフォーマンスが重要な部分をCで記述したりすることが可能になります。cgoを使用する際には、GoとCの間でデータ構造のレイアウトや関数の呼び出し規約(ABI)が一致していることが非常に重要です。不一致があると、データの破損やクラッシュの原因となります。
4. ARMアーキテクチャとEABI (Embedded Application Binary Interface)
ARMは、スマートフォン、タブレット、組み込みシステムなど、幅広いデバイスで使用されているCPUアーキテクチャです。EABIは、ARMプロセッサ上で動作するソフトウェアのバイナリ互換性を保証するための標準です。これには、データ型のアライメント、関数呼び出し規約、スタックフレームのレイアウトなどが含まれます。
特に重要なのが「パディング」です。CPUは、メモリからデータを読み書きする際に、特定のメモリアドレス境界にデータが配置されていることを期待する場合があります(アライメント要求)。例えば、4バイトの整数は4バイト境界に、8バイトの整数は8バイト境界に配置されるべき、といったルールです。構造体内でこれらのアライメント要求を満たすために、コンパイラはメンバー間に「パディング」と呼ばれる未使用のバイトを挿入することがあります。
C言語のコンパイラはEABIのルールに従って構造体をレイアウトしますが、Goのコンパイラが異なるルールで構造体をレイアウトすると、cgoを通じてCとGoの間で同じ構造体を共有しようとしたときに、メンバーのオフセットがずれてしまい、データが正しく読み書きできなくなる問題が発生します。
5. Timespec
とTimeval
構造体
これらはUnix系システムで時間を表現するために広く使われる構造体です。
Timespec
: 秒 (tv_sec
) とナノ秒 (tv_nsec
) で時間を表現します。struct timespec { time_t tv_sec; // 秒 long tv_nsec; // ナノ秒 };
Timeval
: 秒 (tv_sec
) とマイクロ秒 (tv_usec
) で時間を表現します。struct timeval { time_t tv_sec; // 秒 suseconds_t tv_usec; // マイクロ秒 };
これらの構造体は、システムコール(例: nanosleep
, gettimeofday
)の引数として頻繁に利用されます。
技術的詳細
このコミットの技術的な核心は、FreeBSD/ARM環境におけるC言語のABIとGo言語のABI間の構造体レイアウトの不一致を解消することです。具体的には、Timespec
とTimeval
構造体において、C言語側で暗黙的に挿入されるパディングをGo言語側でも明示的に追加することで、両者のメモリレイアウトを一致させます。
ARM EABIでは、構造体内のメンバーのアライメント要件が厳格に定められています。特に、int64
型(8バイト)のような大きなデータ型が構造体に含まれる場合、その後に続くメンバーが適切にアライメントされるように、コンパイラがパディングバイトを挿入することがあります。
元のztypes_freebsd_arm.go
では、Timespec
とTimeval
構造体は以下のように定義されていました。
type Timespec struct {
Sec int64
Nsec int32
}
type Timeval struct {
Sec int64
Usec int32
}
ここで問題となるのは、Sec
がint64
(8バイト)であるのに対し、Nsec
やUsec
がint32
(4バイト)である点です。ARM EABIのルールでは、int64
の後にint32
が続く場合、次のint64
やポインタ型が適切にアライメントされるように、int32
の後に4バイトのパディングが挿入されることがあります。Goのコンパイラがこのパディングを自動的に挿入しない場合、C言語のコードが期待する構造体のサイズやメンバーのオフセットと、Go言語のコードが認識するそれらとの間にずれが生じます。
このずれは、cgoを通じてCの関数にこれらの構造体を渡したり、Cの関数から受け取ったりする際に、メモリ上のデータが正しく解釈されない原因となります。結果として、ビルドエラーや実行時エラー、あるいはサイレントなデータ破損を引き起こす可能性があります。
このコミットでは、この問題を解決するために、Goの構造体にPad_cgo_0 [4]byte
というフィールドを明示的に追加しています。これは、Goコンパイラに対して「ここに4バイトのパディングを挿入せよ」と指示するもので、CコンパイラがEABIルールに従って挿入するパディングと全く同じ効果をもたらします。これにより、GoとCの間でTimespec
およびTimeval
構造体のメモリレイアウトが完全に一致し、cgoがFreeBSD/ARM上で正しく機能するための基盤が整えられます。
Pad_cgo_0
という命名は、cgoが内部的に使用するパディングフィールドの慣例に従ったものです。これは、開発者が手動で追加するパディングであることを示唆しつつ、cgoの文脈で意味を持つように設計されています。
コアとなるコードの変更箇所
変更はsrc/pkg/syscall/ztypes_freebsd_arm.go
ファイルに集中しています。
diff --git a/src/pkg/syscall/ztypes_freebsd_arm.go b/src/pkg/syscall/ztypes_freebsd_arm.go
index b1bf83b4c1..3d943f1346 100644
--- a/src/pkg/syscall/ztypes_freebsd_arm.go
+++ b/src/pkg/syscall/ztypes_freebsd_arm.go
@@ -19,13 +19,15 @@ type (
)
type Timespec struct {
- Sec int64
- Nsec int32
+ Sec int64
+ Nsec int32
+ Pad_cgo_0 [4]byte
}
type Timeval struct {
- Sec int64
- Usec int32
+ Sec int64
+ Usec int32
+ Pad_cgo_0 [4]byte
}
type Rusage struct {
コアとなるコードの解説
このコミットでは、Timespec
とTimeval
という2つの構造体に、それぞれPad_cgo_0 [4]byte
というフィールドが追加されています。
-
Timespec
構造体への変更:- 変更前:
type Timespec struct { Sec int64 Nsec int32 }
- 変更後:
type Timespec struct { Sec int64 Nsec int32 Pad_cgo_0 [4]byte // 追加されたパディングフィールド }
Sec
フィールドはint64
(8バイト)で、Nsec
フィールドはint32
(4バイト)です。ARM EABIのルールでは、int64
の後にint32
が続き、その後に別のint64
やポインタ型が続く場合、int32
の後に4バイトのパディングが挿入されることで、次の8バイト境界へのアライメントが保証されます。このPad_cgo_0 [4]byte
は、その4バイトのパディングをGoの構造体定義に明示的に追加するものです。 - 変更前:
-
Timeval
構造体への変更:- 変更前:
type Timeval struct { Sec int64 Usec int32 }
- 変更後:
type Timeval struct { Sec int64 Usec int32 Pad_cgo_0 [4]byte // 追加されたパディングフィールド }
Timeval
構造体もTimespec
と同様に、Sec
がint64
、Usec
がint32
であるため、同じアライメントの問題が発生します。したがって、ここにもPad_cgo_0 [4]byte
が追加され、C言語のABIとの互換性が確保されます。 - 変更前:
これらの変更により、Go言語のコンパイラが生成するTimespec
およびTimeval
構造体のメモリレイアウトが、FreeBSD/ARM上のC言語コンパイラが生成するそれらと完全に一致するようになります。これにより、cgoを通じてCのライブラリ関数にこれらの構造体を渡したり、Cの関数から受け取ったりする際に、メモリ上のデータの解釈が正しく行われ、ビルドエラーや実行時エラーが回避されます。
この修正は、Go言語が多様なプラットフォームで安定して動作するための、低レベルながらも非常に重要なABI互換性の調整の一例です。
関連リンク
- Go言語のcgoに関する公式ドキュメント: https://go.dev/blog/cgo
- ARM EABIに関する情報 (一般的な情報源):
- https://developer.arm.com/documentation/den0013/d/ (ARMの公式ドキュメント)
- https://en.wikipedia.org/wiki/ARM_architecture#EABI (Wikipedia)
参考にした情報源リンク
- コミットメッセージと差分 (
./commit_data/18423.txt
の内容) - Go言語の
syscall
パッケージの一般的な知識 - cgoの仕組みに関する一般的な知識
- ARMアーキテクチャとEABIにおけるデータアライメントとパディングに関する一般的な知識
Timespec
およびTimeval
構造体に関する一般的な知識- Google検索 (
ARM EABI padding
,Go cgo struct alignment
,FreeBSD ARM syscall
)
[インデックス 18423] ファイルの概要
このコミットは、Go言語のsyscall
パッケージにおいて、freebsd/arm
アーキテクチャ上でのビルドエラーを修正することを目的としています。具体的には、Timespec
およびTimeval
構造体にパディングフィールドを追加することで、C言語との相互運用(cgo)におけるアライメントの問題を解決し、将来的なcgoのFreeBSD/ARMサポートに向けた準備を進めています。
コミット
commit aa29cd98dcbc539f2517457a2cdfb8db3f9ff468
Author: Mikio Hara <mikioh.mikioh@gmail.com>
Date: Fri Feb 7 10:23:02 2014 +0900
syscall: fix build on freebsd/arm
This CL is in preparation to make cgo work on freebsd/arm.
It's just for fixing build fails on freebsd/arm, we still need to
update z-files later for fixing several package test fails.
How to generate z-files on freebsd/arm in the bootstrapping phase:
1. run freebsd on appropriate arm-eabi platforms
2. both syscall z-files and runtime def-files in the current tree are
broken about EABI padding, fix them by hand
3. run make.bash again to build $GOTOOLDIR/cgo
4. use $GOTOOLDIR/cgo directly
LGTM=iant
R=iant, dave
CC=golang-codereviews
https://golang.org/cl/59490052
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/aa29cd98dcbc539f2517457a2cdfb8db3f9ff468
元コミット内容
syscall: fix build on freebsd/arm
This CL is in preparation to make cgo work on freebsd/arm.
It's just for fixing build fails on freebsd/arm, we still need to
update z-files later for fixing several package test fails.
How to generate z-files on freebsd/arm in the bootstrapping phase:
1. run freebsd on appropriate arm-eabi platforms
2. both syscall z-files and runtime def-files in the current tree are
broken about EABI padding, fix them by hand
3. run make.bash again to build $GOTOOLDIR/cgo
4. use $GOTOOLDIR/cgo directly
LGTM=iant
R=iant, dave
CC=golang-codereviews
https://golang.org/cl/59490052
変更の背景
このコミットの主な背景は、Go言語がFreeBSDオペレーティングシステム上のARMアーキテクチャ(freebsd/arm
)でcgo(C言語との相互運用機能)を適切に動作させるための準備です。
Go言語は、異なるオペレーティングシステムやCPUアーキテクチャをサポートするために、各プラットフォーム固有のシステムコールやデータ構造を定義する必要があります。これらの定義は、通常、z-files
と呼ばれる自動生成されたファイルに含まれています。
FreeBSD/ARM環境では、Timespec
やTimeval
といった時間関連の構造体が、C言語のABI(Application Binary Interface)とGo言語のABIの間でアライメントの不一致を起こしていました。特に、ARMアーキテクチャで広く採用されているEABI(Embedded Application Binary Interface)のパディングルールが、この問題の根源でした。この不一致が原因で、GoプログラムがFreeBSD/ARM上でビルドする際にエラーが発生していました。
このコミットは、そのビルドエラーを修正するための第一歩であり、cgoがFreeBSD/ARMで機能するための前提条件を整えるものです。コミットメッセージにもあるように、この修正だけでは全てのパッケージテストがパスするわけではなく、後続のz-files
の更新が必要であることが示唆されています。
前提知識の解説
1. Go言語のsyscall
パッケージ
syscall
パッケージは、Goプログラムからオペレーティングシステムのシステムコールを直接呼び出すための機能を提供します。ファイル操作、ネットワーク通信、プロセス管理など、OSレベルの低レベルな操作を行う際に使用されます。このパッケージは、OSやアーキテクチャごとに異なるシステムコールの定義やデータ構造を扱うため、プラットフォーム固有の実装が多く含まれています。
2. z-files
Goのソースコードには、ztypes_*.go
やzerrors_*.go
といったファイルが多数存在します。これらは一般に「z-files」と呼ばれ、特定のOSやアーキテクチャにおけるシステムコール番号、エラーコード、データ構造の定義などが自動生成されたものです。これらのファイルは、Goのビルドプロセスの一部として、Cヘッダーファイルなどから情報を抽出し、Goのコードとして利用できるように変換されます。ABIの変更やOSのバージョンアップに伴い、これらのファイルも更新される必要があります。
3. cgo (C言語との相互運用)
cgoは、GoプログラムからC言語のコードを呼び出したり、C言語のコードからGoの関数を呼び出したりするためのGoの機能です。これにより、既存のCライブラリをGoプロジェクトで再利用したり、パフォーマンスが重要な部分をCで記述したりすることが可能になります。cgoを使用する際には、GoとCの間でデータ構造のレイアウトや関数の呼び出し規約(ABI)が一致していることが非常に重要です。不一致があると、データの破損やクラッシュの原因となります。
4. ARMアーキテクチャとEABI (Embedded Application Binary Interface)
ARMは、スマートフォン、タブレット、組み込みシステムなど、幅広いデバイスで使用されているCPUアーキテクチャです。EABIは、ARMプロセッサ上で動作するソフトウェアのバイナリ互換性を保証するための標準です。これには、データ型のアライメント、関数呼び出し規約、スタックフレームのレイアウトなどが含まれます。
特に重要なのが「パディング」です。CPUは、メモリからデータを読み書きする際に、特定のメモリアドレス境界にデータが配置されていることを期待する場合があります(アライメント要求)。例えば、4バイトの整数は4バイト境界に、8バイトの整数は8バイト境界に配置されるべき、といったルールです。構造体内でこれらのアライメント要求を満たすために、コンパイラはメンバー間に「パディング」と呼ばれる未使用のバイトを挿入することがあります。
C言語のコンパイラはEABIのルールに従って構造体をレイアウトしますが、Goのコンパイラが異なるルールで構造体をレイアウトすると、cgoを通じてCとGoの間で同じ構造体を共有しようとしたときに、メンバーのオフセットがずれてしまい、データが正しく読み書きできなくなる問題が発生します。
5. Timespec
とTimeval
構造体
これらはUnix系システムで時間を表現するために広く使われる構造体です。
Timespec
: 秒 (tv_sec
) とナノ秒 (tv_nsec
) で時間を表現します。struct timespec { time_t tv_sec; // 秒 long tv_nsec; // ナノ秒 };
Timeval
: 秒 (tv_sec
) とマイクロ秒 (tv_usec
) で時間を表現します。struct timeval { time_t tv_sec; // 秒 suseconds_t tv_usec; // マイクロ秒 };
これらの構造体は、システムコール(例: nanosleep
, gettimeofday
)の引数として頻繁に利用されます。
技術的詳細
このコミットの技術的な核心は、FreeBSD/ARM環境におけるC言語のABIとGo言語のABI間の構造体レイアウトの不一致を解消することです。具体的には、Timespec
とTimeval
構造体において、C言語側で暗黙的に挿入されるパディングをGo言語側でも明示的に追加することで、両者のメモリレイアウトを一致させます。
ARM EABIでは、構造体内のメンバーのアライメント要件が厳格に定められています。特に、int64
型(8バイト)のような大きなデータ型が構造体に含まれる場合、その後に続くメンバーが適切にアライメントされるように、コンパイラがパディングバイトを挿入することがあります。
元のztypes_freebsd_arm.go
では、Timespec
とTimeval
構造体は以下のように定義されていました。
type Timespec struct {
Sec int64
Nsec int32
}
type Timeval struct {
Sec int64
Usec int32
}
ここで問題となるのは、Sec
がint64
(8バイト)であるのに対し、Nsec
やUsec
がint32
(4バイト)である点です。ARM EABIのルールでは、int64
の後にint32
が続く場合、次のint64
やポインタ型が適切にアライメントされるように、int32
の後に4バイトのパディングが挿入されることがあります。Goのコンパイラがこのパディングを自動的に挿入しない場合、C言語のコードが期待する構造体のサイズやメンバーのオフセットと、Go言語のコードが認識するそれらとの間にずれが生じます。
このずれは、cgoを通じてCの関数にこれらの構造体を渡したり、Cの関数から受け取ったりする際に、メモリ上のデータが正しく解釈されない原因となります。結果として、ビルドエラーや実行時エラー、あるいはサイレントなデータ破損を引き起こす可能性があります。
このコミットでは、この問題を解決するために、Goの構造体にPad_cgo_0 [4]byte
というフィールドを明示的に追加しています。これは、Goコンパイラに対して「ここに4バイトのパディングを挿入せよ」と指示するもので、CコンパイラがEABIルールに従って挿入するパディングと全く同じ効果をもたらします。これにより、GoとCの間でTimespec
およびTimeval
構造体のメモリレイアウトが完全に一致し、cgoがFreeBSD/ARM上で正しく機能するための基盤が整えられます。
Pad_cgo_0
という命名は、cgoが内部的に使用するパディングフィールドの慣例に従ったものです。これは、開発者が手動で追加するパディングであることを示唆しつつ、cgoの文脈で意味を持つように設計されています。
コアとなるコードの変更箇所
変更はsrc/pkg/syscall/ztypes_freebsd_arm.go
ファイルに集中しています。
diff --git a/src/pkg/syscall/ztypes_freebsd_arm.go b/src/pkg/syscall/ztypes_freebsd_arm.go
index b1bf83b4c1..3d943f1346 100644
--- a/src/pkg/syscall/ztypes_freebsd_arm.go
+++ b/src/pkg/syscall/ztypes_freebsd_arm.go
@@ -19,13 +19,15 @@ type (
)
type Timespec struct {
- Sec int64
- Nsec int32
+ Sec int64
+ Nsec int32
+ Pad_cgo_0 [4]byte
}
type Timeval struct {
- Sec int64
- Usec int32
+ Sec int64
+ Usec int32
+ Pad_cgo_0 [4]byte
}
type Rusage struct {
コアとなるコードの解説
このコミットでは、Timespec
とTimeval
という2つの構造体に、それぞれPad_cgo_0 [4]byte
というフィールドが追加されています。
-
Timespec
構造体への変更:- 変更前:
type Timespec struct { Sec int64 Nsec int32 }
- 変更後:
type Timespec struct { Sec int64 Nsec int32 Pad_cgo_0 [4]byte // 追加されたパディングフィールド }
Sec
フィールドはint64
(8バイト)で、Nsec
フィールドはint32
(4バイト)です。ARM EABIのルールでは、int64
の後にint32
が続き、その後に別のint64
やポインタ型が続く場合、int32
の後に4バイトのパディングが挿入されることで、次の8バイト境界へのアライメントが保証されます。このPad_cgo_0 [4]byte
は、その4バイトのパディングをGoの構造体定義に明示的に追加するものです。 - 変更前:
-
Timeval
構造体への変更:- 変更前:
type Timeval struct { Sec int64 Usec int32 }
- 変更後:
type Timeval struct { Sec int64 Usec int32 Pad_cgo_0 [4]byte // 追加されたパディングフィールド }
Timeval
構造体もTimespec
と同様に、Sec
がint64
、Usec
がint32
であるため、同じアライメントの問題が発生します。したがって、ここにもPad_cgo_0 [4]byte
が追加され、C言語のABIとの互換性が確保されます。 - 変更前:
これらの変更により、Go言語のコンパイラが生成するTimespec
およびTimeval
構造体のメモリレイアウトが、FreeBSD/ARM上のC言語コンパイラが生成するそれらと完全に一致するようになります。これにより、cgoを通じてCのライブラリ関数にこれらの構造体を渡したり、Cの関数から受け取ったりする際に、メモリ上のデータの解釈が正しく行われ、ビルドエラーや実行時エラーが回避されます。
この修正は、Go言語が多様なプラットフォームで安定して動作するための、低レベルながらも非常に重要なABI互換性の調整の一例です。
関連リンク
- Go言語のcgoに関する公式ドキュメント: https://go.dev/blog/cgo
- ARM EABIに関する情報 (一般的な情報源):
- https://developer.arm.com/documentation/den0013/d/ (ARMの公式ドキュメント)
- https://en.wikipedia.org/wiki/ARM_architecture#EABI (Wikipedia)
参考にした情報源リンク
- コミットメッセージと差分 (
./commit_data/18423.txt
の内容) - Go言語の
syscall
パッケージの一般的な知識 - cgoの仕組みに関する一般的な知識
- ARMアーキテクチャとEABIにおけるデータアライメントとパディングに関する一般的な知識
Timespec
およびTimeval
構造体に関する一般的な知識- Google検索 (
ARM EABI padding
,Go cgo struct alignment
,FreeBSD ARM syscall
)