カーネルビルドシステムの調査中、v4.19より前はカーネルが増分リンク()を使用していて、次のようにld -r
シンアーカイブ()に移動したことを発見しました。ar T
vmLinux、vmlinuz、vmlinux.bin、zimage、bzimageなどのカーネルMakefile用語の違いは何ですか?私は気づいた
その後、リンク速度の向上が大幅に行われていることを確認するために、合成インクリメンタルリンクベンチマークを作成しました。https://stackoverflow.com/questions/29391965/what-is-partial-linking-in-gnu-linker/53959624#53959624しかし、それは私の基準ではありません。
だから私の質問は:カーネルが増分リンクまたはシンアーカイブを使用するのはなぜですか?
ビルドを高速化するためのものですか、それとも他の理由のためですか?
増分接続を導入したコミットは何ですか?これにより私はその根拠を理解することができましたgit log
。git log --grep 'thin archive'
(a5967db9af51a84f5e181600954714a9e4c69f1f)を使用すると、コンパクトなアーカイブに移動しますが、増分リンクされたアーカイブを簡単に取得できないことがわかりました。
ビルドを高速化するために存在する場合は、速度の向上を確認するために増分接続を必要とせずにVSとの接続をすばやくテストする方法はありますか?
ベストアンサー1
弱いファイルの理由
私はパッチ作成者の一人であるNicholas Pigginに電子メールで連絡しました。
問題は、増分リンクされたオブジェクトファイルが大きすぎてリンカーがオブジェクト間で生成されたコードを指す必要があるトランポリンの再配置を挿入できないことです。
増分ビルドの理論的根拠についてはまだ答えを受けていません。
彼の素晴らしい答えは次のとおりです。
これはあなたがどれだけ知っているかに応じてかなり長い答えです。いくつかの理由があります。このパッチを作成したStephenの主な動機は、非常に大きなカーネルを正常に接続できるようにすることでした。
他の利点は次のとおりです。
これは中間ビルド成果物を保存する「より良い」方法です。出力コードを1つの場所に保存し、すべてが接続されるまで参照(最小アーカイブ)を使用して追跡します。したがって、特に大規模なビルドおよびデバッグ情報の場合、より少ないIOおよびディスク領域が必要です。
Linuxは、ビルドする出力ディレクトリが数少ない平均的な最新のワークステーション用の巨大なプロジェクトではなく、すべてキャッシュに保存され、ファイルを増分的に接続する時間が非常に高速です。したがって、Linuxの場合、ビルド速度の利点は一般的に小さいです。
これにより、リンカーは少し優れたコードを生成できます。ファイルを再配置し、リンカスタブをより最適に配置します。
アップストリームLTOビルドのサポートは十分ではありませんが、LTOビルドでよりうまく機能する傾向があります。
しかし、元の動機に戻りましょう。
最後に、リンクされていない再配置可能オブジェクトファイルを作成すると、他の場所で定義されている関数と変数へのシンボルへの参照を含むコードの束が得られます。
--- a.S --- bl myfunc ---
で組み立てる
a.o: file format elf64-powerpcle
.textセクションの分解:
0000000000000000 <.text>: 0: 01 00 00 48 bl 0x0
したがって、コードにはNIA + 0(つまりそれ自体)の分岐がありますが、これは私たちが要求したものではありません。再配置をダンプすると、欠落しているビットが表示されます。
.textセクションの分解:
0000000000000000 <.text>: 0: 01 00 00 48 bl 0x0 0: R_PPC64_REL24 myfunc
再配置はコードではなく.textセクションにはありませんが、その位置の命令にmyfuncという記号の24ビット相対オフセットがあることを示すいくつかのELFメタデータがあります。
オブジェクトを「最終的にリンク」すると、ファイルはデフォルトで一緒にリンクされ、これらの再配置の問題は、正しい場所を指すようにコードとデータを調整することによって解決されます。
aSをmyfuncシンボルを含むbSに関連付けると、次の結果が表示されます。
c: file format elf64-powerpcle Disassembly of section .text: 00000000100000d8 <_start>: 100000d8: 05 00 00 48 bl 100000dc <myfunc> 00000000100000dc <myfunc>: 100000dc: 01 00 63 38 addi r3,r3,1 100000e0: 20 00 80 4e blr
再配置メタデータが削除され、ブランチが正しいオフセットを指します。
したがって、リンカは実際にリンク時にコマンドを調整します。さらに一歩進んで指示を生成します。大規模なビルドがあり、ブランチが24ビットオフセットでmyfuncに到達できない場合、リンカは24ビットでアクセス可能なコードにトランポリン(スタブ、PLT、プロシージャリンクテーブルとも呼ばれる)を挿入します。その後、トランポリンは目標に達するために長い枝を使用します。
リンカーは、コードの途中に何かを追加すると、中間を通過する相対参照が失われるため、コードのどこにもこれらのトランポリンを配置できません。リンカーは知らない みんな.oファイルの参照、未解決の参照のみが適用されます。したがって、リンカーは.oファイルを一緒にリンクする場合にのみ、その参照を確認する前に.oファイル間にトランポリンを配置する必要があります。
以前の増分ビルド方法は、ビルドディレクトリのルートに近づくにつれて、.oファイルをより大きな.oファイルにマージしました。したがって、.oファイルが大きすぎると、ブランチがトランポリンに到達するために独自の.oファイルの外に到達できない場合に問題が発生します。この参照を解決する方法はありません。
シンアーカイブの場合、最終接続は数千の非常に小さな .o ファイルで行われます。これにより、リンカーがこれらのトランポリンを配置するときに最大限の柔軟性を得ることができるため、この制限に当たることはありません。