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

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

このコミットは、src/pkg/syscall/asm_linux_arm.s ファイルに対する変更です。このファイルは、Linux ARMアーキテクチャ向けのシステムコールを実装するためのGoアセンブリコードを含んでいます。

コミット

  • コミットハッシュ: ae6cbd4fcf35471996c35018ec0ff908c0a59728
  • Author: Dave Cheney dave@cheney.net
  • Date: Sat May 17 00:06:56 2014 +0000

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

https://github.com/golang/go/commit/ae6cbd4fcf35471996c35018ec0ff908c0a59728

元コミット内容

syscall: fix arm build

Rename Seek to seek in asm file, was overlooked in CL 99320043.

LGTM=bradfitz, r
R=r, rsc, bradfitz
CC=golang-codereviews
https://golang.org/cl/99320044

変更の背景

このコミットは、GoのsyscallパッケージにおけるARMアーキテクチャ向けのビルド問題を修正するためのものです。具体的には、以前の変更(コミットメッセージで「CL 99320043」と参照されているもの)で、Seekというシンボル名がGoアセンブリファイル内で正しく処理されず、ARMビルドが失敗する問題が発生しました。

Goのリンカやアセンブラは、シンボル名の大文字・小文字を区別する場合があります。この場合、Goのソースコードで定義された関数名と、アセンブリコード内で参照されるシンボル名との間で、大文字・小文字の不一致があったことが原因と考えられます。Seekという関数が、アセンブリコード内ではseekという小文字で参照されるべきであったにもかかわらず、大文字のSeekとして記述されていたため、リンカがシンボルを解決できずにビルドエラーを引き起こしていました。

このコミットは、この大文字・小文字の不一致を修正し、ARM環境でのsyscallパッケージのビルドを再び成功させることを目的としています。

前提知識の解説

このコミットを理解するためには、以下の概念について知っておく必要があります。

  • Goのシステムコール (syscall): Goプログラムがオペレーティングシステム(OS)の機能(ファイル操作、ネットワーク通信など)にアクセスするためのインターフェースを提供するパッケージです。OSの機能は通常、システムコールを通じて利用されます。
  • ARMアーキテクチャ: スマートフォン、タブレット、組み込みシステムなどで広く使用されているCPUアーキテクチャです。Goは様々なアーキテクチャをサポートしており、ARMもその一つです。
  • Goアセンブリ (Plan 9 Assembly): Go言語は、特定の低レベルな処理やパフォーマンスが重要な部分で、Goアセンブリと呼ばれる独自のアセンブリ言語を使用します。これは一般的なx86アセンブリとは異なる構文を持ち、Plan 9アセンブリをベースにしています。Goアセンブリファイルは通常 .s 拡張子を持ちます。
  • シンボル (Symbol): プログラム内で関数、変数、ラベルなどを識別するための名前です。コンパイラやリンカはこれらのシンボル名を使って、コード内の参照を実際のメモリ位置に解決します。
  • TEXT ディレクティブ: Goアセンブリにおいて、関数の開始を宣言するために使用されます。TEXT funcname(SB), flags, framesize-argsize の形式で記述されます。
    • funcname: Goの関数名。
    • SB (Static Base): グローバルシンボルや外部シンボルを参照するための擬似レジスタ。通常、関数名はfuncname(SB)のように記述され、グローバルスコープのシンボルであることを示します。
    • NOSPLIT: この関数がスタックを分割しないことを示すフラグ。通常、小さな関数やシステムコールラッパーなどで使用されます。
    • framesize-argsize: スタックフレームのサイズと引数のサイズを示します。
  • レジスタ: CPU内部にある高速な記憶領域で、演算やデータ転送に使用されます。ARMアーキテクチャでは、R0, R7などが汎用レジスタとして使われます。
    • R0: 関数呼び出しの最初の引数や戻り値を格納するためによく使われます。
    • R7: Linux ARMのシステムコールでは、システムコール番号を格納するためによく使われます。
  • MOVW 命令: ARMアセンブリにおけるデータ転送命令の一つで、ワード(32ビット)データをレジスタに移動させます。
  • BL 命令: Branch with Linkの略で、関数呼び出しに使用されます。呼び出し元の次の命令のアドレスをリンクレジスタ(LR)に保存し、指定されたアドレスにジャンプします。
  • runtime·entersyscall(SB): Goランタイムが提供する関数で、Goのスケジューラがシステムコールに入る前に呼び出されます。これにより、ガベージコレクタが安全に動作できるよう、Goルーチンがシステムコール中にブロックされていることをランタイムに通知します。
  • SYS__LLSEEK: Linuxシステムコールllseekのシステムコール番号を表す定数です。llseekは、大きなファイル(2GB以上)のオフセットを操作するためのシステムコールです。
  • llseek システムコール: ファイルディスクリプタの読み書きオフセットを変更するために使用されるシステムコールです。lseekの64ビット版です。
  • Goのビルドプロセス: Goのソースコードは、コンパイラによってオブジェクトファイルに変換され、その後リンカによって実行可能ファイルにリンクされます。この過程で、Goアセンブリファイルもコンパイルされ、他のオブジェクトファイルと結合されます。シンボル解決はリンカの重要な役割の一つです。

技術的詳細

このコミットの技術的な詳細は、Goアセンブリにおけるシンボル名の解決と、ARMアーキテクチャ特有のシステムコール呼び出し規約にあります。

Goのsyscallパッケージは、OSのシステムコールをGoプログラムから呼び出すためのラッパー関数を提供します。これらのラッパー関数の一部は、パフォーマンスや低レベルな制御のためにGoアセンブリで直接実装されています。

問題の核心は、src/pkg/syscall/asm_linux_arm.sファイル内で定義されているSeek関数のシンボル名にありました。Goのソースコード(おそらくsyscallパッケージ内のGoファイル)では、Seekという名前で関数が定義されていたと推測されます。しかし、ARMアセンブリファイル内では、この関数をTEXT ·Seek(SB)として定義していました。

Goのツールチェーン(特にリンカ)は、Goのソースコードから生成されたオブジェクトファイルとアセンブリから生成されたオブジェクトファイルをリンクする際に、シンボル名を解決します。この際、特定の環境やツールチェーンのバージョンにおいて、シンボル名の大文字・小文字の区別が厳密に適用されることがあります。

このケースでは、Seekという大文字で始まるシンボル名が、Goのリンカが期待する小文字で始まるseekというシンボル名と一致しなかったため、リンカがSeek関数を見つけられず、ビルドエラーが発生しました。これは、Goの内部的な命名規則や、特定のシステムコールラッパーの慣習に起因する可能性があります。例えば、Goの内部では、エクスポートされない関数やアセンブリで実装される関数は小文字で始まる慣習がある場合があります。

修正は非常に単純で、TEXT ·Seek(SB)TEXT ·seek(SB)にリネームすることでした。これにより、アセンブリファイル内のシンボル名がGoのリンカが期待する形式と一致し、シンボル解決が成功し、ARM環境でのビルドが可能になりました。

この問題は、以前の変更(CL 99320043)で導入されたもので、その変更がSeek関数のアセンブリ実装に影響を与えたか、あるいはその変更によって既存の命名規則との不一致が顕在化したと考えられます。

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

--- a/src/pkg/syscall/asm_linux_arm.s
+++ b/src/pkg/syscall/asm_linux_arm.s
@@ -103,7 +103,7 @@ ok2:
 // taking the address of the return value newoffset.
 // Underlying system call is
 //	llseek(int fd, int offhi, int offlo, int64 *result, int whence)
-TEXT ·Seek(SB),NOSPLIT,$0-32
+TEXT ·seek(SB),NOSPLIT,$0-32
 	BL	runtime·entersyscall(SB)
 	MOVW	$SYS__LLSEEK, R7	// syscall entry
 	MOVW	4(SP), R0	// fd

コアとなるコードの解説

変更はsrc/pkg/syscall/asm_linux_arm.sファイルの1行のみです。

  • 変更前: TEXT ·Seek(SB),NOSPLIT,$0-32
    • ここでは、Seekという大文字で始まるシンボル名で関数が定義されていました。
  • 変更後: TEXT ·seek(SB),NOSPLIT,$0-32
    • Seekseekという小文字で始まるシンボル名に修正されました。

この変更により、GoのリンカがGoのソースコードから参照されるseek関数と、このアセンブリファイルで定義されているseekシンボルを正しくマッチングできるようになりました。

このアセンブリコードブロックの目的は、Linux ARM環境でllseekシステムコールを呼び出すためのGoラッパー関数を実装することです。

  • BL runtime·entersyscall(SB): システムコールに入る前にGoランタイムのentersyscall関数を呼び出します。これはGoスケジューラの整合性を保つために重要です。
  • MOVW $SYS__LLSEEK, R7: llseekシステムコールの番号(SYS__LLSEEK)をレジスタR7にロードします。Linux ARMのシステムコール規約では、システムコール番号はR7に置かれます。
  • MOVW 4(SP), R0: スタックポインタSPから4バイトオフセットした位置にある値(これはfd、つまりファイルディスクリプタの引数に相当します)をレジスタR0にロードします。R0は通常、最初の引数を保持します。

このコミットは、機能的な変更ではなく、ビルドシステムにおけるシンボル解決の問題を修正するものであり、Goのクロスコンパイルとアセンブリ言語の相互作用における細かな注意点を示しています。

関連リンク

参考にした情報源リンク

  • Go Assembly Language (Plan 9 Assembly): https://go.dev/doc/asm (一般的なGoアセンブリのドキュメント)
  • Linux ARM System Call Convention (一般的なARMシステムコール規約に関する情報源、特定のリンクは提供できないが、この知識は広く利用可能)