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

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

このコミットは、Go言語のsyscallパッケージにおけるLinux/ARMアーキテクチャ向けのシステムコール実装のバグを修正するものです。特に、64ビット引数の扱いに関するARM ABI(Application Binary Interface)の要件と、それに伴うfallocateシステムコールでのEFBIG(File too large)エラーの発生、そして手動で調整されていたシステムコールルーチンの自動生成への移行が主な変更点です。また、asm/unistd.hヘッダーファイルの取得方法も変更されています。

コミット

commit 6e211225d7ec363d5205799fe15bb8cebd9703f9
Author: Shenghou Ma <minux.ma@gmail.com>
Date:   Tue Mar 6 03:12:11 2012 +0800

    syscall: fix mkall.sh, mksyscall_linux.pl, and regen for Linux/ARM
    CL 3075041 says ARM is not little-endian, but my test suggests otherwise.
    My test program is:
    
        package main
        import ("fmt"; "syscall"; "os")
        func main() {
           err := syscall.Fallocate(1, 1/*FALLOC_FL_KEEP_SIZE*/, 0, int64(40960));
           fmt.Fprintln(os.Stderr, err)
        }
    
    Without this CL, ./test > testfile will show: file too large; and strace shows:
        fallocate(1, 01, 0, 175921860444160)    = -1 EFBIG (File too large)
    With this CL, ./test > testfile will show: <nil>; and strace shows:
        fallocate(1, 01, 0, 40960)              = 0
    
    Quoting rsc:
    "[It turns out that] ARM syscall ABI requires 64-bit arguments to use an
    (even, odd) register pair, not an (odd, even) pair. Switching to "big-endian"
    worked because it ended up using the high 32-bits (always zero in the tests
    we had) as the padding word, because the 64-bit argument was the last one,
    and because we fill in zeros for the rest of the system call arguments, up to
    six. So it happened to work."
    
    I updated mksyscall_linux.pl to accommodate the register pair ABI requirement,
    and removed all hand-tweaked syscall routines in favor of the auto-generated
    ones. These including: Ftruncate, Truncate, Pread and Pwrite.
    
    Some recent Linux/ARM distributions do not bundle kernel asm headers,
    so instead we always get latest asm/unistd.h from git.kernel.org (just like
    what we do for FreeBSD).
    
    R=ken, r, rsc, r, dave, iant
    CC=golang-dev
    https://golang.org/cl/5726051

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

https://github.com/golang/go/commit/6e211225d7ec363d5205798fe15bb8cebd9703f9

元コミット内容

syscall: fix mkall.sh, mksyscall_linux.pl, and regen for Linux/ARM
CL 3075041 says ARM is not little-endian, but my test suggests otherwise.
My test program is:

    package main
    import ("fmt"; "syscall"; "os")
    func main() {
       err := syscall.Fallocate(1, 1/*FALLOC_FL_KEEP_SIZE*/, 0, int64(40960));
       fmt.Fprintln(os.Stderr, err)
    }

Without this CL, ./test > testfile will show: file too large; and strace shows:
    fallocate(1, 01, 0, 175921860444160)    = -1 EFBIG (File too large)
With this CL, ./test > testfile will show: <nil>; and strace shows:
    fallocate(1, 01, 0, 40960)              = 0

Quoting rsc:
"[It turns out that] ARM syscall ABI requires 64-bit arguments to use an
(even, odd) register pair, not an (odd, even) pair. Switching to "big-endian"
worked because it ended up using the high 32-bits (always zero in the tests
we had) as the padding word, because the 64-bit argument was the last one,
and because we fill in zeros for the rest of the system call arguments, up to
six. So it happened to work."

I updated mksyscall_linux.pl to accommodate the register pair ABI requirement,
and removed all hand-tweaked syscall routines in favor of the auto-generated
ones. These including: Ftruncate, Truncate, Pread and Pwrite.

Some recent Linux/ARM distributions do not bundle kernel asm headers,
so instead we always get latest asm/unistd.h from git.kernel.org (just like
what we do for FreeBSD).

R=ken, r, rsc, r, dave, iant
CC=golang-dev
https://golang.org/cl/5726051

変更の背景

このコミットは、Go言語がLinux/ARM環境でシステムコールを正しく実行できないという重要なバグを修正するために導入されました。具体的には、fallocateシステムコールがEFBIG(File too large)エラーを返す問題が報告されました。これは、GoのsyscallパッケージがARMアーキテクチャのシステムコールABI(Application Binary Interface)における64ビット引数の渡し方を誤解していたことに起因します。

従来のGoの実装では、ARMがリトルエンディアンではないという誤った仮定に基づいて64ビット引数を処理していました。しかし、実際のテストではARMがリトルエンディアンであることが示され、この誤解がシステムコールへの引数渡しに問題を引き起こしていました。特に、64ビット引数が期待されるfallocateのようなシステムコールでは、誤った値がカーネルに渡され、結果としてファイルサイズが異常に大きな値として解釈され、EFBIGエラーが発生していました。

また、この問題は、Goのsyscallパッケージ内で一部のシステムコール(Ftruncate, Truncate, Pread, Pwriteなど)が手動で調整された(hand-tweaked)実装を持っていたことにも関連していました。これらの手動実装は、特定のABIの癖に対応するために導入されたものですが、ABIの正確な理解が不足していたり、ABIの変更に対応しきれていなかったりすると、かえって問題を引き起こす可能性がありました。

さらに、一部のLinux/ARMディストリビューションでは、カーネルのasm/unistd.hヘッダーファイルがバンドルされていないため、システムコール番号の定義を取得する際に問題が発生していました。これも、Goのビルドプロセスにおける課題となっていました。

これらの問題を解決し、GoがLinux/ARM環境でより堅牢かつ正確に動作するようにするために、このコミットが作成されました。

前提知識の解説

ARMシステムコールABIと64ビット引数

システムコールABIは、ユーザー空間のプログラムがカーネルにサービスを要求する際に、引数をどのように渡し、戻り値をどのように受け取るかを定義する規約です。ARMアーキテクチャ、特に32ビットARM(ARMv7など)のLinux Embedded ABI (EABI)では、64ビットの引数(例: long long型)を渡す際に、特定のレジスタペアを使用するという特殊なルールが存在します。

通常、32ビットアーキテクチャでは、レジスタは32ビット幅です。64ビットの値を渡す場合、これを2つの32ビットレジスタに分割して渡す必要があります。ARM EABIの規約では、64ビット引数は「偶数-奇数」のレジスタペア(例: r0r1r2r3など)に配置されます。つまり、64ビット値の下位32ビットが偶数番目のレジスタに、上位32ビットが奇数番目のレジスタに格納されます。

このコミットの元の問題は、Goのシステムコール生成ツールがこの「偶数-奇数」レジスタペアの規約を正しく理解していなかった、または誤ったエンディアンの仮定に基づいて引数を配置していたことにあります。コミットメッセージにあるrscの引用が示すように、64ビット引数が最後の引数であった場合、たまたまゼロがパディングとして埋められ、動作してしまうケースもあったようですが、これは偶然に依存する不安定な挙動でした。

Goのシステムコール生成 (mksyscall.pl)

Go言語のsyscallパッケージは、オペレーティングシステムの低レベルなシステムコールをGoプログラムから呼び出すためのインターフェースを提供します。Goはクロスプラットフォーム言語であるため、各OSおよびアーキテクチャ固有のシステムコール呼び出し規約に対応する必要があります。

Goでは、mksyscall.plというPerlスクリプトが、システムコール呼び出しのためのGoコードを自動生成するために使用されていました。このスクリプトは、Goのソースファイル内に記述された特別なコメント(例: //sys//sysnb)を解析し、それに基づいて各システムコールのGoラッパー関数を生成します。この生成プロセスには、引数の型変換、レジスタへの配置、システムコール番号の指定などが含まれます。

しかし、mksyscall.plがABIの複雑な詳細(特にARMの64ビット引数レジスタペアの要件)を完全に把握していなかったため、生成されるコードが誤った引数渡しを行うことがありました。

EFBIGエラー

EFBIGは、POSIX標準で定義されているエラーコードの一つで、「File too large」(ファイルが大きすぎる)を意味します。このエラーは、ファイルシステムがサポートする最大ファイルサイズを超える操作を行おうとした場合に発生します。

このコミットのケースでは、fallocateシステムコールがEFBIGエラーを返していました。fallocateは、ファイルにディスクスペースを事前に割り当てるためのシステムコールです。コミットメッセージのテストプログラムが示すように、fallocate(1, 1/*FALLOC_FL_KEEP_SIZE*/, 0, int64(40960))という呼び出しが、実際にはfallocate(1, 01, 0, 175921860444160)(非常に大きな値)としてカーネルに渡されていました。これは、Goが64ビットのlength引数(40960)をARM ABIの規約に従って正しくレジスタに配置できなかったため、カーネルが誤った(巨大な)値を読み取ってしまい、結果としてファイルシステムの上限を超えたと判断されEFBIGエラーが発生したものです。

asm/unistd.h

asm/unistd.hは、Linuxカーネルのソースコードに含まれるヘッダーファイルで、特定のアーキテクチャ(例: ARM, x86)向けのシステムコール番号の定義が含まれています。Goのシステムコール生成プロセスでは、これらのヘッダーファイルからシステムコール番号を抽出し、Goのコードに組み込む必要があります。

一部のLinux/ARMディストリビューションでは、開発環境にこれらのカーネルヘッダーがバンドルされていないことがあり、Goのビルド時にシステムコール番号の定義が見つからないという問題が発生していました。

技術的詳細

このコミットは、GoのLinux/ARMシステムコール実装における複数の問題を包括的に解決しています。

  1. mksyscall.plの修正とARM ABIへの対応:

    • src/pkg/syscall/mksyscall.plスクリプトに-armオプションが追加されました。
    • このオプションが有効な場合、64ビット引数を処理する際に、現在の引数リストの数が奇数であれば、パディングとして0を挿入するロジックが追加されました。これは、ARM ABIが64ビット引数に「偶数-奇数」のレジスタペアを要求するため、引数の位置を調整するためのものです。これにより、64ビット値が常に偶数番目のレジスタから始まるように保証されます。
    • 以前の-b32(big-endian)オプションが、たまたま64ビット引数のパディングを正しく行っていたケースがあったというrscのコメントは、このABIの複雑さを示しています。今回の修正で、より汎用的な方法でABI要件を満たすようになりました。
  2. 手動調整されたシステムコールルーチンの削除と自動生成への移行:

    • src/pkg/syscall/syscall_linux_arm.goから、Pread, Pwrite, Ftruncate, Truncateといったシステムコールの手動実装が削除されました。
    • これらのシステムコールは、//sysディレクティブを使用して自動生成されるように変更されました。これにより、mksyscall.plの修正がこれらのシステムコールにも適用され、64ビット引数の渡し方がABIに準拠するようになります。手動実装は、ABIの変更や複雑なケースに対応しきれないリスクがあるため、自動生成に移行することで、より堅牢で保守性の高いコードベースが実現されます。
  3. asm/unistd.hの取得方法の変更:

    • src/pkg/syscall/mkall.shスクリプトにおいて、Linux/ARM向けのmksysnum(システムコール番号生成)コマンドのソースが変更されました。
    • 以前は/usr/include/asm/unistd.hというローカルパスから取得しようとしていましたが、これが一部のディストリビューションで利用できない問題がありました。
    • 修正後は、curl -s 'http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=blob_plain;f=arch/arm/include/asm/unistd.h;hb=HEAD'というコマンドを使用して、git.kernel.orgから直接最新のasm/unistd.hを取得するようになりました。これはFreeBSD向けと同様のアプローチであり、システムコール番号の定義の可用性と一貫性を向上させます。
  4. zsyscall_linux_arm.goにおける引数順序の修正:

    • Fallocateシステムコールの呼び出しにおいて、64ビット引数offlenのレジスタへの配置順序が修正されました。以前はuintptr(off>>32), uintptr(off)の順でしたが、uintptr(off), uintptr(off>>32)に修正されています。これは、ARMの64ビット引数渡し規約において、下位32ビットが偶数レジスタ、上位32ビットが奇数レジスタに配置されるというルールに合致させるための変更です。
    • 同様に、Teeシステムコールの戻り値の結合順序もint64(int64(r0)<<32 | int64(r1))からint64(int64(r1)<<32 | int64(r0))に修正されています。これは、システムコールからの戻り値がレジスタr0r1に分割されて返される場合に、正しい64ビット値を再構築するためのエンディアンに関する修正です。

これらの変更により、GoのLinux/ARM環境でのシステムコール呼び出しがABIに完全に準拠し、fallocateのような64ビット引数を使用するシステムコールが正しく動作するようになりました。

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

このコミットにおける主要なコード変更は以下のファイルに集中しています。

  1. src/pkg/syscall/mkall.sh:

    • Linux/ARM向けのmksysnumコマンドのソースが変更されました。
    • 変更前: mksysnum="./mksysnum_linux.pl /usr/include/asm/unistd.h"
    • 変更後: mksysnum="curl -s 'http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=blob_plain;f=arch/arm/include/asm/unistd.h;hb=HEAD' | ./mksysnum_linux.pl"
  2. src/pkg/syscall/mksyscall.pl:

    • -armオプションが追加され、64ビット引数のレジスタペア処理ロジックが導入されました。
    • 変更前:
      } elsif($type eq "int64" && $_32bit ne "") {
      	if($_32bit eq "big-endian") {
      		push @args, "uintptr($name>>32)", "uintptr($name)";
      	} else {
      
    • 変更後:
      } elsif($type eq "int64" && $_32bit ne "") {
      	if(@args % 2 && $arm) {
      		# arm abi specifies 64-bit argument uses 
      		# (even, odd) pair
      		push @args, "0"
      	}
      	if($_32bit eq "big-endian") {
      		push @args, "uintptr($name>>32)", "uintptr($name)";
      	} else {
      
  3. src/pkg/syscall/syscall_linux_arm.go:

    • 手動で実装されていたPread, Pwrite, Ftruncate, Truncate関数が削除されました。
    • これらの関数の定義が//sysディレクティブに置き換えられ、自動生成されるようになりました。
    • 変更前(抜粋):
      func Pread(fd int, p []byte, offset int64) (n int, err error) { ... }
      func Pwrite(fd int, p []byte, offset int64) (n int, err error) { ... }
      func Ftruncate(fd int, length int64) (err error) { ... }
      func Truncate(path string, length int64) (err error) { ... }
      
    • 変更後(抜粋):
      //sys   Pread(fd int, p []byte, offset int64) (n int, err error) = SYS_PREAD64
      //sys   Pwrite(fd int, p []byte, offset int64) (n int, err error) = SYS_PWRITE64
      //sys	Truncate(path string, length int64) (err error) = SYS_TRUNCATE64
      //sys	Ftruncate(fd int, length int64) (err error) = SYS_FTRUNCATE64
      
  4. src/pkg/syscall/zsyscall_linux_arm.go:

    • Fallocateシステムコールの引数順序が修正されました。
    • 変更前: _, _, e1 := Syscall6(SYS_FALLOCATE, uintptr(fd), uintptr(mode), uintptr(off>>32), uintptr(off), uintptr(len>>32), uintptr(len))
    • 変更後: _, _, e1 := Syscall6(SYS_FALLOCATE, uintptr(fd), uintptr(mode), uintptr(off), uintptr(off>>32), uintptr(len), uintptr(len>>32))
    • Teeシステムコールの戻り値の結合順序が修正されました。
    • 変更前: n = int64(int64(r0)<<32 | int64(r1))
    • 変更後: n = int64(int64(r1)<<32 | int64(r0))
    • 削除された手動実装のシステムコール(Pread, Pwrite, Truncate, Ftruncate)の自動生成されたコードが追加されました。
  5. src/pkg/syscall/zerrors_linux_arm.go:

    • 新しい定数(例: ETH_P_CAIF, F_GETPIPE_SZ, IP_FREEBINDなど)が追加され、一部の既存定数の値が更新されました。これは、asm/unistd.hの更新に伴う変更です。
  6. src/pkg/syscall/zsysnum_linux_arm.go:

    • 新しいシステムコール番号(例: SYS_RECVMMSG, SYS_FANOTIFY_INITなど)が追加されました。これもasm/unistd.hの更新に伴う変更です。
  7. src/pkg/syscall/ztypes_linux_arm.go:

    • 構造体CmsghdrInotifyEventの内部配列の型が[0]byteから[0]uint8に変更されました。
    • 定数IFLA_MAXの値が更新されました。

コアとなるコードの解説

src/pkg/syscall/mkall.shの変更

mkall.shは、Goのsyscallパッケージをビルドする際に、各OS/アーキテクチャ固有のファイルを生成するためのスクリプトです。Linux/ARMセクションにおけるmksysnumの変更は、システムコール番号の定義元をローカルの/usr/include/asm/unistd.hから、Linuxカーネルの公式Gitリポジトリ(git.kernel.org)から直接取得するように変更したものです。

--- a/src/pkg/syscall/mkall.sh
+++ b/src/pkg/syscall/mkall.sh
@@ -144,8 +144,8 @@ linux_amd64)
 	;;
 linux_arm)
 	mkerrors="$mkerrors"
-	mksyscall="./mksyscall.pl -b32"
-	mksysnum="./mksysnum_linux.pl /usr/include/asm/unistd.h"
+	mksyscall="./mksyscall.pl -l32 -arm"
+	mksysnum="curl -s 'http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=blob_plain;f=arch/arm/include/asm/unistd.h;hb=HEAD' | ./mksysnum_linux.pl"
 	mktypes="GOARCH=$GOARCH go tool cgo -godefs"
 	;;
 netbsd_386)

この変更により、Goのビルドシステムは、ユーザーのシステムに特定のカーネルヘッダーが存在するかどうかに依存することなく、常に最新かつ正確なシステムコール番号の定義を取得できるようになります。これは、異なるLinuxディストリビューションやARMデバイス間でのビルドの信頼性を向上させる上で非常に重要です。

src/pkg/syscall/mksyscall.plの変更

mksyscall.plは、Goのシステムコールラッパーを生成するPerlスクリプトです。このコミットの最も重要な変更点の一つは、ARMの64ビット引数渡し規約に対応するためのロジックの追加です。

--- a/src/pkg/syscall/mksyscall.pl
+++ b/src/pkg/syscall/mksyscall.pl
@@ -27,6 +27,7 @@ my $_32bit = "";
 my $plan9 = 0;
 my $openbsd = 0;
 my $netbsd = 0;
+my $arm = 0; # 64-bit value should use (even, odd)-pair
 
 if($ARGV[0] eq "-b32") {
 	$_32bit = "big-endian";
@@ -47,6 +48,10 @@ if($ARGV[0] eq "-netbsd") {
 	$netbsd = 1;
 	shift;
 }
+if($ARGV[0] eq "-arm") {
+	$arm = 1;
+	shift;
+}
 
 if($ARGV[0] =~ /^-/) {
 	print STDERR "usage: mksyscall.pl [-b32 | -l32] [file ...]\\n";
@@ -135,6 +140,11 @@ while(<>) {
 			push @args, "uintptr($name)";
 		}
 	} elsif($type eq "int64" && $_32bit ne "") {
+		if(@args % 2 && $arm) {
+			# arm abi specifies 64-bit argument uses 
+			# (even, odd) pair
+			push @args, "0"
+		}
 		if($_32bit eq "big-endian") {
 			push @args, "uintptr($name>>32)", "uintptr($name)";
 		} else {

追加された-armオプションと、int64型引数処理内のif(@args % 2 && $arm)ブロックが重要です。

  • @args % 2: 現在までにシステムコールに渡される引数の数が奇数であるかをチェックします。
  • $arm: -armオプションが指定されているか(つまり、ARMアーキテクチャ向けであるか)をチェックします。
  • この両方が真の場合、push @args, "0"によって0が引数リストに挿入されます。これは、ARM ABIが64ビット引数に「偶数-奇数」のレジスタペアを要求するため、引数のアライメントを調整するためのパディングです。これにより、次に続く64ビット引数が常に偶数番目のレジスタから始まるように保証され、ABIの規約に適合します。

src/pkg/syscall/syscall_linux_arm.goの変更

このファイルでは、以前手動で実装されていたPread, Pwrite, Ftruncate, Truncateといったシステムコールが削除され、代わりに//sysディレクティブを使用して自動生成されるように変更されました。

--- a/src/pkg/syscall/syscall_linux_arm.go
+++ b/src/pkg/syscall/syscall_linux_arm.go
@@ -4,8 +4,6 @@
 
 package syscall
 
-import "unsafe"
-
 func Getpagesize() int { return 4096 }
 
 func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
@@ -23,52 +21,6 @@ func NsecToTimeval(nsec int64) (tv Timeval) {
 	return
 }
 
-// Pread and Pwrite are special: they insert padding before the int64.
-
-func Pread(fd int, p []byte, offset int64) (n int, err error) { ... }
-func Pwrite(fd int, p []byte, offset int64) (n int, err error) { ... }
-func Ftruncate(fd int, length int64) (err error) { ... }
-func Truncate(path string, length int64) (err error) { ... }
-
 // Seek is defined in assembly.
 
 func Seek(fd int, offset int64, whence int) (newoffset int64, err error)
@@ -118,6 +70,11 @@ func Seek(fd int, offset int64, whence int) (newoffset int64, err error)
 //sysnb	Gettimeofday(tv *Timeval) (err error)
 //sysnb	Time(t *Time_t) (tt Time_t, err error)
 
+//sys   Pread(fd int, p []byte, offset int64) (n int, err error) = SYS_PREAD64
+//sys   Pwrite(fd int, p []byte, offset int64) (n int, err error) = SYS_PWRITE64
+//sys	Truncate(path string, length int64) (err error) = SYS_TRUNCATE64
+//sys	Ftruncate(fd int, length int64) (err error) = SYS_FTRUNCATE64
+
 //sys	mmap2(addr uintptr, length uintptr, prot int, flags int, fd int, pageOffset uintptr) (xaddr uintptr, err error)
 
 func mmap(addr uintptr, length uintptr, prot int, flags int, fd int, offset int64) (xaddr uintptr, err error) {

手動実装の削除と//sysディレクティブへの移行は、Goのシステムコール生成戦略における重要な改善です。これにより、mksyscall.plで行われたABI関連の修正がこれらのシステムコールにも自動的に適用され、手動でのエラーやABIの変更への追従漏れのリスクがなくなります。

src/pkg/syscall/zsyscall_linux_arm.goの変更

このファイルはmksyscall.plによって自動生成されるファイルです。このコミットでは、FallocateTeeシステムコールの引数渡しと戻り値の処理が修正されています。

Fallocateの引数順序の修正:

--- a/src/pkg/syscall/zsyscall_linux_arm.go
+++ b/src/pkg/syscall/zsyscall_linux_arm.go
@@ -287,7 +287,7 @@ func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) {
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
 func Fallocate(fd int, mode uint32, off int64, len int64) (err error) {
-	_, _, e1 := Syscall6(SYS_FALLOCATE, uintptr(fd), uintptr(mode), uintptr(off>>32), uintptr(off), uintptr(len>>32), uintptr(len))\n
+	_, _, e1 := Syscall6(SYS_FALLOCATE, uintptr(fd), uintptr(mode), uintptr(off), uintptr(off>>32), uintptr(len), uintptr(len>>32))\n
 	if e1 != 0 {
 		err = e1
 	}

offlenは64ビット整数であり、ARM ABIでは下位32ビットが偶数レジスタ、上位32ビットが奇数レジスタに配置されます。以前の実装ではuintptr(off>>32), uintptr(off)となっており、これは上位32ビットが先に渡され、その後に下位32ビットが渡されることを意味していました。この順序がuintptr(off), uintptr(off>>32)に修正されたことで、ABIの要件に合致し、fallocateが正しく動作するようになりました。

Teeの戻り値の結合順序の修正:

--- a/src/pkg/syscall/zsyscall_linux_arm.go
+++ b/src/pkg/syscall/zsyscall_linux_arm.go
@@ -784,7 +784,7 @@ func Sysinfo(info *Sysinfo_t) (err error) {
 
 func Tee(rfd int, wfd int, len int, flags int) (n int64, err error) {
 	r0, r1, e1 := Syscall6(SYS_TEE, uintptr(rfd), uintptr(wfd), uintptr(len), uintptr(flags), 0, 0)
-	n = int64(int64(r0)<<32 | int64(r1))\n
+	n = int64(int64(r1)<<32 | int64(r0))\n
 	if e1 != 0 {
 		err = e1
 	}

システムコールからの64ビット戻り値は、通常、r0r1レジスタに分割されて返されます。この修正は、r1(上位32ビット)とr0(下位32ビット)を正しい順序で結合して64ビット整数を再構築するためのものです。これにより、Teeシステムコールが正しい戻り値を返すようになります。

これらの変更は、GoのLinux/ARMシステムコール実装の正確性と堅牢性を大幅に向上させ、特に64ビット引数や戻り値の処理におけるABI準拠の問題を解決しました。

関連リンク

参考にした情報源リンク