[インデックス 19359] ファイルの概要
このコミットは、Go言語のツールチェインに含まれるnm
コマンドとobjdump
コマンドにおけるELF(Executable and Linkable Format)ファイルのシンボル型解析のバグ修正、およびobjdump
の逆アセンブル処理における境界チェックの改善を目的としています。特に、elf.File.Sections
のインデックス処理の誤りを修正し、テキストセグメント外の逆アセンブル要求によるクラッシュを防ぐ堅牢性向上が図られています。
コミット
commit 8e22903b46aadd6eda937417cba86b528cba92e2
Author: Russ Cox <rsc@golang.org>
Date: Wed May 14 17:45:13 2014 -0700
cmd/nm, cmd/objdump: fix elf symbol types
Turns out elf.File.Sections is indexed by the actual
section number, not the number minus one.
I don't know why I thought the -1 was necessary.
Fixes objdump test (and therefore build) on ELF systems.
While we're here, fix bounds on gnuDump so that we
don't crash when asked to disassemble outside
the text segment. May fix Windows build or at least
make the failure more interesting.
TBR=iant
CC=golang-codereviews
https://golang.org/cl/92390043
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/8e22903b46aadd6eda937417cba86b528cba92e2
元コミット内容
cmd/nm, cmd/objdump: fix elf symbol types
Turns out elf.File.Sections is indexed by the actual
section number, not the number minus one.
I don't know why I thought the -1 was necessary.
Fixes objdump test (and therefore build) on ELF systems.
While we're here, fix bounds on gnuDump so that we
don't crash when asked to disassemble outside
the text segment. May fix Windows build or at least
make the failure more interesting.
TBR=iant
CC=golang-codereviews
https://golang.org/cl/92390043
変更の背景
このコミットは主に2つの問題に対処しています。
- ELFセクションインデックスの誤り: Goの
elf
パッケージが提供するelf.File.Sections
は、ELFファイルのセクションヘッダテーブルを表します。ELF仕様ではセクション番号は1から始まる(0は未定義セクション)ため、このスライスは実際のセクション番号で直接インデックスされるべきでした。しかし、これまでの実装では誤ってi-1
のようにオフセットを適用しており、これがシンボル型を正しく識別できない原因となっていました。このバグは特にELFシステム上でのobjdump
のテスト失敗を引き起こしていました。 objdump
における逆アセンブル範囲の堅牢性不足:objdump
コマンドのgnuDump
関数は、逆アセンブルを行う際に指定されたアドレス範囲が実行可能ファイルのテキストセグメント(コードが配置される領域)の境界を越える場合に、クラッシュする可能性がありました。これは、無効なアドレス範囲が指定された場合にプログラムが予期せぬ動作をする脆弱性を示していました。この修正は、特にWindowsのようなシステムでのビルドの安定性向上、または問題発生時のデバッグ情報の改善に寄与します。
これらの問題は、Goツールチェインの安定性と正確性に影響を与えるものであり、特にクロスコンパイルや異なるOS環境でのツール利用において重要でした。
前提知識の解説
ELF (Executable and Linkable Format)
ELFは、Unix系OS(Linux、BSDなど)で広く使用されている実行可能ファイル、オブジェクトコード、共有ライブラリ、コアダンプファイルの標準フォーマットです。プログラムの実行に必要な情報(コード、データ、シンボルテーブル、セクション情報など)を構造化して格納します。
- セクション (Sections): ELFファイルは複数のセクションに分割されます。各セクションは特定の種類のデータ(例:
.text
は実行可能コード、.data
は初期化済みデータ、.bss
は初期化されていないデータ、.symtab
はシンボルテーブルなど)を格納します。 - セクションヘッダテーブル (Section Header Table): ファイル内の各セクションに関する情報(名前、種類、サイズ、ファイルオフセット、メモリ上のアドレス、フラグなど)を記述したテーブルです。
- シンボル (Symbols): プログラム内の関数や変数などの名前と、それらがメモリ上のどこに配置されているか(アドレス)を関連付ける情報です。シンボルは、リンカが異なるオブジェクトファイルを結合したり、デバッガがソースコードと実行中のプログラムを関連付けたりするために使用されます。
- シンボルテーブル (Symbol Table): シンボル情報のリストです。各エントリはシンボルの名前、値(アドレス)、サイズ、型(関数、オブジェクトなど)、および関連するセクションインデックスなどを含みます。
nm
コマンド
nm
(name mangler)は、オブジェクトファイル、静的ライブラリ、または実行可能ファイル内のシンボル(関数名、変数名など)をリスト表示するためのUnix系コマンドです。シンボルの種類(例: T
はテキストセクションの関数、B
はBSSセクションの変数、D
はデータセクションの変数など)も表示します。
objdump
コマンド
objdump
は、オブジェクトファイルや実行可能ファイルに関する様々な情報を表示するためのUnix系コマンドです。主な機能には、逆アセンブル(機械語コードをアセンブリ言語に変換)、セクションヘッダの表示、シンボルテーブルの表示などがあります。このコミットでは、特に逆アセンブル機能(gnuDump
関数に関連)とシンボル型解析が関係しています。
Goのelf
パッケージ
Go標準ライブラリのdebug/elf
パッケージは、GoプログラムからELFファイルを読み込み、解析するための機能を提供します。このパッケージは、ELFヘッダ、プログラムヘッダ、セクションヘッダ、シンボルテーブルなどの構造をGoの型として定義し、それらの情報にアクセスするためのメソッドを提供します。
elf.File.Sections
: ELFファイルのセクションヘッダテーブルを表すスライスです。このスライスのインデックスが、ELF仕様におけるセクション番号とどのように対応するかが、今回のバグの核心でした。
技術的詳細
ELFセクションインデックスの修正
元のコードでは、elf.File.Sections
スライスにアクセスする際に、シンボルが属するセクションのインデックスi
から1
を引いていました(p.Sections[i-1]
)。これは、スライスが0-ベースのインデックスを持つという一般的なプログラミングの慣習に基づいていた可能性があります。しかし、ELF仕様においてセクション番号は1から始まるため、elf.File.Sections
は実際のセクション番号を直接インデックスとして使用するように設計されていました。
例えば、ELFファイルでセクション番号1が.text
セクションを指す場合、elf.File.Sections[1]
がそのセクション情報を含むべきです。しかし、p.Sections[i-1]
というコードでは、セクション番号1のシンボルに対してp.Sections[0]
にアクセスしてしまい、誤ったセクション情報(または存在しないセクション)を参照していました。
この修正により、i-1
がi
に修正され、p.Sections[i]
と直接アクセスすることで、シンボルが実際に属するセクションの情報を正しく取得できるようになりました。これにより、nm
とobjdump
がシンボルの種類(例: コードセクションのシンボルはT
、データセクションのシンボルはD
など)を正確に判別できるようになります。
また、インデックスの境界チェックもi <= 0 || i > len(p.Sections)
からi < 0 || i >= len(p.Sections)
に変更されました。これは、Goのスライスインデックスの慣習(0からlen-1
まで)に合わせたもので、i
が0の場合(ELFのSHN_UNDEF
など、未定義セクションを示す特殊な値)や、スライスの範囲外にアクセスしようとした場合のパニックを防ぎます。
objdump
における逆アセンブル範囲の堅牢性向上
src/cmd/objdump/main.go
のgnuDump
関数では、逆アセンブルの開始アドレス(start
)と終了アドレス(end
)が、実行可能ファイルのテキストセグメント(textStart
からtextStart + len(textData)
まで)の範囲内に収まるように調整するロジックが追加されました。
if start < textStart { start = textStart }
: 指定された開始アドレスがテキストセグメントの開始アドレスよりも小さい場合、テキストセグメントの開始アドレスに調整します。これにより、テキストセグメントより前のメモリ領域を逆アセンブルしようとする試みを防ぎます。if end < start { end = start }
: 終了アドレスが開始アドレスよりも小さい場合、終了アドレスを開始アドレスに調整します。これは、無効な範囲指定(例: 終了アドレスが開始アドレスより前)を正規化し、空の範囲として扱います。if end > textStart+uint64(len(textData)) { end = textStart + uint64(len(textData)) }
: 指定された終了アドレスがテキストセグメントの終了アドレスよりも大きい場合、テキストセグメントの終了アドレスに調整します。これにより、テキストセグメントより後のメモリ領域を逆アセンブルしようとする試みを防ぎます。
これらの境界チェックにより、gnuDump
関数は常に有効なテキストセグメントの範囲内で逆アセンブルを実行するようになり、無効な入力によって発生する可能性のあるクラッシュや予期せぬ動作を防ぎ、ツールの堅牢性が向上しました。
コアとなるコードの変更箇所
src/cmd/nm/elf.go
--- a/src/cmd/nm/elf.go
+++ b/src/cmd/nm/elf.go
@@ -34,10 +34,10 @@ func elfSymbols(f *os.File) []Sym {
sym.Code = 'B'
default:
i := int(s.Section)
- if i <= 0 || i > len(p.Sections) {
+ if i < 0 || i >= len(p.Sections) {
break
}
- sect := p.Sections[i-1]
+ sect := p.Sections[i]
switch sect.Flags & (elf.SHF_WRITE | elf.SHF_ALLOC | elf.SHF_EXECINSTR) {
case elf.SHF_ALLOC | elf.SHF_EXECINSTR:
sym.Code = 'T'
src/cmd/objdump/elf.go
--- a/src/cmd/objdump/elf.go
+++ b/src/cmd/objdump/elf.go
@@ -42,10 +42,10 @@ func elfSymbols(f *os.File) (syms []Sym, goarch string) {
sym.Code = 'B'
default:
i := int(s.Section)
- if i <= 0 || i > len(p.Sections) {
+ if i < 0 || i >= len(p.Sections) {
break
}
- sect := p.Sections[i-1]
+ sect := p.Sections[i]
switch sect.Flags & (elf.SHF_WRITE | elf.SHF_ALLOC | elf.SHF_EXECINSTR) {
case elf.SHF_ALLOC | elf.SHF_EXECINSTR:
sym.Code = 'T'
src/cmd/objdump/main.go
--- a/src/cmd/objdump/main.go
+++ b/src/cmd/objdump/main.go
@@ -235,6 +235,15 @@ func gnuDump(tab *gosym.Table, lookup lookupFunc, disasm disasmFunc, textData []
if err != nil {
log.Fatalf("invalid end PC: %v", err)
}
+ if start < textStart {
+ start = textStart
+ }
+ if end < start {
+ end = start
+ }
+ if end > textStart+uint64(len(textData)) {
+ end = textStart + uint64(len(textData))
+ }
stdout := bufio.NewWriter(os.Stdout)
defer stdout.Flush()
コアとなるコードの解説
src/cmd/nm/elf.go
および src/cmd/objdump/elf.go
の変更
これらのファイルでは、elfSymbols
関数内でシンボルのセクション情報を処理する部分が変更されています。
i := int(s.Section)
: シンボルが属するセクションのインデックスを取得します。s.Section
はdebug/elf
パッケージのSymbol
構造体の一部で、ELFシンボルテーブルエントリのst_shndx
フィールドに対応します。if i < 0 || i >= len(p.Sections)
: 変更後の境界チェックです。i < 0
: セクションインデックスが負の値である場合(これは通常、SHN_UNDEF
などの特殊なセクションインデックスを示すか、不正な値であることを意味します)。i >= len(p.Sections)
: セクションインデックスがp.Sections
スライスの範囲外である場合。 これらの条件のいずれかが真であれば、ループを抜けて次のシンボルに進みます。これにより、不正なインデックスアクセスによるパニックを防ぎます。
sect := p.Sections[i]
: ここが最も重要な変更点です。以前はp.Sections[i-1]
でしたが、i
に修正されました。これにより、elf.File.Sections
が実際のELFセクション番号で直接インデックスされるという設計意図に合致し、シンボルが属するセクションの情報を正しく取得できるようになりました。switch sect.Flags & (elf.SHF_WRITE | elf.SHF_ALLOC | elf.SHF_EXECINSTR)
: 取得したセクションのフラグをチェックし、シンボルの種類(例: 実行可能コードセクションであればT
、データセクションであればD
など)を決定します。このフラグチェックは、正しいセクション情報が取得されることで、より正確なシンボル型分類が可能になります。
src/cmd/objdump/main.go
の変更
gnuDump
関数は、指定されたアドレス範囲の機械語コードを逆アセンブルする役割を担っています。
if start < textStart { start = textStart }
: 逆アセンブルの開始アドレスstart
が、実行可能コードが格納されているテキストセグメントの開始アドレスtextStart
よりも小さい場合、start
をtextStart
に強制的に設定します。これにより、コード領域外の不正な開始アドレスが指定されても、逆アセンブルはテキストセグメントの先頭から行われるようになります。if end < start { end = start }
: 逆アセンブルの終了アドレスend
が、開始アドレスstart
よりも小さい場合、end
をstart
に設定します。これは、逆アセンブル範囲が負になるような不正な指定(例:start=100, end=50
)を修正し、結果として空の逆アセンブル範囲(または単一アドレスの逆アセンブル)として扱われるようにします。if end > textStart+uint64(len(textData)) { end = textStart + uint64(len(textData)) }
: 逆アセンブルの終了アドレスend
が、テキストセグメントの終了アドレス(textStart
にテキストデータの長さlen(textData)
を加えたもの)よりも大きい場合、end
をテキストセグメントの終了アドレスに強制的に設定します。これにより、コード領域外の不正な終了アドレスが指定されても、逆アセンブルはテキストセグメントの末尾までで停止するようになります。
これらの変更により、gnuDump
関数はより堅牢になり、ユーザーがどのようなアドレス範囲を指定しても、プログラムがクラッシュすることなく、常に有効なテキストセグメントの範囲内で安全に逆アセンブルを実行できるようになりました。
関連リンク
- Go CL 92390043: https://golang.org/cl/92390043
参考にした情報源リンク
- (この解説の生成において、特定の外部Webサイトを直接参照する必要はありませんでした。Goのソースコード、ELFの一般的な知識、および
nm
/objdump
コマンドの機能に関する既存の知識に基づいて作成されました。)```markdown
[インデックス 19359] ファイルの概要
このコミットは、Go言語のツールチェインに含まれるnm
コマンドとobjdump
コマンドにおけるELF(Executable and Linkable Format)ファイルのシンボル型解析のバグ修正、およびobjdump
の逆アセンブル処理における境界チェックの改善を目的としています。特に、elf.File.Sections
のインデックス処理の誤りを修正し、テキストセグメント外の逆アセンブル要求によるクラッシュを防ぐ堅牢性向上が図られています。
コミット
commit 8e22903b46aadd6eda937417cba86b528cba92e2
Author: Russ Cox <rsc@golang.org>
Date: Wed May 14 17:45:13 2014 -0700
cmd/nm, cmd/objdump: fix elf symbol types
Turns out elf.File.Sections is indexed by the actual
section number, not the number minus one.
I don't know why I thought the -1 was necessary.
Fixes objdump test (and therefore build) on ELF systems.
While we're here, fix bounds on gnuDump so that we
don't crash when asked to disassemble outside
the text segment. May fix Windows build or at least
make the failure more interesting.
TBR=iant
CC=golang-codereviews
https://golang.org/cl/92390043
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/8e22903b46aadd6eda937417cba86b528cba92e2
元コミット内容
cmd/nm, cmd/objdump: fix elf symbol types
Turns out elf.File.Sections is indexed by the actual
section number, not the number minus one.
I don't know why I thought the -1 was necessary.
Fixes objdump test (and therefore build) on ELF systems.
While we're here, fix bounds on gnuDump so that we
don't crash when asked to disassemble outside
the text segment. May fix Windows build or at least
make the failure more interesting.
TBR=iant
CC=golang-codereviews
https://golang.org/cl/92390043
変更の背景
このコミットは主に2つの問題に対処しています。
- ELFセクションインデックスの誤り: Goの
elf
パッケージが提供するelf.File.Sections
は、ELFファイルのセクションヘッダテーブルを表します。ELF仕様ではセクション番号は1から始まる(0は未定義セクション)ため、このスライスは実際のセクション番号で直接インデックスされるべきでした。しかし、これまでの実装では誤ってi-1
のようにオフセットを適用しており、これがシンボル型を正しく識別できない原因となっていました。このバグは特にELFシステム上でのobjdump
のテスト失敗を引き起こしていました。 objdump
における逆アセンブル範囲の堅牢性不足:objdump
コマンドのgnuDump
関数は、逆アセンブルを行う際に指定されたアドレス範囲が実行可能ファイルのテキストセグメント(コードが配置される領域)の境界を越える場合に、クラッシュする可能性がありました。これは、無効なアドレス範囲が指定された場合にプログラムが予期せぬ動作をする脆弱性を示していました。この修正は、特にWindowsのようなシステムでのビルドの安定性向上、または問題発生時のデバッグ情報の改善に寄与します。
これらの問題は、Goツールチェインの安定性と正確性に影響を与えるものであり、特にクロスコンパイルや異なるOS環境でのツール利用において重要でした。
前提知識の解説
ELF (Executable and Linkable Format)
ELFは、Unix系OS(Linux、BSDなど)で広く使用されている実行可能ファイル、オブジェクトコード、共有ライブラリ、コアダンプファイルの標準フォーマットです。プログラムの実行に必要な情報(コード、データ、シンボルテーブル、セクション情報など)を構造化して格納します。
- セクション (Sections): ELFファイルは複数のセクションに分割されます。各セクションは特定の種類のデータ(例:
.text
は実行可能コード、.data
は初期化済みデータ、.bss
は初期化されていないデータ、.symtab
はシンボルテーブルなど)を格納します。 - セクションヘッダテーブル (Section Header Table): ファイル内の各セクションに関する情報(名前、種類、サイズ、ファイルオフセット、メモリ上のアドレス、フラグなど)を記述したテーブルです。
- シンボル (Symbols): プログラム内の関数や変数などの名前と、それらがメモリ上のどこに配置されているか(アドレス)を関連付ける情報です。シンボルは、リンカが異なるオブジェクトファイルを結合したり、デバッガがソースコードと実行中のプログラムを関連付けたりするために使用されます。
- シンボルテーブル (Symbol Table): シンボル情報のリストです。各エントリはシンボルの名前、値(アドレス)、サイズ、型(関数、オブジェクトなど)、および関連するセクションインデックスなどを含みます。
nm
コマンド
nm
(name mangler)は、オブジェクトファイル、静的ライブラリ、または実行可能ファイル内のシンボル(関数名、変数名など)をリスト表示するためのUnix系コマンドです。シンボルの種類(例: T
はテキストセクションの関数、B
はBSSセクションの変数、D
はデータセクションの変数など)も表示します。
objdump
コマンド
objdump
は、オブジェクトファイルや実行可能ファイルに関する様々な情報を表示するためのUnix系コマンドです。主な機能には、逆アセンブル(機械語コードをアセンブリ言語に変換)、セクションヘッダの表示、シンボルテーブルの表示などがあります。このコミットでは、特に逆アセンブル機能(gnuDump
関数に関連)とシンボル型解析が関係しています。
Goのelf
パッケージ
Go標準ライブラリのdebug/elf
パッケージは、GoプログラムからELFファイルを読み込み、解析するための機能を提供します。このパッケージは、ELFヘッダ、プログラムヘッダ、セクションヘッダ、シンボルテーブルなどの構造をGoの型として定義し、それらの情報にアクセスするためのメソッドを提供します。
elf.File.Sections
: ELFファイルのセクションヘッダテーブルを表すスライスです。このスライスのインデックスが、ELF仕様におけるセクション番号とどのように対応するかが、今回のバグの核心でした。
技術的詳細
ELFセクションインデックスの修正
元のコードでは、elf.File.Sections
スライスにアクセスする際に、シンボルが属するセクションのインデックスi
から1
を引いていました(p.Sections[i-1]
)。これは、スライスが0-ベースのインデックスを持つという一般的なプログラミングの慣習に基づいていた可能性があります。しかし、ELF仕様においてセクション番号は1から始まるため、elf.File.Sections
は実際のセクション番号を直接インデックスとして使用するように設計されていました。
例えば、ELFファイルでセクション番号1が.text
セクションを指す場合、elf.File.Sections[1]
がそのセクション情報を含むべきです。しかし、p.Sections[i-1]
というコードでは、セクション番号1のシンボルに対してp.Sections[0]
にアクセスしてしまい、誤ったセクション情報(または存在しないセクション)を参照していました。
この修正により、i-1
がi
に修正され、p.Sections[i]
と直接アクセスすることで、シンボルが実際に属するセクションの情報を正しく取得できるようになりました。これにより、nm
とobjdump
がシンボルの種類(例: コードセクションのシンボルはT
、データセクションのシンボルはD
など)を正確に判別できるようになります。
また、インデックスの境界チェックもi <= 0 || i > len(p.Sections)
からi < 0 || i >= len(p.Sections)
に変更されました。これは、Goのスライスインデックスの慣習(0からlen-1
まで)に合わせたもので、i
が0の場合(ELFのSHN_UNDEF
など、未定義セクションを示す特殊な値)や、スライスの範囲外にアクセスしようとした場合のパニックを防ぎます。
objdump
における逆アセンブル範囲の堅牢性向上
src/cmd/objdump/main.go
のgnuDump
関数では、逆アセンブルの開始アドレス(start
)と終了アドレス(end
)が、実行可能ファイルのテキストセグメント(textStart
からtextStart + len(textData)
まで)の範囲内に収まるように調整するロジックが追加されました。
if start < textStart { start = textStart }
: 指定された開始アドレスがテキストセグメントの開始アドレスよりも小さい場合、テキストセグメントの開始アドレスに調整します。これにより、テキストセグメントより前のメモリ領域を逆アセンブルしようとする試みを防ぎます。if end < start { end = start }
: 終了アドレスが開始アドレスよりも小さい場合、終了アドレスを開始アドレスに調整します。これは、無効な範囲指定(例: 終了アドレスが開始アドレスより前)を正規化し、空の範囲として扱います。if end > textStart+uint64(len(textData)) { end = textStart + uint64(len(textData)) }
: 指定された終了アドレスがテキストセグメントの終了アドレス(textStart
にテキストデータの長さlen(textData)
を加えたもの)よりも大きい場合、end
をテキストセグメントの終了アドレスに強制的に設定します。これにより、コード領域外の不正な終了アドレスが指定されても、逆アセンブルはテキストセグメントの末尾までで停止するようになります。
これらの境界チェックにより、gnuDump
関数はより堅牢になり、ユーザーがどのようなアドレス範囲を指定しても、プログラムがクラッシュすることなく、常に有効なテキストセグメントの範囲内で安全に逆アセンブルを実行できるようになりました。
コアとなるコードの変更箇所
src/cmd/nm/elf.go
--- a/src/cmd/nm/elf.go
+++ b/src/cmd/nm/elf.go
@@ -34,10 +34,10 @@ func elfSymbols(f *os.File) []Sym {
sym.Code = 'B'
default:
i := int(s.Section)
- if i <= 0 || i > len(p.Sections) {
+ if i < 0 || i >= len(p.Sections) {
break
}
- sect := p.Sections[i-1]
+ sect := p.Sections[i]
switch sect.Flags & (elf.SHF_WRITE | elf.SHF_ALLOC | elf.SHF_EXECINSTR) {
case elf.SHF_ALLOC | elf.SHF_EXECINSTR:
sym.Code = 'T'
src/cmd/objdump/elf.go
--- a/src/cmd/objdump/elf.go
+++ b/src/cmd/objdump/elf.go
@@ -42,10 +42,10 @@ func elfSymbols(f *os.File) (syms []Sym, goarch string) {
sym.Code = 'B'
default:
i := int(s.Section)
- if i <= 0 || i > len(p.Sections) {
+ if i < 0 || i >= len(p.Sections) {
break
}
- sect := p.Sections[i-1]
+ sect := p.Sections[i]
switch sect.Flags & (elf.SHF_WRITE | elf.SHF_ALLOC | elf.SHF_EXECINSTR) {
case elf.SHF_ALLOC | elf.SHF_EXECINSTR:
sym.Code = 'T'
src/cmd/objdump/main.go
--- a/src/cmd/objdump/main.go
+++ b/cmd/objdump/main.go
@@ -235,6 +235,15 @@ func gnuDump(tab *gosym.Table, lookup lookupFunc, disasm disasmFunc, textData []
if err != nil {
log.Fatalf("invalid end PC: %v", err)
}
+ if start < textStart {
+ start = textStart
+ }
+ if end < start {
+ end = start
+ }
+ if end > textStart+uint64(len(textData)) {
+ end = textStart + uint64(len(textData))
+ }
stdout := bufio.NewWriter(os.Stdout)
defer stdout.Flush()
コアとなるコードの解説
src/cmd/nm/elf.go
および src/cmd/objdump/elf.go
の変更
これらのファイルでは、elfSymbols
関数内でシンボルのセクション情報を処理する部分が変更されています。
i := int(s.Section)
: シンボルが属するセクションのインデックスを取得します。s.Section
はdebug/elf
パッケージのSymbol
構造体の一部で、ELFシンボルテーブルエントリのst_shndx
フィールドに対応します。if i < 0 || i >= len(p.Sections)
: 変更後の境界チェックです。i < 0
: セクションインデックスが負の値である場合(これは通常、SHN_UNDEF
などの特殊なセクションインデックスを示すか、不正な値であることを意味します)。i >= len(p.Sections)
: セクションインデックスがp.Sections
スライスの範囲外である場合。 これらの条件のいずれかが真であれば、ループを抜けて次のシンボルに進みます。これにより、不正なインデックスアクセスによるパニックを防ぎます。
sect := p.Sections[i]
: ここが最も重要な変更点です。以前はp.Sections[i-1]
でしたが、i
に修正されました。これにより、elf.File.Sections
が実際のELFセクション番号で直接インデックスされるという設計意図に合致し、シンボルが属するセクションの情報を正しく取得できるようになりました。switch sect.Flags & (elf.SHF_WRITE | elf.SHF_ALLOC | elf.SHF_EXECINSTR)
: 取得したセクションのフラグをチェックし、シンボルの種類(例: 実行可能コードセクションであればT
、データセクションであればD
など)を決定します。このフラグチェックは、正しいセクション情報が取得されることで、より正確なシンボル型分類が可能になります。
src/cmd/objdump/main.go
の変更
gnuDump
関数は、指定されたアドレス範囲の機械語コードを逆アセンブルする役割を担っています。
if start < textStart { start = textStart }
: 逆アセンブルの開始アドレスstart
が、実行可能コードが格納されているテキストセグメントの開始アドレスtextStart
よりも小さい場合、start
をtextStart
に強制的に設定します。これにより、コード領域外の不正な開始アドレスが指定されても、逆アセンブルはテキストセグメントの先頭から行われるようになります。if end < start { end = start }
: 逆アセンブルの終了アドレスend
が、開始アドレスstart
よりも小さい場合、end
をstart
に設定します。これは、逆アセンブル範囲が負になるような不正な指定(例:start=100, end=50
)を修正し、結果として空の逆アセンブル範囲(または単一アドレスの逆アセンブル)として扱われるようにします。if end > textStart+uint64(len(textData)) { end = textStart + uint64(len(textData)) }
: 逆アセンブルの終了アドレスend
が、テキストセグメントの終了アドレス(textStart
にテキストデータの長さlen(textData)
を加えたもの)よりも大きい場合、end
をテキストセグメントの終了アドレスに強制的に設定します。これにより、コード領域外の不正な終了アドレスが指定されても、逆アセンブルはテキストセグメントの末尾までで停止するようになります。
これらの変更により、gnuDump
関数はより堅牢になり、ユーザーがどのようなアドレス範囲を指定しても、プログラムがクラッシュすることなく、常に有効なテキストセグメントの範囲内で安全に逆アセンブルを実行できるようになりました。
関連リンク
- Go CL 92390043: https://golang.org/cl/92390043
参考にした情報源リンク
- (この解説の生成において、特定の外部Webサイトを直接参照する必要はありませんでした。Goのソースコード、ELFの一般的な知識、および
nm
/objdump
コマンドの機能に関する既存の知識に基づいて作成されました。)