[インデックス 18773] ファイルの概要
このコミットは、Go言語のsyscall
パッケージにおけるNetBSD/ARMポートをEABI(Embedded Application Binary Interface)に更新するものです。具体的には、システムコール関連の構造体のアライメントとパディングを調整し、mksyscall.pl
スクリプトの引数を変更することで、NetBSD上のARMアーキテクチャにおけるGoプログラムの互換性と安定性を向上させています。
コミット
commit 30d60936d97423af0403f2d53995c604ac0ff3757
Author: Shenghou Ma <minux.ma@gmail.com>
Date: Thu Mar 6 00:55:57 2014 -0500
syscall: update NetBSD/ARM port to EABI.
LGTM=jsing
R=golang-codereviews, jsing
CC=golang-codereviews
https://golang.org/cl/70720043
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/30d60936d97423af0403f2d5395c604ac0ff3757
元コミット内容
syscall: update NetBSD/ARM port to EABI.
LGTM=jsing
R=golang-codereviews, jsing
CC=golang-codereviews
https://golang.org/cl/70720043
変更の背景
このコミットの背景には、ARMアーキテクチャにおけるABI(Application Binary Interface)の標準化と、それに対応するGo言語のsyscall
パッケージの必要性があります。
ARMアーキテクチャでは、異なるABIが複数存在します。特に、組み込みシステムや特定のOS環境では、パフォーマンスや互換性のために特定のABIが採用されます。EABI(Embedded Application Binary Interface)は、ARMプロセッサ向けのソフトウェア開発において、関数呼び出し規約、データ型のアライメント、レジスタの使用方法などを標準化するための仕様です。これにより、異なるツールチェインやコンパイラで生成されたコード間での互換性が保証され、システム全体の安定性が向上します。
NetBSDは、様々なアーキテクチャをサポートする移植性の高いUNIX系OSです。ARMアーキテクチャ上でのNetBSDの動作において、Go言語のプログラムがシステムコールを正しく実行するためには、NetBSDが採用しているARMのABI(この場合はEABI)にGoのsyscall
パッケージが準拠している必要があります。
以前のGoのNetBSD/ARMポートは、EABIに完全に準拠していなかった可能性があります。これにより、システムコール呼び出し時の引数の渡し方や、構造体のメモリレイアウトに不整合が生じ、Goプログラムが予期せぬ動作をしたり、クラッシュしたりする可能性がありました。このコミットは、これらの問題を解決し、NetBSD/ARM環境でのGoプログラムの堅牢性を高めることを目的としています。
前提知識の解説
ABI (Application Binary Interface)
ABIは、オペレーティングシステムとアプリケーション、またはアプリケーションの異なるモジュール間で、バイナリレベルでの互換性を定義する一連の規約です。これには以下の要素が含まれます。
- データ型のサイズとアライメント: 各データ型(例:
int
,long
,struct
)がメモリ上でどれくらいのサイズを占め、どのメモリ境界に配置されるか。 - 関数呼び出し規約: 関数に引数を渡す方法(レジスタ渡し、スタック渡し)、戻り値の受け取り方、スタックの管理方法。
- レジスタの使用規約: 関数呼び出し前後でどのレジスタが保存されるべきか(caller-saved vs. callee-saved)。
- システムコール規約: アプリケーションがOSのサービスを要求する際のインターフェース。
ABIが異なると、同じソースコードからコンパイルされたバイナリであっても、互換性が失われる可能性があります。
EABI (Embedded Application Binary Interface)
EABIは、特にARMアーキテクチャ向けのABIの標準です。組み込みシステムやモバイルデバイスなど、リソースが限られた環境での効率的なコード生成と互換性を目的としています。EABIは、浮動小数点演算の扱い、構造体のアライメント、関数呼び出し規約などにおいて、従来のARM ABIとは異なる特定のルールを定めています。
システムコール (Syscall)
システムコールは、アプリケーションがオペレーティングシステムのカーネルが提供するサービス(ファイルI/O、メモリ管理、プロセス制御など)を利用するためのインターフェースです。Go言語のsyscall
パッケージは、OS固有のシステムコールをGoプログラムから呼び出すための機能を提供します。システムコールを正しく呼び出すためには、OSが期待する引数の型、順序、メモリレイアウトに厳密に合わせる必要があります。
構造体のアライメントとパディング
コンピュータのメモリは、通常バイト単位でアドレス指定されますが、CPUは特定のデータ型を特定のメモリ境界(アライメント)に配置することで、より効率的にアクセスできます。例えば、4バイトの整数は4バイト境界に、8バイトの整数は8バイト境界に配置されることが一般的です。
構造体の場合、メンバ変数がそれぞれのアライメント要件を満たすように配置されます。この際、メンバ間に未使用の領域(パディング)が挿入されることがあります。パディングは、構造体全体のサイズをアライメント要件の倍数にするためにも使用されます。ABIは、これらのアライメントとパディングのルールを厳密に定義しており、異なるABI間では構造体のメモリレイアウトが異なる可能性があります。
mksyscall.pl
mksyscall.pl
は、Go言語のsyscall
パッケージでシステムコールを生成するために使用されるPerlスクリプトです。このスクリプトは、Goのソースファイルからシステムコール定義を読み取り、OSやアーキテクチャ固有のGoコード(例: zsyscall_*.go
, ztypes_*.go
)を自動生成します。これにより、手動での記述ミスを防ぎ、異なるプラットフォームへの移植を容易にします。
技術的詳細
このコミットの技術的詳細は、主に以下の2点に集約されます。
-
mksyscall.pl
スクリプトの引数変更:src/pkg/syscall/zsyscall_netbsd_arm.go
ファイルのヘッダコメントが変更されています。 変更前:// mksyscall.pl -l32 -netbsd syscall_bsd.go syscall_netbsd.go syscall_netbsd_arm.go
変更後:// mksyscall.pl -l32 -arm syscall_bsd.go syscall_netbsd.go syscall_netbsd_arm.go
この変更は、mksyscall.pl
スクリプトがNetBSD固有のシステムコール生成ロジックではなく、より一般的なARMアーキテクチャ向けのシステムコール生成ロジックを使用するように指示していることを示唆しています。これは、NetBSD/ARMがEABIに準拠しているため、ARMの標準的なABIルールに従ってシステムコールを生成することが適切であるという判断に基づいています。 -
構造体のアライメントとパディングの調整:
src/pkg/syscall/ztypes_netbsd_arm.go
ファイルでは、複数のシステムコール関連構造体にPad_cgo_0
,Pad_cgo_1
,Pad_cgo_2
といったパディングフィールドが追加されています。これは、NetBSD/ARMのEABIにおける構造体のアライメント要件を満たすためです。Timespec
構造体:Nsec
フィールドの後に[4]byte
のパディングが追加されています。Timeval
構造体:Usec
フィールドの後に[4]byte
のパディングが追加されています。Stat_t
構造体:Mode
フィールドの後、Gid
フィールドの後、そして構造体の最後にそれぞれ[4]byte
のパディングが追加されています。Kevent_t
構造体:Udata
フィールドの後に[4]byte
のパディングが追加されています。SizeofIfData
定数の値が0x84
から0x88
に変更されています。これは、IfData
構造体のサイズがパディングの追加によって増加したことを示しています。IfMsghdr
構造体からPad_cgo_1 [4]byte
が削除されています。これは、IfData
構造体内のパディング調整により、この位置でのパディングが不要になったか、あるいは別の場所でアライメントが満たされるようになったためと考えられます。
これらのパディングの追加は、Goの構造体レイアウトがNetBSD/ARMのEABIが期待するメモリレイアウトと一致するように調整されたことを意味します。これにより、Goプログラムがシステムコールを呼び出す際に、カーネルとアプリケーション間でデータ構造の解釈に齟齬が生じることを防ぎ、システムコールの成功率と安定性を向上させます。特に、C言語で書かれたカーネルAPIとの相互運用性において、ABIの厳密な準拠は不可欠です。
コアとなるコードの変更箇所
src/pkg/syscall/zsyscall_netbsd_arm.go
--- a/src/pkg/syscall/zsyscall_netbsd_arm.go
+++ b/src/pkg/syscall/zsyscall_netbsd_arm.go
@@ -1,4 +1,4 @@
-// mksyscall.pl -l32 -netbsd syscall_bsd.go syscall_netbsd.go syscall_netbsd_arm.go
+// mksyscall.pl -l32 -arm syscall_bsd.go syscall_netbsd.go syscall_netbsd_arm.go
// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
package syscall
src/pkg/syscall/ztypes_netbsd_arm.go
--- a/src/pkg/syscall/ztypes_netbsd_arm.go
+++ b/src/pkg/syscall/ztypes_netbsd_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 {
@@ -57,10 +59,12 @@ type _Gid_t uint32
type Stat_t struct {
Dev uint64
Mode uint32
+ Pad_cgo_0 [4]byte
Ino uint64
Nlink uint32
Uid uint32
Gid uint32
+ Pad_cgo_1 [4]byte
Rdev uint64
Atimespec Timespec
Mtimespec Timespec
@@ -72,6 +76,7 @@ type Stat_t struct {
Flags uint32
Gen uint32
Spare [2]uint32
+ Pad_cgo_2 [4]byte
}
type Statfs_t [0]byte
@@ -217,12 +222,13 @@ const (
)
type Kevent_t struct {
- Ident uint32
- Filter uint32
- Flags uint32
- Fflags uint32
- Data int64
- Udata int32
+ Ident uint32
+ Filter uint32
+ Flags uint32
+ Fflags uint32
+ Data int64
+ Udata int32
+ Pad_cgo_0 [4]byte
}
type FdSet struct {
@@ -231,7 +237,7 @@ type FdSet struct {
const (
SizeofIfMsghdr = 0x98
- SizeofIfData = 0x84
+ SizeofIfData = 0x88
SizeofIfaMsghdr = 0x18
SizeofIfAnnounceMsghdr = 0x18
SizeofRtMsghdr = 0x78
@@ -247,7 +253,6 @@ type IfMsghdr struct {
Index uint16
Pad_cgo_0 [2]byte
Data IfData
- Pad_cgo_1 [4]byte
}
type IfData struct {
コアとなるコードの解説
src/pkg/syscall/zsyscall_netbsd_arm.go
の変更
このファイルの変更は、コメント行のmksyscall.pl
の呼び出し方を変えただけです。これは、このファイルが自動生成される際のコマンドライン引数を記録しているためです。-netbsd
オプションから-arm
オプションへの変更は、NetBSD/ARM環境でのシステムコール生成において、NetBSD固有のABI調整よりも、ARM EABIの一般的なルールを優先して適用するようにmksyscall.pl
に指示していることを意味します。これにより、Goのsyscall
パッケージがNetBSD/ARMのEABIに正確に準拠したシステムコールインターフェースを生成できるようになります。
src/pkg/syscall/ztypes_netbsd_arm.go
の変更
このファイルは、NetBSD/ARMアーキテクチャ固有のシステムコール関連のC言語構造体をGoの構造体として定義している部分です。変更の核心は、Goの構造体に明示的なパディングフィールド(Pad_cgo_0
, Pad_cgo_1
, Pad_cgo_2
)を追加したことです。
Timespec
とTimeval
: これらの構造体は、時間情報を表すために使用されます。int64
とint32
の組み合わせで、EABIのパディングルールに従うために[4]byte
のパディングが追加されました。これにより、構造体全体のサイズが適切にアライメントされ、C言語のAPIとの互換性が保たれます。Stat_t
: ファイルやディレクトリの統計情報を表す構造体です。複数のuint32
やuint64
フィールドが含まれており、EABIの厳密なアライメント要件を満たすために、複数の箇所に[4]byte
のパディングが挿入されています。これにより、Stat_t
構造体がカーネルから返される際に、Go側で正しく解釈されることが保証されます。Kevent_t
: kqueueシステムコールで使用されるイベント情報を表す構造体です。ここでもint64
とint32
のフィールドの後に[4]byte
のパディングが追加され、EABIに準拠しています。SizeofIfData
定数:IfData
構造体のサイズを表す定数です。この値が0x84
(132バイト)から0x88
(136バイト)に増加しています。これは、IfData
構造体内部にパディングが追加された結果、そのサイズが4バイト増加したことを示しています。IfMsghdr
からのパディング削除:IfMsghdr
構造体からPad_cgo_1 [4]byte
が削除されています。これは、IfData
構造体自体のパディングが調整されたことで、IfMsghdr
のこの位置での追加パディングが不要になったためと考えられます。全体として、構造体のアライメントが最適化され、冗長なパディングが排除された可能性があります。
これらの変更は、Goのコンパイラが生成する構造体のメモリレイアウトが、NetBSD/ARMのEABIが期待するレイアウトと完全に一致するように調整されたことを意味します。これにより、GoプログラムがNetBSDカーネルとシステムコールを通じてデータをやり取りする際の、バイナリレベルでの互換性が確保され、Goプログラムの安定性と信頼性が向上します。
関連リンク
- ARM EABI: ARMの公式ドキュメントや、GCCなどのコンパイラプロジェクトのドキュメントで詳細な仕様を確認できます。
- NetBSD: NetBSDの公式ウェブサイトやドキュメント。
- Go
syscall
パッケージ: Go言語の標準ライブラリドキュメント。
参考にした情報源リンク
- Go言語のコミット履歴とソースコード
- ARM EABIに関する一般的な情報源(例: Wikipedia, 組み込みシステム関連の技術ブログ)
- NetBSDのドキュメント(特にARMアーキテクチャ関連)
- Go言語の
mksyscall.pl
スクリプトの機能に関する情報 - C言語における構造体のアライメントとパディングに関する一般的なプログラミング知識
- golang/go のコミット 30d60936d97423af0403f2d5395c604ac0ff3757
- Go CL 70720043 (Gerrit Code Review)
- Embedded Application Binary Interface - Wikipedia
- NetBSD/arm - NetBSD Wiki
- Go source code: src/pkg/syscall/zsyscall_netbsd_arm.go (コミット時点のパス)
- Go source code: src/pkg/syscall/ztypes_netbsd_arm.go (コミット時点のパス)
- Go source code: src/mksyscall.pl (コミット時点のパス)