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

[インデックス 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環境では、TimespecTimevalといった時間関連の構造体が、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_*.gozerrors_*.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. TimespecTimeval構造体

これらは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間の構造体レイアウトの不一致を解消することです。具体的には、TimespecTimeval構造体において、C言語側で暗黙的に挿入されるパディングをGo言語側でも明示的に追加することで、両者のメモリレイアウトを一致させます。

ARM EABIでは、構造体内のメンバーのアライメント要件が厳格に定められています。特に、int64型(8バイト)のような大きなデータ型が構造体に含まれる場合、その後に続くメンバーが適切にアライメントされるように、コンパイラがパディングバイトを挿入することがあります。

元のztypes_freebsd_arm.goでは、TimespecTimeval構造体は以下のように定義されていました。

type Timespec struct {
	Sec  int64
	Nsec int32
}

type Timeval struct {
	Sec  int64
	Usec int32
}

ここで問題となるのは、Secint64(8バイト)であるのに対し、NsecUsecint32(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 {

コアとなるコードの解説

このコミットでは、TimespecTimevalという2つの構造体に、それぞれPad_cgo_0 [4]byteというフィールドが追加されています。

  1. 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の構造体定義に明示的に追加するものです。

  2. Timeval構造体への変更:

    • 変更前:
      type Timeval struct {
      	Sec  int64
      	Usec int32
      }
      
    • 変更後:
      type Timeval struct {
      	Sec       int64
      	Usec      int32
      	Pad_cgo_0 [4]byte // 追加されたパディングフィールド
      }
      

    Timeval構造体もTimespecと同様に、Secint64Usecint32であるため、同じアライメントの問題が発生します。したがって、ここにもPad_cgo_0 [4]byteが追加され、C言語のABIとの互換性が確保されます。

これらの変更により、Go言語のコンパイラが生成するTimespecおよびTimeval構造体のメモリレイアウトが、FreeBSD/ARM上のC言語コンパイラが生成するそれらと完全に一致するようになります。これにより、cgoを通じてCのライブラリ関数にこれらの構造体を渡したり、Cの関数から受け取ったりする際に、メモリ上のデータの解釈が正しく行われ、ビルドエラーや実行時エラーが回避されます。

この修正は、Go言語が多様なプラットフォームで安定して動作するための、低レベルながらも非常に重要なABI互換性の調整の一例です。

関連リンク

参考にした情報源リンク

  • コミットメッセージと差分 (./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環境では、TimespecTimevalといった時間関連の構造体が、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_*.gozerrors_*.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. TimespecTimeval構造体

これらは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間の構造体レイアウトの不一致を解消することです。具体的には、TimespecTimeval構造体において、C言語側で暗黙的に挿入されるパディングをGo言語側でも明示的に追加することで、両者のメモリレイアウトを一致させます。

ARM EABIでは、構造体内のメンバーのアライメント要件が厳格に定められています。特に、int64型(8バイト)のような大きなデータ型が構造体に含まれる場合、その後に続くメンバーが適切にアライメントされるように、コンパイラがパディングバイトを挿入することがあります。

元のztypes_freebsd_arm.goでは、TimespecTimeval構造体は以下のように定義されていました。

type Timespec struct {
	Sec  int64
	Nsec int32
}

type Timeval struct {
	Sec  int64
	Usec int32
}

ここで問題となるのは、Secint64(8バイト)であるのに対し、NsecUsecint32(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 {

コアとなるコードの解説

このコミットでは、TimespecTimevalという2つの構造体に、それぞれPad_cgo_0 [4]byteというフィールドが追加されています。

  1. 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の構造体定義に明示的に追加するものです。

  2. Timeval構造体への変更:

    • 変更前:
      type Timeval struct {
      	Sec  int64
      	Usec int32
      }
      
    • 変更後:
      type Timeval struct {
      	Sec       int64
      	Usec      int32
      	Pad_cgo_0 [4]byte // 追加されたパディングフィールド
      }
      

    Timeval構造体もTimespecと同様に、Secint64Usecint32であるため、同じアライメントの問題が発生します。したがって、ここにもPad_cgo_0 [4]byteが追加され、C言語のABIとの互換性が確保されます。

これらの変更により、Go言語のコンパイラが生成するTimespecおよびTimeval構造体のメモリレイアウトが、FreeBSD/ARM上のC言語コンパイラが生成するそれらと完全に一致するようになります。これにより、cgoを通じてCのライブラリ関数にこれらの構造体を渡したり、Cの関数から受け取ったりする際に、メモリ上のデータの解釈が正しく行われ、ビルドエラーや実行時エラーが回避されます。

この修正は、Go言語が多様なプラットフォームで安定して動作するための、低レベルながらも非常に重要なABI互換性の調整の一例です。

関連リンク

参考にした情報源リンク

  • コミットメッセージと差分 (./commit_data/18423.txtの内容)
  • Go言語のsyscallパッケージの一般的な知識
  • cgoの仕組みに関する一般的な知識
  • ARMアーキテクチャとEABIにおけるデータアライメントとパディングに関する一般的な知識
  • TimespecおよびTimeval構造体に関する一般的な知識
  • Google検索 (ARM EABI padding, Go cgo struct alignment, FreeBSD ARM syscall)