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

[インデックス 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点に集約されます。

  1. 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ルールに従ってシステムコールを生成することが適切であるという判断に基づいています。

  2. 構造体のアライメントとパディングの調整: 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)を追加したことです。

  • TimespecTimeval: これらの構造体は、時間情報を表すために使用されます。int64int32の組み合わせで、EABIのパディングルールに従うために[4]byteのパディングが追加されました。これにより、構造体全体のサイズが適切にアライメントされ、C言語のAPIとの互換性が保たれます。
  • Stat_t: ファイルやディレクトリの統計情報を表す構造体です。複数のuint32uint64フィールドが含まれており、EABIの厳密なアライメント要件を満たすために、複数の箇所に[4]byteのパディングが挿入されています。これにより、Stat_t構造体がカーネルから返される際に、Go側で正しく解釈されることが保証されます。
  • Kevent_t: kqueueシステムコールで使用されるイベント情報を表す構造体です。ここでもint64int32のフィールドの後に[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プログラムの安定性と信頼性が向上します。

関連リンク

参考にした情報源リンク