共有ライブラリと実行可能ファイルは、PIC コードを有効または無効にしてビルドできます。つまり、PIC なしでビルドした場合でも、他のアプリで使用できます。ただし、PIC 以外のライブラリはどこでもサポートされているわけではありませんが、Linux ではサポートされていますが、いくつかの制限があります。
=== これは必要のない簡単な説明です ;-) ===
PIC が行うことは、コードの位置を独立させることです。各共有ライブラリはメモリ内のある位置にロードされます - セキュリティ上の理由から、この場所はしばしばランダム化されます - したがって、コード内の「絶対」メモリ参照は実際には「絶対」にはなりません - 実際、それらはライブラリのメモリセグメントの開始に関連しています住所。ライブラリがロードされた後、それらを調整する必要があります。
これは、それらすべてを調べて (それらのアドレスはファイル ヘッダーに格納されます)、修正することで実行できます。しかし、これは遅く、ベースアドレスが異なる場合、「修正された」イメージをプロセス間で共有できません。
したがって、通常は別の方法が使用されます。メモリへの各参照は、特殊レジスタ (通常は ebx) を介して行われます。関数が呼び出されると、最初に、ebx 値をライブラリのメモリ セグメント アドレスに調整する特別なコード ブロックにジャンプします。次に、関数は [ebx + 既知のオフセット] を使用してそのデータにアクセスします。
したがって、すべての関数やメモリ参照ではなく、プログラムごとにこのコード ブロックのみを調整する必要があります。
関数が同じ共有ライブラリの他の関数から呼び出されることがわかっている場合、コンパイラ/リンカーは PIC レジスタ (ebx) の調整を省略できることに注意してください。これは、関数が既に正しい値を持っていることがわかっているためです。一部のアーキテクチャ (特に x86_64) では、プログラムは IP (現在の命令ポインター) に関連するデータにアクセスできます。IP は既に絶対調整されているため、ebx のような特別なレジスターとその調整の必要性がなくなります。
=== 読まずにスキップできるセクションの終わり ===
では、なぜPICなしで何かを構築したいのでしょうか?
まず第一に、各関数の開始時にレジスタを調整するために追加のコードが実行され、オプティマイザが貴重なレジスタを使用できないため、プログラムが数パーセント遅くなります (x86 のみ)。多くの場合、関数は同じライブラリから呼び出されたのか別のライブラリから呼び出されたのかを認識できないため、内部呼び出しでさえペナルティを受けます。したがって、速度を最適化したい場合は、PIC なしでコンパイルしてみてください。
次に、お気づきのように、コード サイズが少し大きくなります。これは、各関数に PIC レジスタをセットアップするための命令がさらにいくつか含まれるためです。
これは、リンク時の最適化 (--lto スイッチ) と保護された関数の可視性を使用して、外部からまったく呼び出されない関数をコンパイラが認識し、PIC コードを必要としない場合に、ある程度回避できます。しかし、私はそれを試していません(まだ)。
そして、なぜPICを使いたいのですか?安全性が高いため (これはアドレス空間のランダム化に必要です)。すべてのシステムが非 PIC ライブラリをサポートしているわけではないためです。PIC 以外のライブラリでは、起動時の読み込み時間が遅くなる可能性があるため (テーブル スタブだけでなく、コード セグメント全体を絶対アドレスに調整する必要があります)。また、ロードされたライブラリ セグメントは、別のスペースにロードされている場合は共有できません (つまり、より多くのメモリが使用される可能性があります)。次に、すべてのコンパイラ/リンカー フラグが非 PIC ライブラリと互換性があるわけではありません (私が覚えていることから、スレッド ローカル サポートについて何かがあると思います)。そのため、非 PIC コードをまったくビルドできない場合があります。
そのため、PIC 以外のコードは少しリスクが高く (安全性が低く)、常に取得できるとは限りませんが、必要な場合 (速度など) には理由があります。