[インデックス 18757] ファイルの概要
このコミットは、Go言語のリンカ(cmd/ld
)におけるELF(Executable and Linkable Format)ノートセクションのサイズ計算に関する修正です。具体的には、ノートセクションのサイズにパディングの長さを含めないように変更することで、NetBSDなどの一部のOSで発生していたプログラム実行時の問題を解決します。
コミット
commit 37e195cf727eb61d352f244230d988eb444a9b13
Author: Shenghou Ma <minux.ma@gmail.com>
Date: Wed Mar 5 14:40:55 2014 -0500
cmd/ld: don't include padding length in size of the note section
Recently NetBSD starts to enforce this, and refuses to execute
the program if n is larger than the sum of entry sizes.
Before:
$ readelf -n ../bin/go.old
Notes at offset 0x00000bd0 with length 0x00000019:
Owner Data size Description
NetBSD 0x00000004 NT_VERSION (version)
readelf: Warning: corrupt note found at offset 18 into core notes
readelf: Warning: type: 0, namesize: 00000000, descsize: 00000000
$ readelf -n ../bin/go
Notes at offset 0x00000bd0 with length 0x00000018:
Owner Data size Description
NetBSD 0x00000004 NT_VERSION (version)
LGTM=iant
R=iant
CC=golang-codereviews
https://golang.org/cl/70710043
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/37e195cf727eb61d352f244230d988eb444a9b13
元コミット内容
このコミットの目的は、Go言語のリンカ(cmd/ld
)が生成するELF形式の実行ファイルにおいて、ノートセクションのサイズ計算からパディングの長さを除外することです。これにより、NetBSDなどの一部のオペレーティングシステムが、ノートセクションのサイズがエントリサイズの合計よりも大きい場合にプログラムの実行を拒否するという問題を解決します。
コミットメッセージには、修正前後のreadelf -n
コマンドの出力例が示されています。修正前はノートセクションの長さが0x00000019
(25バイト)であり、readelf
が「corrupt note found」という警告を出していました。これは、ノートエントリ自体の合計サイズが24バイトであるにもかかわらず、セクション全体のサイズが25バイトと報告されていたため、1バイトのパディングが含まれていたことを示唆しています。修正後は、長さが0x00000018
(24バイト)となり、警告も解消されています。
変更の背景
ELF形式の実行ファイルには、プログラムに関する追加情報(バージョン情報、ビルド情報など)を格納するための「ノートセクション」(.note
セクション)が存在します。このセクションは、一つ以上の「ノートエントリ」で構成されます。各ノートエントリは、特定の情報を格納するための構造化されたデータです。
問題の背景には、ELFノートセクションの厳密な解釈と、NetBSDのような一部のOSにおけるその解釈の強化があります。ELF仕様では、ノートセクションのサイズは、そのセクションに含まれるすべてのノートエントリの合計サイズと一致する必要があります。しかし、Goのリンカは、ノートセクションの最後にアライメントのためのパディングバイトを追加し、そのパディングバイトの長さもセクションの合計サイズに含めていました。
NetBSDは、最近になってこのELFノートセクションのサイズに関するチェックを厳格化しました。具体的には、ノートセクションのヘッダに記述されているサイズ(sh_size
)が、実際にそのセクションに含まれる個々のノートエントリの合計サイズよりも大きい場合、その実行ファイルを不正なものとみなし、実行を拒否するようになりました。
Goのリンカが生成する実行ファイルは、このNetBSDの新しい厳格なチェックに引っかかり、実行できないという問題が発生していました。readelf -n
の出力で示されている「corrupt note found」という警告は、この不整合を指摘するものでした。この警告は、ノートセクションの報告されたサイズと、実際に解析されたノートエントリの合計サイズとの間に矛盾があることを示しています。
このコミットは、このNetBSDの厳格なチェックに対応し、GoでビルドされたプログラムがNetBSD上で正しく実行されるようにするために必要とされました。
前提知識の解説
このコミットを理解するためには、以下の前提知識が必要です。
-
ELF (Executable and Linkable Format):
- Unix系OS(Linux, BSD, Solarisなど)で広く使用されている実行ファイル、オブジェクトファイル、共有ライブラリの標準フォーマットです。
- ELFファイルは、ヘッダ、プログラムヘッダテーブル、セクションヘッダテーブル、そして様々なセクション(コード、データ、シンボルテーブルなど)で構成されます。
- セクション: ELFファイル内の論理的なデータの塊です。各セクションは、その種類(コード、データ、読み取り専用データなど)に応じて特定の目的を持ちます。
- ノートセクション (
.note
セクション): ELFファイル内の特殊なセクションの一つで、プログラムに関する追加情報(例: OSのバージョン、ビルドツール情報、プロセッサ固有の機能フラグなど)を格納するために使用されます。
-
ELFノートエントリ:
- ノートセクションは、一つ以上のノートエントリのシーケンスで構成されます。
- 各ノートエントリは、以下の構造を持ちます(通常、4バイト境界にアライメントされます):
n_namesz
(4バイト):n_name
フィールドのサイズ(NULL終端文字を含む)。n_descsz
(4バイト):n_desc
フィールドのサイズ。n_type
(4バイト): ノートのタイプを示す識別子(例:NT_VERSION
はバージョン情報を示す)。n_name
(可変長): ノートの所有者(通常はベンダー名やOS名、例: "NetBSD")。n_desc
(可変長): ノートの記述データ(例: バージョン番号)。
- ノートエントリの各フィールドは、通常4バイト境界にアライメントされるため、
n_name
やn_desc
の実際のデータサイズが4の倍数でない場合、パディングバイトが追加されることがあります。
-
readelf
コマンド:- ELF形式のオブジェクトファイルに関する情報を表示するためのGNU Binutilsに含まれるユーティリティです。
readelf -n <filename>
コマンドは、指定されたELFファイルのノートセクションの内容を解析し、表示します。このコマンドの出力は、ノートセクションの全体サイズと、個々のノートエントリの詳細(所有者、データサイズ、タイプ、説明)を示します。- このコミットメッセージの「Before」と「After」のセクションで、
readelf -n
の出力が比較されており、問題の具体的な症状と修正の効果が示されています。
-
アライメントとパディング:
- コンピュータのメモリやファイルシステムでは、データが特定のバイト境界(例: 4バイト、8バイト)に配置されることが効率的である場合があります。これを「アライメント」と呼びます。
- アライメント要件を満たすために、データの間に「パディング」と呼ばれる意味のないバイトが挿入されることがあります。
- このコミットでは、ELFノートセクションの最後に、セクション全体が特定のアライメント要件を満たすために追加されていたパディングが問題となっていました。
-
NetBSDのELFノートセクションの厳格化:
- オペレーティングシステムは、実行ファイルをロードする際にそのフォーマットを検証します。
- NetBSDは、ELFノートセクションのサイズに関する検証を厳格化し、セクションヘッダに記述されたサイズが、実際に含まれるノートエントリの合計サイズと一致しない場合に、そのファイルを不正と判断し、実行を拒否するようになりました。これは、セキュリティ上の理由や、ELF仕様へのより厳密な準拠を目的としている可能性があります。
技術的詳細
このコミットが修正している問題は、Go言語のリンカがELFノートセクションのサイズを計算する際に、セクションの最後に挿入されるアライメントのためのパディングバイトを含めてしまっていたことに起因します。
ELFノートセクションは、通常、4バイト境界にアライメントされる必要があります。これは、セクション内の各ノートエントリが効率的にアクセスできるようにするためです。Goのリンカは、ノートセクションの最後に、セクション全体のサイズが4の倍数になるようにパディングバイトを追加していました。そして、このパディングバイトの長さも、ELFセクションヘッダのsh_size
フィールド(セクションのサイズを示す)に含めていました。
しかし、NetBSDの新しい厳格なチェックでは、sh_size
は、実際に有効なノートエントリの合計サイズと厳密に一致する必要があると解釈されました。パディングバイトは有効なノートエントリの一部ではないため、sh_size
にパディングの長さが含まれていると、NetBSDはこれを不整合と判断し、プログラムの実行を拒否しました。
コミットメッセージのreadelf -n
の出力例がこの状況を明確に示しています。
-
修正前:
Notes at offset 0x00000bd0 with length 0x00000019:
(25バイト)NT_VERSION
ノートエントリのOwner
は"NetBSD"(7バイト + NULL終端1バイト = 8バイト)、Data size
は0x00000004
(4バイト)。- ノートエントリのヘッダ(
n_namesz
,n_descsz
,n_type
)はそれぞれ4バイトなので、合計12バイト。 n_name
("NetBSD") は8バイト。n_desc
(バージョンデータ) は4バイト。- 合計: 12 + 8 + 4 = 24バイト。
- しかし、報告されている長さは25バイト。これは、24バイトの有効なデータに1バイトのパディングが追加され、そのパディングもサイズに含まれていたことを示しています。
readelf
が「corrupt note found」と警告しているのは、この1バイトの不整合のためです。
-
修正後:
Notes at offset 0x00000bd0 with length 0x00000018:
(24バイト)- 有効なノートエントリの合計サイズである24バイトと一致しており、警告も解消されています。
この修正は、src/cmd/ld/elf.c
ファイル内のelfnote
関数において、sh->size
の計算方法を変更することで実現されています。以前はsh->size = n;
としていましたが、これはn
がノートセクションの合計サイズ(パディングを含む)を表していたため問題でした。新しい計算式sh->size = n - resoff % 4;
は、n
からアライメントのために追加されたパディングの長さを差し引くことで、sh->size
が純粋に有効なノートエントリの合計サイズと一致するようにします。
resoff % 4
は、resoff
(リソースオフセット、おそらくノートセクションの開始オフセット)が4で割り切れない場合に、4バイト境界にアライメントするために必要なパディングの長さを計算します。例えば、resoff
が25の場合、25 % 4
は1となり、1バイトのパディングが必要であることを示します。この1バイトをn
から差し引くことで、正しい有効なノートエントリの合計サイズが得られます。
コアとなるコードの変更箇所
変更はsrc/cmd/ld/elf.c
ファイルのelfnote
関数内の一行です。
--- a/src/cmd/ld/elf.c
+++ b/src/cmd/ld/elf.c
@@ -355,7 +355,7 @@ elfnote(ElfShdr *sh, uint64 startva, uint64 resoff, int sz)\n sh->addralign = 4;\n sh->addr = startva + resoff - n;\n sh->off = resoff - n;\n-\tsh->size = n;\n+\tsh->size = n - resoff % 4;\n \n return n;\n }\n```
## コアとなるコードの解説
`elfnote`関数は、ELFノートセクションのセクションヘッダ(`ElfShdr *sh`)を設定する役割を担っています。この関数は、ノートセクションのサイズ、アドレス、オフセットなどのプロパティを計算し、設定します。
* `sh->addralign = 4;`: ノートセクションが4バイト境界にアライメントされるべきであることを示します。
* `sh->addr = startva + resoff - n;`: ノートセクションの仮想アドレスを設定します。
* `sh->off = resoff - n;`: ノートセクションのファイルオフセットを設定します。
* `sh->size = n;` (変更前):
* `n`は、ノートセクション全体のサイズ(パディングを含む)を表していました。
* この行は、セクションヘッダの`sh_size`フィールドに、パディングを含む全体のサイズをそのまま設定していました。これがNetBSDでの問題の原因でした。
* `sh->size = n - resoff % 4;` (変更後):
* `resoff % 4`: `resoff`は、ノートセクションの開始オフセット(または関連するオフセット)を示していると考えられます。この`% 4`演算は、`resoff`が4で割り切れない場合に、4バイト境界にアライメントするために必要なパディングの長さを計算します。例えば、`resoff`が25の場合、`25 % 4`は1となり、1バイトのパディングが必要であることを意味します。
* `n - (resoff % 4)`: `n`(パディングを含む全体のサイズ)から、アライメントのために追加されたパディングの長さを差し引きます。これにより、`sh->size`は、純粋に有効なノートエントリの合計サイズと一致するようになります。
この変更により、Goリンカが生成するELFファイルは、NetBSDの厳格なELFノートセクションのサイズチェックに合格するようになり、プログラムが正しく実行されるようになりました。
## 関連リンク
* Go言語のIssueトラッカー: このコミットに関連するIssueや議論がある可能性がありますが、コミットメッセージには直接的なIssue番号は記載されていません。しかし、`https://golang.org/cl/70710043`というChange List(CL)へのリンクが提供されています。
* Go Change List 70710043: [https://golang.org/cl/70710043](https://golang.org/cl/70710043) (このコミットのレビューページ)
## 参考にした情報源リンク
* **ELF (Executable and Linkable Format) Specification**:
* ELFの公式仕様書は、様々なバージョンが存在しますが、基本的な構造は共通しています。
* [Tool Interface Standard (TIS) Portable Formats Specification, Version 1.1](https://refspecs.linuxfoundation.org/ELF/elf.pdf) (PDF)
* **`readelf` man page**:
* `readelf`コマンドの詳細な使用方法と出力の説明。
* `man readelf`
* **NetBSDのELFノートに関する情報**:
* NetBSDのドキュメントやメーリングリストのアーカイブで、ELFノートセクションの厳格化に関する議論や変更履歴が見つかる可能性があります。
* NetBSDの公式ウェブサイト: [https://www.netbsd.org/](https://www.netbsd.org/)
* **Go言語のリンカのソースコード**:
* `src/cmd/ld/elf.c`ファイルは、GoのリンカがELFファイルをどのように生成するかを理解するための主要な情報源です。
* GoのGitHubリポジトリ: [https://github.com/golang/go](https://github.com/golang/go)
* **ELFノートセクションの構造に関する一般的な情報**:
* 様々な技術ブログやOS開発に関するドキュメントで、ELFノートセクションの構造と目的について解説されています。
* 例: [https://docs.oracle.com/cd/E19683-01/817-3677/6m7460000/index.html](https://docs.oracle.com/cd/E19683-01/817-3677/6m7460000/index.html) (Oracle Solaris Studio 12.4: Linker and Libraries Guide - Note Sections)```markdown
# [インデックス 18757] ファイルの概要
このコミットは、Go言語のリンカ(`cmd/ld`)におけるELF(Executable and Linkable Format)ノートセクションのサイズ計算に関する修正です。具体的には、ノートセクションのサイズにパディングの長さを含めないように変更することで、NetBSDなどの一部のOSで発生していたプログラム実行時の問題を解決します。
## コミット
commit 37e195cf727eb61d352f244230d988eb444a9b13 Author: Shenghou Ma minux.ma@gmail.com Date: Wed Mar 5 14:40:55 2014 -0500
cmd/ld: don't include padding length in size of the note section
Recently NetBSD starts to enforce this, and refuses to execute
the program if n is larger than the sum of entry sizes.
Before:
$ readelf -n ../bin/go.old
Notes at offset 0x00000bd0 with length 0x00000019:
Owner Data size Description
NetBSD 0x00000004 NT_VERSION (version)
readelf: Warning: corrupt note found at offset 18 into core notes
readelf: Warning: type: 0, namesize: 00000000, descsize: 00000000
$ readelf -n ../bin/go
Notes at offset 0x00000bd0 with length 0x00000018:
Owner Data size Description
NetBSD 0x00000004 NT_VERSION (version)
LGTM=iant
R=iant
CC=golang-codereviews
https://golang.org/cl/70710043
## GitHub上でのコミットページへのリンク
[https://github.com/golang/go/commit/37e195cf727eb61d352f244230d988eb444a9b13](https://github.com/golang/go/commit/37e195cf727eb61d352f244230d988eb444a9b13)
## 元コミット内容
このコミットの目的は、Go言語のリンカ(`cmd/ld`)が生成するELF形式の実行ファイルにおいて、ノートセクションのサイズ計算からパディングの長さを除外することです。これにより、NetBSDなどの一部のオペレーティングシステムが、ノートセクションのサイズがエントリサイズの合計よりも大きい場合にプログラムの実行を拒否するという問題を解決します。
コミットメッセージには、修正前後の`readelf -n`コマンドの出力例が示されています。修正前はノートセクションの長さが`0x00000019`(25バイト)であり、`readelf`が「corrupt note found」という警告を出していました。これは、ノートエントリ自体の合計サイズが24バイトであるにもかかわらず、セクション全体のサイズが25バイトと報告されていたため、1バイトのパディングが含まれていたことを示唆しています。修正後は、長さが`0x00000018`(24バイト)となり、警告も解消されています。
## 変更の背景
ELF形式の実行ファイルには、プログラムに関する追加情報(バージョン情報、ビルド情報など)を格納するための「ノートセクション」(`.note`セクション)が存在します。このセクションは、一つ以上の「ノートエントリ」で構成されます。各ノートエントリは、特定の情報を格納するための構造化されたデータです。
問題の背景には、ELFノートセクションの厳密な解釈と、NetBSDのような一部のOSにおけるその解釈の強化があります。ELF仕様では、ノートセクションのサイズは、そのセクションに含まれるすべてのノートエントリの合計サイズと一致する必要があります。しかし、Goのリンカは、ノートセクションの最後にアライメントのためのパディングバイトを追加し、そのパディングバイトの長さもセクションの合計サイズに含めていました。
NetBSDは、最近になってこのELFノートセクションのサイズに関するチェックを厳格化しました。具体的には、ノートセクションのヘッダに記述されているサイズ(`sh_size`)が、実際にそのセクションに含まれる個々のノートエントリの合計サイズよりも大きい場合、その実行ファイルを不正なものとみなし、実行を拒否するようになりました。
Goのリンカが生成する実行ファイルは、このNetBSDの新しい厳格なチェックに引っかかり、実行できないという問題が発生していました。`readelf -n`の出力で示されている「corrupt note found」という警告は、この不整合を指摘するものでした。この警告は、ノートセクションの報告されたサイズと、実際に解析されたノートエントリの合計サイズとの間に矛盾があることを示しています。
このコミットは、このNetBSDの厳格なチェックに対応し、GoでビルドされたプログラムがNetBSD上で正しく実行されるようにするために必要とされました。
## 前提知識の解説
このコミットを理解するためには、以下の前提知識が必要です。
1. **ELF (Executable and Linkable Format)**:
* Unix系OS(Linux, BSD, Solarisなど)で広く使用されている実行ファイル、オブジェクトファイル、共有ライブラリの標準フォーマットです。
* ELFファイルは、ヘッダ、プログラムヘッダテーブル、セクションヘッダテーブル、そして様々なセクション(コード、データ、シンボルテーブルなど)で構成されます。
* **セクション**: ELFファイル内の論理的なデータの塊です。各セクションは、その種類(コード、データ、読み取り専用データなど)に応じて特定の目的を持ちます。
* **ノートセクション (`.note`セクション)**: ELFファイル内の特殊なセクションの一つで、プログラムに関する追加情報(例: OSのバージョン、ビルドツール情報、プロセッサ固有の機能フラグなど)を格納するために使用されます。
2. **ELFノートエントリ**:
* ノートセクションは、一つ以上のノートエントリのシーケンスで構成されます。
* 各ノートエントリは、以下の構造を持ちます(通常、4バイト境界にアライメントされます):
* `n_namesz` (4バイト): `n_name`フィールドのサイズ(NULL終端文字を含む)。
* `n_descsz` (4バイト): `n_desc`フィールドのサイズ。
* `n_type` (4バイト): ノートのタイプを示す識別子(例: `NT_VERSION`はバージョン情報を示す)。
* `n_name` (可変長): ノートの所有者(通常はベンダー名やOS名、例: "NetBSD")。
* `n_desc` (可変長): ノートの記述データ(例: バージョン番号)。
* ノートエントリの各フィールドは、通常4バイト境界にアライメントされるため、`n_name`や`n_desc`の実際のデータサイズが4の倍数でない場合、パディングバイトが追加されることがあります。
3. **`readelf`コマンド**:
* ELF形式のオブジェクトファイルに関する情報を表示するためのGNU Binutilsに含まれるユーティリティです。
* `readelf -n <filename>`コマンドは、指定されたELFファイルのノートセクションの内容を解析し、表示します。このコマンドの出力は、ノートセクションの全体サイズと、個々のノートエントリの詳細(所有者、データサイズ、タイプ、説明)を示します。
* このコミットメッセージの「Before」と「After」のセクションで、`readelf -n`の出力が比較されており、問題の具体的な症状と修正の効果が示されています。
4. **アライメントとパディング**:
* コンピュータのメモリやファイルシステムでは、データが特定のバイト境界(例: 4バイト、8バイト)に配置されることが効率的である場合があります。これを「アライメント」と呼びます。
* アライメント要件を満たすために、データの間に「パディング」と呼ばれる意味のないバイトが挿入されることがあります。
* このコミットでは、ELFノートセクションの最後に、セクション全体が特定のアライメント要件を満たすために追加されていたパディングが問題となっていました。
5. **NetBSDのELFノートセクションの厳格化**:
* オペレーティングシステムは、実行ファイルをロードする際にそのフォーマットを検証します。
* NetBSDは、ELFノートセクションのサイズに関する検証を厳格化し、セクションヘッダに記述されたサイズが、実際に含まれるノートエントリの合計サイズと一致しない場合に、そのファイルを不正と判断し、実行を拒否するようになりました。これは、セキュリティ上の理由や、ELF仕様へのより厳密な準拠を目的としている可能性があります。
## 技術的詳細
このコミットが修正している問題は、Go言語のリンカがELFノートセクションのサイズを計算する際に、セクションの最後に挿入されるアライメントのためのパディングバイトを含めてしまっていたことに起因します。
ELFノートセクションは、通常、4バイト境界にアライメントされる必要があります。これは、セクション内の各ノートエントリが効率的にアクセスできるようにするためです。Goのリンカは、ノートセクションの最後に、セクション全体のサイズが4の倍数になるようにパディングバイトを追加していました。そして、このパディングバイトの長さも、ELFセクションヘッダの`sh_size`フィールド(セクションのサイズを示す)に含めていました。
しかし、NetBSDの新しい厳格なチェックでは、`sh_size`は、実際に有効なノートエントリの合計サイズと厳密に一致する必要があると解釈されました。パディングバイトは有効なノートエントリの一部ではないため、`sh_size`にパディングの長さが含まれていると、NetBSDはこれを不整合と判断し、プログラムの実行を拒否しました。
コミットメッセージの`readelf -n`の出力例がこの状況を明確に示しています。
* **修正前**: `Notes at offset 0x00000bd0 with length 0x00000019:` (25バイト)
* `NT_VERSION`ノートエントリの`Owner`は"NetBSD"(7バイト + NULL終端1バイト = 8バイト)、`Data size`は`0x00000004`(4バイト)。
* ノートエントリのヘッダ(`n_namesz`, `n_descsz`, `n_type`)はそれぞれ4バイトなので、合計12バイト。
* `n_name` ("NetBSD") は8バイト。
* `n_desc` (バージョンデータ) は4バイト。
* 合計: 12 + 8 + 4 = 24バイト。
* しかし、報告されている長さは25バイト。これは、24バイトの有効なデータに1バイトのパディングが追加され、そのパディングもサイズに含まれていたことを示しています。`readelf`が「corrupt note found」と警告しているのは、この1バイトの不整合のためです。
* **修正後**: `Notes at offset 0x00000bd0 with length 0x00000018:` (24バイト)
* 有効なノートエントリの合計サイズである24バイトと一致しており、警告も解消されています。
この修正は、`src/cmd/ld/elf.c`ファイル内の`elfnote`関数において、`sh->size`の計算方法を変更することで実現されています。以前は`sh->size = n;`としていましたが、これは`n`がノートセクションの合計サイズ(パディングを含む)を表していたため問題でした。新しい計算式`sh->size = n - resoff % 4;`は、`n`からアライメントのために追加されたパディングの長さを差し引くことで、`sh->size`が純粋に有効なノートエントリの合計サイズと一致するようにします。
`resoff % 4`は、`resoff`(リソースオフセット、おそらくノートセクションの開始オフセット)が4で割り切れない場合に、4バイト境界にアライメントするために必要なパディングの長さを計算します。例えば、`resoff`が25の場合、`25 % 4`は1となり、1バイトのパディングが必要であることを示します。この1バイトを`n`から差し引くことで、正しい有効なノートエントリの合計サイズが得られます。
## コアとなるコードの変更箇所
変更は`src/cmd/ld/elf.c`ファイルの`elfnote`関数内の一行です。
```diff
--- a/src/cmd/ld/elf.c
+++ b/src/cmd/ld/elf.c
@@ -355,7 +355,7 @@ elfnote(ElfShdr *sh, uint64 startva, uint64 resoff, int sz)\n sh->addralign = 4;\n sh->addr = startva + resoff - n;\n sh->off = resoff - n;\n-\tsh->size = n;\n+\tsh->size = n - resoff % 4;\n \n return n;\n }\n```
## コアとなるコードの解説
`elfnote`関数は、ELFノートセクションのセクションヘッダ(`ElfShdr *sh`)を設定する役割を担っています。この関数は、ノートセクションのサイズ、アドレス、オフセットなどのプロパティを計算し、設定します。
* `sh->addralign = 4;`: ノートセクションが4バイト境界にアライメントされるべきであることを示します。
* `sh->addr = startva + resoff - n;`: ノートセクションの仮想アドレスを設定します。
* `sh->off = resoff - n;`: ノートセクションのファイルオフセットを設定します。
* `sh->size = n;` (変更前):
* `n`は、ノートセクション全体のサイズ(パディングを含む)を表していました。
* この行は、セクションヘッダの`sh_size`フィールドに、パディングを含む全体のサイズをそのまま設定していました。これがNetBSDでの問題の原因でした。
* `sh->size = n - resoff % 4;` (変更後):
* `resoff % 4`: `resoff`は、ノートセクションの開始オフセット(または関連するオフセット)を示していると考えられます。この`% 4`演算は、`resoff`が4で割り切れない場合に、4バイト境界にアライメントするために必要なパディングの長さを計算します。例えば、`resoff`が25の場合、`25 % 4`は1となり、1バイトのパディングが必要であることを意味します。
* `n - (resoff % 4)`: `n`(パディングを含む全体のサイズ)から、アライメントのために追加されたパディングの長さを差し引きます。これにより、`sh->size`は、純粋に有効なノートエントリの合計サイズと一致するようになります。
この変更により、Goリンカが生成するELFファイルは、NetBSDの厳格なELFノートセクションのサイズチェックに合格するようになり、プログラムが正しく実行されるようになりました。
## 関連リンク
* Go言語のIssueトラッカー: このコミットに関連するIssueや議論がある可能性がありますが、コミットメッセージには直接的なIssue番号は記載されていません。しかし、`https://golang.org/cl/70710043`というChange List(CL)へのリンクが提供されています。
* Go Change List 70710043: [https://golang.org/cl/70710043](https://golang.org/cl/70710043) (このコミットのレビューページ)
## 参考にした情報源リンク
* **ELF (Executable and Linkable Format) Specification**:
* ELFの公式仕様書は、様々なバージョンが存在しますが、基本的な構造は共通しています。
* [Tool Interface Standard (TIS) Portable Formats Specification, Version 1.1](https://refspecs.linuxfoundation.org/ELF/elf.pdf) (PDF)
* **`readelf` man page**:
* `readelf`コマンドの詳細な使用方法と出力の説明。
* `man readelf`
* **NetBSDのELFノートに関する情報**:
* NetBSDのドキュメントやメーリングリストのアーカイブで、ELFノートセクションの厳格化に関する議論や変更履歴が見つかる可能性があります。
* NetBSDの公式ウェブサイト: [https://www.netbsd.org/](https://www.netbsd.org/)
* **Go言語のリンカのソースコード**:
* `src/cmd/ld/elf.c`ファイルは、GoのリンカがELFファイルをどのように生成するかを理解するための主要な情報源です。
* GoのGitHubリポジトリ: [https://github.com/golang/go](https://github.com/golang/go)
* **ELFノートセクションの構造に関する一般的な情報**:
* 様々な技術ブログやOS開発に関するドキュメントで、ELFノートセクションの構造と目的について解説されています。
* 例: [https://docs.oracle.com/cd/E19683-01/817-3677/6m7460000/index.html](https://docs.oracle.com/cd/E19683-01/817-3677/6m7460000/index.html) (Oracle Solaris Studio 12.4: Linker and Libraries Guide - Note Sections)