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

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

このコミットは、Go言語のcmd/objdumpツールにおける、Plan 9システム上でのgoarch(ターゲットアーキテクチャ)の検出と設定に関する修正です。具体的には、objdumpがPlan 9形式のバイナリを解析する際に、デフォルトで386アーキテクチャを仮定していた問題を解決し、amd64armといった他のアーキテクチャのバイナリに対しても正確な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環境でもamd64armといった異なるアーキテクチャのGoバイナリが生成される可能性があります。objdumpが誤ったgoarchを仮定すると、バイナリ内の機械語コードの解釈が不正確になり、結果として誤った逆アセンブル結果や、pprofなどのツールでの解析エラーを引き起こす可能性がありました。

この変更の背景には、objdumpが異なるアーキテクチャのPlan 9バイナリに対しても正確な情報を提供できるようにし、Goツールチェーン全体の堅牢性と正確性を向上させるという目的があります。

前提知識の解説

  • cmd/objdump: Go言語の標準ツールチェーンに含まれるコマンドラインユーティリティで、go tool objdumpとして実行されます。その主な機能は、Goコンパイラによって生成された実行可能ファイルを逆アセンブルすることです。これは、GNU objdumpツールに似た機能を提供しますが、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 9 a.out形式に似た構造を持つことがあり、src/debug/plan9objパッケージは、この形式のオブジェクトファイルを読み取るための機能を提供します。この形式は、プログラムヘッダやシンボルテーブルなど、バイナリの構造を定義しています。
  • plan9obj.MagicAMD64, plan9obj.Magic386, plan9obj.MagicARM: これらはsrc/debug/plan9objパッケージ内で定義されている定数で、Plan 9 a.out形式のバイナリの「マジックナンバー」に対応します。マジックナンバーは、ファイルの先頭に記述される特定のバイト列で、ファイルの種類やフォーマットを識別するために使用されます。これらの定数は、それぞれamd64386armアーキテクチャ向けのPlan 9バイナリを識別するための値です。objdumpは、バイナリのマジックナンバーを読み取ることで、そのバイナリがどのアーキテクチャ向けにコンパイルされたかを判断します。

技術的詳細

このコミットの技術的な核心は、cmd/objdumpがPlan 9形式のGoバイナリを解析する際に、バイナリのマジックナンバーに基づいて正確なgoarchを動的に決定するように変更された点にあります。

以前の実装では、src/cmd/objdump/plan9obj.go内のplan9Symbols関数において、goarch変数が無条件に"386"に設定されていました。これは、Plan 9環境におけるGoの初期開発が主に32ビットx86アーキテクチャ(386)を対象としていたためと考えられます。

しかし、Goが他のアーキテクチャ(amd64armなど)もサポートするようになるにつれて、Plan 9環境でもこれらのアーキテクチャ向けのGoバイナリが生成されるようになりました。objdumpが常に386を仮定していると、amd64armのバイナリを正しく逆アセンブルできません。なぜなら、機械語命令のエンコーディングやレジスタの命名規則などがアーキテクチャによって異なるため、誤ったアーキテクチャを前提とすると、逆アセンブル結果が意味をなさなくなるからです。

このコミットでは、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が提供する逆アセンブル情報やシンボル情報が、対象バイナリの実際のアーキテクチャと一致するようになり、ツールの正確性が大幅に向上しました。

関連リンク

参考にした情報源リンク