⛓️
Rust製リンカーに対する改善(GSoC'25)
#zatsu
2025-07-22
先日私が参加しているGoogle Summer of Codeの中間審査が行われ,通過しました.これによりプロジェクトを完遂すると貰える金額の内,45%が支払われました[1].最終審査で残りの55%も獲得できると良いなと思っています.
最終審査は9月上旬に控えており,そちらは(形式は多分問われませんが)報告書を書いて公開する必要があります.どの媒体に書くかは決めていませんが,多分このブログに書くのだろうと思います.
一方中間審査についてはそういった縛りは無いのですが,GSoCに採択された際に書いた記事では応募に際した内容が主で,何をやるのかについては分量の関係上あえて深く触れませんでした.最終審査の報告書は英語で書く必要があるので,日本語で私が何をやり,何ができるようになる予定なのかについて書くには今が適しているだろうと思い,この記事を書いています.
採択直後に書いた以下の記事でも触れたように,本プロジェクトのタイトルは"Improve Wild linker test suites"でした.
これはRust製の高速なリンカーであるWildについて,他のリンカーのテストをWildを用いて手軽に実行できるような仕組みを構築することで,Wildのバグや不足しているオプション等を発見し,それらを修正するというものです.
このプロポーザルの骨子は,既存の他の主要なLinux向けのリンカー(ld, lld, mold, gold等)に存在するオプションとその効果が大体同じであることを利用しています.これにより,他のリンカー向けのテストの実行を自動化する余地と意味とが増加します.
しかしプロジェクトページを見ると,実際にやることとして書かれているのはテストスイートの改善だけでは無いことが分かります:
After that, I will work on a variety of improvements to Wild, including tasks such as adding support for new architectures and fixing existing bugs.
すなわち,タイトルが示している部分はコアなタスクとして据えられており,期間中には他のタスクもやるという構成です(実際にここまで作業をやる中でコアタスクの範疇に含まれる内容はほぼ終わっていて,それどころか拡張タスクに割いていた時間の方が圧倒的に多かったです).これはプロポーザル作成段階からメンターから提案を受けてこのようにしており,少々理由がありました.
私は当初プロポーザルの原案には,コアタスク及びそこから派生する内容を作業する予定であると書いていました.しかしメンターからは「コアタスクは小さく保って,自由に拡張の余地があるタスクを複数設定して,それらを自由にやると良いのでは.というかそうしてほしい」といった提案を受け,相談の後にそのようにプロポーザルを修正しました.これは次の理由によるものです:
- 普通に人手が足りないがちのでWildに関連するものであれば割と何でもできるようにしておくと便利(私の興味関心的にもその方が好都合)
- 去年も(Wildに関連するものではないが)メンターを担当しており,その際のタスクはあまりにも野心的過ぎたため思うようにはいかなかったらしく,このような事態をできるだけ避けたい
もとより私はリンカーの本質的な改善に興味があり,外部のリンカーのテストを動かすことで改善点を多く発見できる見込みがあり,それを基にして多様な改善ができると考えたため,そのような点でも理に適った構成であると思ったため,このような構成としました.
moldのテストスイートをWild内で動作させるだけなら,その実装はそこまで大変ではありません.moldのテストはシェルスクリプトベースであるため,リンカーとしてWildを用いるためのセットアップなどをやったらあとはそれらを実行するだけで最低限は達成可能だからです.もちろんそれを便利に使うための仕組みは別で構築する必要があり,そういったものも実装しましたが.
実装をして試しに走らせてみると,多くのテストが失敗しました.一部のテストは例えばWildがまだサポートしていないアーキテクチャを対象としているなど失敗するのが自明なテストなのでそういったものを後で無視したりするようにしましたが,依然多いです.なので最近は失敗したテストについて分析をし,徐々に直す作業を行っています.
ldとかのmanを読んでWildに未実装だが実装すれば便利なオプションを見つけて実装したり,既知のバグを修正したり,現在進行中のRISC-Vサポートに関連した作業をやっていたりしました.
最近はGDB indexのサポートを追加しようと思ってその辺りについて調査したり,RISC-Vサポートの一環としてrelaxation等の最適化を実装するなどのタスクをしようとしています.
期間中は以下のPRについて作業をしていました(出した順).やっている内容に統一性が無いように見えるのは先述した理由によるものです:
- linker-diff: Detect differences between program segments
- Update dependabot schedule and replace deprecated link checker
- Support
-Bsymbolic-functions
- Support
-Bsymbolic
,-Bsymbolic-non-weak
,-Bsymbolic-non-weak-functions
and-Bno-symbolic
- add alias for
-shared
to-Bshareable
- Add flag to write symbols for PLT / GOT entries
- remove unnecessary nightly installation
- Nix Docker: fix some problems in Dockerfile
- Add missing write to symbol table for
--got-plt-syms
- Allow running the mold test suite
- change the description for
-Bsymbolic-non-weak
tests - linker-diff for RISC-V
- Filter mold tests by architecture
- Bump minimal Rust version to 1.88
- Split mold tests into submodules
- Add alternative syntax for some options
- Add missing steps in Ubuntu Dockerfile
- Unify parsing of
--option val
and--option=val
- Allow skipping of mold tests
- Update doc for cross-arch testing
- Fix Nix Docker
- Add
external_tests
feature flag - Rename
skip_tests.toml
- Add doc on steps to run external tests
- Stop downloading unnecessary submodules
- Run external tests in CI
- Add
--unresolved-symbols=
options support
リンカーの主務はいくつかのオブジェクトファイルを受け取って実行可能ファイルを作成することですが,実際にその様なことをつつがなく達成するのは容易ではなく,また同時に面白い点であると感じています.成果物である実行可能ファイルは単なるバイナリでしかなく,オプションの組み合わせ等によっては処理の内容が思わぬ場所にまで波及しかねないためです.
実例として,以前私は次のようなPRを出し,マージされました.これは動的リンクされたELFにおいては共有ライブラリ内の関数や外部のデータシンボルは通常GOTやPLTを介して呼び出されますが,シンボルテーブルのエントリーとして,それらのGOTやPLTのエントリーを$got
や$plt
のsuffixを付けた名前で追加することにより,直接的にこれらの値を参照できるようにするオプションを追加するものです.
マージされて実装が終わったものだと思いましたが,実際にこのオプションをデフォルトでオンにした状態だとテストが失敗するものがあるという報告が上がりました.これは次のPRで修正したのですが,いくつかあるシンボルテーブルにエントリーを追加する処理に不足があったのが主な原因でした.
このような,実装を誤ると簡単に成果物全体が破綻しうるというのはリンカーの面白い点であり,また難しい点でもあると思いました.最近は中間審査があったりつくばにいないがちだったので若干休んでいましたが,最終審査に向けてまた作業を再開しようと思います.
この割合自体は固定ですが,米ドルで支払われるので実際に受け取る金額はそのときの為替レートの影響を受けます ↩︎