[インデックス 18799] ファイルの概要
このコミットは、Go言語のリンカーであるliblink
におけるamd64p32
アーキテクチャでのmorestack
処理のバグ修正に関するものです。具体的には、src/liblink/obj6.c
ファイルが変更されています。
コミット
commit 9460cf78257fd8326827f1564da5da29b3bb8089
Author: Rémy Oudompheng <oudomphe@phare.normalesup.org>
Date: Fri Mar 7 19:44:35 2014 +0100
liblink: fix morestack handling on amd64p32.
It was using MOVL to pass a 64-bit argument
(concatenated framesize and argsize) to morestack11.
LGTM=dave, rsc
R=dave, rsc, iant
CC=golang-codereviews
https://golang.org/cl/72360044
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/9460cf78257fd8326827f1564da5da29b3bb8089
元コミット内容
liblink: fix morestack handling on amd64p32.
It was using MOVL to pass a 64-bit argument
(concatenated framesize and argsize) to morestack11.
LGTM=dave, rsc
R=dave, rsc, iant
CC=golang-codereviews
https://golang.org/cl/72360044
変更の背景
Go言語のランタイムには、ゴルーチンのスタックが不足した場合に動的にスタックを拡張するmorestack
というメカニズムがあります。このメカニズムは、関数呼び出しの前にスタックの残量を確認し、不足していればmorestack
関数を呼び出して新しいスタック領域を確保します。
このコミットの背景には、amd64p32
という特定のアーキテクチャにおけるmorestack
処理の実装上の問題がありました。amd64p32
は64ビットのCPUアーキテクチャでありながら、ポインタサイズが32ビットに制限されている特殊な環境です。
問題は、morestack11
という関数に引数を渡す際に、framesize
(フレームサイズ)とargsize
(引数サイズ)を連結した64ビットの値を渡す必要があったにもかかわらず、誤って32ビットのデータ転送命令であるMOVL
を使用していた点にあります。これにより、64ビットの引数が正しく渡されず、morestack
処理が正常に機能しない可能性がありました。このコミットは、この誤った命令の使用を修正し、amd64p32
環境でのmorestack
の信頼性を向上させることを目的としています。
前提知識の解説
Go言語のmorestack
関数
Go言語のゴルーチンは、初期スタックサイズが小さく設定されており、必要に応じて動的にスタックを拡張します。この動的なスタック拡張を担うのがmorestack
関数です。
- スタックオーバーフローチェック: Goコンパイラは、ほとんどの関数のエントリポイントにスタックオーバーフローチェックのプロローグを挿入します。これにより、現在のゴルーチンのスタックポインタが割り当てられた制限を超えていないかを確認します。
morestack
の呼び出し: スタック制限に達した場合、morestack
関数(またはruntime.morestack_noctxt
)がランタイムによって呼び出されます。- スタックの拡張:
morestack
が呼び出されると、ゴルーチンのスタック用に新しくより大きな連続したメモリブロックが割り当てられ、通常はサイズが倍増します。古いスタックの内容は新しいメモリ領域にコピーされ、ポインタも新しいアドレスを反映するように調整されます。
このメカニズムにより、Goプログラムは比較的小さな初期スタックを使用し、必要な場合にのみスタックを拡張することでメモリ使用量を最適化できます。
liblink
(Goリンカー)
liblink
はGo言語のリンカーであり、コンパイルされたGoパッケージ(オブジェクトファイル)をリンクして実行可能バイナリを生成するツールチェーンのコンポーネントです。morestack
メカニズムは、Goコンパイラによって生成され、liblink
によって処理およびリンクされる特定のアセンブリコードを含んでいます。
amd64p32
アーキテクチャ
amd64p32
は、x32 ABI
とも呼ばれる、64ビットのIntelおよびAMDハードウェア上で動作するアプリケーションバイナリインターフェース(ABI)です。このアーキテクチャは、x86-64命令セット(より多くのCPUレジスタ、改善された浮動小数点性能、より高速な位置独立コードなど)の利点を活用しながら、32ビットの整数、long
型、およびポインタ(ILP32)を使用します。
つまり、CPU自体は64ビットですが、メモリのアドレス指定には32ビットのポインタが使用されます。これは、特定の組み込みシステムや、メモリアドレス指定が互換性やリソースの制約のために32ビットに制限されている環境で使用されることがあります。
amd64p32
の呼び出し規約は、主にSystem V AMD64 ABIに従いますが、ポインタとlong
型のサイズが32ビットである点が主な違いです。
MOVL
とMOVQ
アセンブリ命令
x86アセンブリにおいて、MOVL
とMOVQ
はどちらもデータ転送命令ですが、操作するデータのサイズが異なります。
-
MOVL
(Move Long):- 「ロングワード」を移動するために使用され、**32ビット(4バイト)**のデータに対応します。
- 通常、32ビットレジスタ(
EAX
,EBX
,ECX
,EDX
など)または32ビットメモリ位置を扱う際に使用されます。
-
MOVQ
(Move Quadword):- 「クアッドワード」を移動するために使用され、**64ビット(8バイト)**のデータに対応します。
- 主に64ビット環境(x86-64)で、64ビットレジスタ(
RAX
,RBX
,RCX
,RDX
など)または64ビットメモリ位置を操作するために使用されます。
AMOVQ
は標準的なx86命令ニーモニックではありませんが、これはMOVQ
を指している可能性が高いです。MOV
命令のサフィックス(L
はロング、Q
はクアッドワード)は、転送されるデータのサイズを明示的に示します。
技術的詳細
このコミットの技術的な問題は、amd64p32
アーキテクチャにおいて、morestack11
関数に渡される引数のサイズと、その引数を転送するために使用されるアセンブリ命令の不一致にありました。
morestack11
関数は、framesize
(現在のスタックフレームのサイズ)とargsize
(関数に渡される引数の合計サイズ)を連結した64ビットの単一の引数を受け取ります。この64ビットの値は、スタックの拡張に必要な情報をmorestack
ランタイムに提供するために重要です。
しかし、元のコードでは、この64ビットの引数を転送するためにMOVL
命令が使用されていました。MOVL
は32ビットのデータを扱う命令であるため、64ビットの値を正しく転送することができません。これにより、morestack11
関数は不完全または誤った引数を受け取り、結果としてスタックの拡張処理が失敗したり、予期せぬ動作を引き起こしたりする可能性がありました。
この修正は、MOVL
をAMOVQ
(実質的にはMOVQ
)に置き換えることで、この問題を解決します。MOVQ
は64ビットのデータを転送するための命令であるため、framesize
とargsize
を連結した64ビットの引数がmorestack11
に正しく渡されるようになります。これにより、amd64p32
環境におけるGoランタイムのスタック管理の堅牢性が向上します。
コアとなるコードの変更箇所
--- a/src/liblink/obj6.c
+++ b/src/liblink/obj6.c
@@ -862,7 +862,8 @@ stacksplit(Link *ctxt, Prog *p, int32 framesize, int32 textarg, int noctxt, Prog
p->to.type = D_BRANCH;
p->to.sym = ctxt->symmorestack[2*2+noctxt];
} else {
- p->as = mov;
+ // Pass framesize and argsize.
+ p->as = AMOVQ;
p->from.type = D_CONST;
p->from.offset = (uint64)moreconst2 << 32;
p->from.offset |= moreconst1;
コアとなるコードの解説
変更はsrc/liblink/obj6.c
ファイルのstacksplit
関数内で行われています。この関数は、Goのリンカーがスタック分割チェック(morestack
へのジャンプ)を生成する際に関連するコードです。
元のコードでは、以下の行がありました。
p->as = mov;
ここでmov
は、アセンブリ命令の種類を示す変数であり、このコンテキストでは32ビットのデータ転送を意味するMOVL
に解決されていました。
修正後のコードでは、この行が以下のように変更されています。
// Pass framesize and argsize.
p->as = AMOVQ;
// Pass framesize and argsize.
:このコメントは、この命令がframesize
とargsize
という2つの重要な情報をmorestack11
関数に渡すためのものであることを明確に示しています。p->as = AMOVQ;
:この行が修正の核心です。mov
(MOVL
)をAMOVQ
に置き換えることで、生成されるアセンブリ命令が32ビットのデータ転送から64ビットのデータ転送に変わります。これにより、p->from.offset
に格納されているframesize
とargsize
を連結した64ビットの値が、正しくmorestack11
関数に引数として渡されるようになります。
p->from.offset = (uint64)moreconst2 << 32; p->from.offset |= moreconst1;
の行は、framesize
とargsize
を連結して64ビットの定数を作成している部分です。moreconst2
が上位32ビット、moreconst1
が下位32ビットを構成し、これらを結合して単一の64ビット値として扱っています。この64ビット値を正しく転送するためにAMOVQ
が必要でした。
この変更により、amd64p32
環境でGoプログラムがスタックを動的に拡張する際の信頼性が確保され、潜在的なランタイムエラーやクラッシュが防止されます。
関連リンク
- Go CL 72360044: https://golang.org/cl/72360044
参考にした情報源リンク
- Go
morestack
function: https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQFcxxruBulH7SqzCB1678Icvxsvre6xWfITtIp7opyjSgj4ngzCsTKbJKw1d1AVcCtAIgdXJo1rGn2zMpqB18n4A7-8MASPV4tXvZYnV3GHhQ5wPCI6rn8C_YQRiN_33KeOFF0MYVQpWtPmndYpLgM3WvsVPQ== - Go
morestack
function (studyraid.com): https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQGF43que1PqJBDFYdm_Cld6qfawI5z8-VHD71D-bk3ESjk5lpTlFhqgxSwvaFuTskM1pXmrgsYm43AYmGj3z3tteDSuS0yqsOsZYVED6ODD1pbY-qQaCWMjAtoGERthh-aDJ4MYGhFtIZwVVgUi-uIKaZrk_wGf8QkF0ZSLfVhsywChJ8Rz amd64p32
architecture calling convention (Wikipedia): https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQFuumW3MYVFBX6fbcTvX2yG0CJ8a7Riwh4x0dJQ9W8vUIx2_Fk6uOTk5eYUDkDd9fJC2x8ZEVQDGwzzA6Z5sPKoUU-b4heIuus_kmb5dPs5kbBjZRrjdbbDpMRiQLHngPg==MOVL
vsMOVQ
x86 assembly (Oracle): https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQHHKVjPN86txnRy3UC62EVCuHskicVltzvRn49rJ4Su7CvnB-WLoFqIwk2xjHhn0AwL3I04GAaNPeschF5KMohSQOweaJ8s-VllprfU9jpI6flwletXtOEEnJfM4vtkNcZmgRIx7811gpOH8-OreB56z8uQ-YRnlPX_yjXW59R0oZQgy01FXg==MOVL
vsMOVQ
x86 assembly (Stack Overflow): https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQHm62zRGXtyroC_o8fg3W9G-s1qbvvJsboJBrkAGrQBm63J_5RUr8jDa1-OPMx9pWyXGQOFk5hOJYsPTfQwLwTKRoDOrU-8RYUZh26iCEunmsURE3uWpU5W2U-PbFtlJS_4fsigFMSBRVzbqjK24XsbeoFt2DI0g3fPQ5JnEKS0U2MJ8Ibur9aEybm4nX4J0fpNFsg7G9LzgwYaXNEie7VL5TzYTRwQm0mhp1W8TLo3F7NJBjD8cg==