[インデックス 19693] ファイルの概要
このコミットは、Go言語のcmd/objdump
ツールにおける、Plan 9システム上でのgoarch
(ターゲットアーキテクチャ)の検出と設定に関する修正です。具体的には、objdump
がPlan 9形式のバイナリを解析する際に、デフォルトで386
アーキテクチャを仮定していた問題を解決し、amd64
やarm
といった他のアーキテクチャのバイナリに対しても正確なgoarch
を設定できるように改善しています。これにより、Plan 9環境で生成されたGoバイナリの逆アセンブルが、より正確に行われるようになります。
コミット
cmd/objdump: set goarch properly on non-386 Plan 9 systems
LGTM=0intro, r
R=0intro, r
CC=ality, golang-codereviews, jas, mischief
https://golang.org/cl/108420043
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/fa113cf767ac330b836966c4e75b6b21566da095
元コミット内容
cmd/objdump: set goarch properly on non-386 Plan 9 systems
このコミットは、cmd/objdump
ツールがPlan 9システム上で動作する際に、goarch
(Goのターゲットアーキテクチャ)を適切に設定するように修正することを目的としています。特に、386
以外のアーキテクチャ(例: amd64
, arm
)でコンパイルされたPlan 9バイナリに対して、objdump
が正しいアーキテクチャを認識できるように改善します。
変更の背景
Go言語のツールチェーンには、Goバイナリを逆アセンブルするためのgo tool objdump
というユーティリティが含まれています。このツールは、主にGoのプロファイリングツールであるpprof
が、実行中のGoプログラムのスタックトレースやCPUプロファイルを解析する際に、シンボル情報と機械語コードを関連付けるために利用されます。
objdump
は、Goバイナリの構造を解析するために、src/debug/plan9obj
パッケージが提供するPlan 9 a.out
オブジェクトファイル形式のパーサーを利用しています。Plan 9 a.out
は、Goの初期段階で利用されていた実行可能ファイル形式であり、その名残がGoのツールチェーンの一部に残っています。
このコミット以前のcmd/objdump
は、Plan 9システム上でGoバイナリを解析する際、goarch
の値を一律に386
と仮定していました。しかし、Plan 9環境でもamd64
やarm
といった異なるアーキテクチャのGoバイナリが生成される可能性があります。objdump
が誤ったgoarch
を仮定すると、バイナリ内の機械語コードの解釈が不正確になり、結果として誤った逆アセンブル結果や、pprof
などのツールでの解析エラーを引き起こす可能性がありました。
この変更の背景には、objdump
が異なるアーキテクチャのPlan 9バイナリに対しても正確な情報を提供できるようにし、Goツールチェーン全体の堅牢性と正確性を向上させるという目的があります。
前提知識の解説
cmd/objdump
: Go言語の標準ツールチェーンに含まれるコマンドラインユーティリティで、go tool objdump
として実行されます。その主な機能は、Goコンパイラによって生成された実行可能ファイルを逆アセンブルすることです。これは、GNUobjdump
ツールに似た機能を提供しますが、Goのプロファイリングツール(pprof
)をサポートするために特化しています。バイナリ内の関数(テキストシンボル)の機械語コードを表示し、ソースファイルと行番号、メモリアドレス、対応するアセンブリ命令などの情報を提供します。goarch
: Go言語の環境変数の一つで、Goプログラムがコンパイルされるターゲットプロセッサアーキテクチャを指定します。例えば、amd64
(64ビットx86)、arm64
(64ビットARM)、386
(32ビットx86)などがあります。GOOS
(ターゲットオペレーティングシステム)と組み合わせて、クロスコンパイル(異なるOSやアーキテクチャ向けのバイナリを生成すること)を可能にします。objdump
がバイナリを解析する際には、このgoarch
の値が、機械語命令の解釈や実行可能ファイルのレイアウトを正しく理解するために不可欠です。- Plan 9
a.out
オブジェクトファイル形式: Plan 9は、ベル研究所で開発された分散オペレーティングシステムです。その実行可能ファイル形式であるa.out
は、Go言語の初期のツールチェーンで利用されていました。Goのバイナリは、このPlan 9a.out
形式に似た構造を持つことがあり、src/debug/plan9obj
パッケージは、この形式のオブジェクトファイルを読み取るための機能を提供します。この形式は、プログラムヘッダやシンボルテーブルなど、バイナリの構造を定義しています。 plan9obj.MagicAMD64
,plan9obj.Magic386
,plan9obj.MagicARM
: これらはsrc/debug/plan9obj
パッケージ内で定義されている定数で、Plan 9a.out
形式のバイナリの「マジックナンバー」に対応します。マジックナンバーは、ファイルの先頭に記述される特定のバイト列で、ファイルの種類やフォーマットを識別するために使用されます。これらの定数は、それぞれamd64
、386
、arm
アーキテクチャ向けのPlan 9バイナリを識別するための値です。objdump
は、バイナリのマジックナンバーを読み取ることで、そのバイナリがどのアーキテクチャ向けにコンパイルされたかを判断します。
技術的詳細
このコミットの技術的な核心は、cmd/objdump
がPlan 9形式のGoバイナリを解析する際に、バイナリのマジックナンバーに基づいて正確なgoarch
を動的に決定するように変更された点にあります。
以前の実装では、src/cmd/objdump/plan9obj.go
内のplan9Symbols
関数において、goarch
変数が無条件に"386"
に設定されていました。これは、Plan 9環境におけるGoの初期開発が主に32ビットx86アーキテクチャ(386
)を対象としていたためと考えられます。
しかし、Goが他のアーキテクチャ(amd64
やarm
など)もサポートするようになるにつれて、Plan 9環境でもこれらのアーキテクチャ向けのGoバイナリが生成されるようになりました。objdump
が常に386
を仮定していると、amd64
やarm
のバイナリを正しく逆アセンブルできません。なぜなら、機械語命令のエンコーディングやレジスタの命名規則などがアーキテクチャによって異なるため、誤ったアーキテクチャを前提とすると、逆アセンブル結果が意味をなさなくなるからです。
このコミットでは、plan9Symbols
関数内で、読み込んだPlan 9オブジェクトファイルのマジックナンバー(p.Magic
)をswitch
文で評価するように変更されました。
plan9obj.MagicAMD64
であればgoarch
を"amd64"
に設定。plan9obj.Magic386
であればgoarch
を"386"
に設定。plan9obj.MagicARM
であればgoarch
を"arm"
に設定。
これにより、objdump
は、解析対象のPlan 9バイナリが実際にどのアーキテクチャ向けにコンパイルされたかを正確に識別し、それに応じたgoarch
を設定できるようになりました。この正確なgoarch
情報に基づいて、後続の逆アセンブル処理が実行されるため、異なるアーキテクチャのPlan 9バイナリに対しても正しい逆アセンブル結果が得られるようになります。
この変更は、Goツールチェーンのクロスプラットフォーム対応と、デバッグ・プロファイリングツールの正確性を向上させる上で重要な修正です。
コアとなるコードの変更箇所
--- a/src/cmd/objdump/plan9obj.go
+++ b/src/cmd/objdump/plan9obj.go
@@ -34,7 +34,14 @@ func plan9Symbols(f *os.File) (syms []Sym, goarch string) {
return
}\n
- goarch = "386"
+ switch p.Magic {
+ case plan9obj.MagicAMD64:
+ goarch = "amd64"
+ case plan9obj.Magic386:
+ goarch = "386"
+ case plan9obj.MagicARM:
+ goarch = "arm"
+ }
// Build sorted list of addresses of all symbols.
// We infer the size of a symbol by looking at where the next symbol begins.
コアとなるコードの解説
変更はsrc/cmd/objdump/plan9obj.go
ファイルのplan9Symbols
関数内で行われています。
元のコードでは、以下の行がありました。
goarch = "386"
これは、plan9Symbols
関数が返すgoarch
の値を、読み込んだPlan 9オブジェクトファイルの種類に関わらず、常に"386"
(32ビットx86アーキテクチャ)に固定していました。
修正後のコードでは、この固定値を削除し、代わりにswitch
文が導入されています。
switch p.Magic {
case plan9obj.MagicAMD64:
goarch = "amd64"
case plan9obj.Magic386:
goarch = "386"
case plan9obj.MagicARM:
goarch = "arm"
}
p
は、plan9obj.File
型の変数であり、読み込んだPlan 9オブジェクトファイルを表します。p.Magic
は、そのオブジェクトファイルのマジックナンバー(ファイルの種類を識別する値)を保持しています。switch
文は、p.Magic
の値に基づいて異なるケースを処理します。case plan9obj.MagicAMD64:
: もしマジックナンバーがamd64
アーキテクチャのPlan 9バイナリを示すものであれば、goarch
を"amd64"
に設定します。case plan9obj.Magic386:
: もしマジックナンバーが386
アーキテクチャのPlan 9バイナリを示すものであれば、goarch
を"386"
に設定します。これは以前のデフォルト値と同じですが、明示的にマジックナンバーに基づいて設定されるようになりました。case plan9obj.MagicARM:
: もしマジックナンバーがarm
アーキテクチャのPlan 9バイナリを示すものであれば、goarch
を"arm"
に設定します。
この変更により、objdump
は、解析対象のPlan 9バイナリがどのCPUアーキテクチャ向けにコンパイルされたかを、ファイル自身が持つ情報(マジックナンバー)から正確に判断し、それに応じたgoarch
を設定できるようになりました。これにより、objdump
が提供する逆アセンブル情報やシンボル情報が、対象バイナリの実際のアーキテクチャと一致するようになり、ツールの正確性が大幅に向上しました。
関連リンク
- Go
cmd/objdump
documentation: https://pkg.go.dev/cmd/objdump - Go
debug/plan9obj
package: https://pkg.go.dev/debug/plan9obj - Go
GOARCH
environment variable: https://go.dev/doc/install/source#environment
参考にした情報源リンク
- https://pkg.go.dev/cmd/objdump
- https://pkg.go.dev/debug/plan9obj
- https://go.dev/doc/install/source#environment
- https://github.com/golang/go/commit/fa113cf767ac330b836966c4e75b6b21566da095
- Google Web Search results for "Go cmd/objdump plan9obj.go goarch" (as provided by the tool)