web-dev-qa-db-ja.com

すべてのコードが位置独立にコンパイルされないのはなぜですか?

Gccで共有ライブラリをコンパイルするとき、-fPICオプションはコードを位置独立としてコンパイルします。すべてのコード位置に依存しないでコンパイルしない理由(パフォーマンスまたはその他)がありますか?

71
ojblass

インダイレクションを追加します。位置に依存しないコードでは、関数のアドレスを読み込んでからジャンプする必要があります。通常、関数のアドレスは命令ストリームにすでに存在します。

61
wowest

はい、パフォーマンス上の理由があります。一部のアクセスは、メモリ内の絶対位置を取得するために、事実上別の間接層の下にあります。

グローバル変数のオフセットを保存するGOT(グローバルオフセットテーブル)もあります。私には、これはIATフィックスアップテーブルのように見えます。これは、ウィキペディアや他のいくつかのソースによって位置依存として分類されています。

http://en.wikipedia.org/wiki/Position_independent_code

26
Unknown

この記事 PICの仕組みを説明し、代替と比較します- ロード時の再配置 。あなたの質問に関係があると思います。

25
Eli Bendersky

受け入れられた答えに加えて。 PICコードのパフォーマンスを大きく損なうことの1つは、x86の「IP相対アドレス指定」の欠如です。 「IP相対アドレス指定」を使用すると、現在の命令ポインターからXバイトのデータを要求できます。これにより、PICコードがはるかに簡単になります。

ジャンプと呼び出しは通常EIPに関連するため、これらは実際には問題になりません。ただし、データにアクセスするには、少し余分な策略が必要になります。時々、レジスタは、コードが必要とするデータへの「ベースポインタ」として一時的に予約されます。たとえば、一般的な手法は、x86での呼び出しの動作を悪用することです。

call label_1
.dd 0xdeadbeef
.dd 0xfeedf00d
.dd 0x11223344
label_1:
pop ebp            ; now ebp holds the address of the first dataword
                   ; this works because the call pushes the **next**
                   ; instructions address
                   ; real code follows
mov eax, [ebp + 4] ; for example i'm accessing the '0xfeedf00d' in a PIC way

この手法およびその他の手法により、データアクセスに間接層が追加されます。たとえば、gccコンパイラで使用されるGOT(グローバルオフセットテーブル)。

x86-64では、lotをよりシンプルにする「RIP相対」モードが追加されました。

19
Evan Teran

完全に位置に依存しないコードを実装すると、コードジェネレーターに制約が追加され、高速な操作の使用が妨げられたり、その制約を維持するための追加のステップが追加されたりします。

これは、仮想メモリシステムを使用せずにマルチプロセッシングを行うための許容可能なトレードオフです。この場合、プロセスは相互のメモリに侵入せず、特定のアプリケーションを任意のベースアドレスにロードする必要があります。

現代の多くのシステムでは、パフォーマンスのトレードオフが異なります。また、再配置ローダーは、自由に統治できる場合にオプティマイザーができる最善の方法よりも安価です(コードを最初にロードするたびにコストがかかります)。また、仮想アドレス空間の可用性は、そもそも位置独立の動機付けのほとんどを隠しています。

2
RBerteig

また、最新のほとんどのプロセッサ(最新のOSで使用されている)の仮想メモリハードウェアは、多くのコード(すべてのユーザースペースアプリ、mmapの風変わりな使用を禁止するなど)が位置に依存する必要がないことを意味します。すべてのプログラムは、ゼロから始まると考える独自のアドレス空間を取得します。

1
smcameron

position-independent codeは、追加のレジスタを必要とするため、ほとんどのアーキテクチャでパフォーマンスのオーバーヘッドがあります。

したがって、これはパフォーマンスのためです。

1
Eric Wang

質問の日付は2009年です。10年が経過し、現在、すべてのコードは実際には位置に依存していません。これは現在、オペレーティングシステムとコンパイラによって実施されています。オプトアウトする方法はありません。このASLRの言い訳の一部として、すべてのコードはPIEで強制コンパイルされ、-no-pic/-no-pieフラグは無視されます。その理由は、セキュリティの向上を装って、以前は高速だったアプリの速度を落とし、新しいハードウェアを販売するためです。これは完全に非合理的です。メモリサイズが大きくなったため、動的リンクの問題をまったくなくし、すべてのアプリを静的にコンパイルできるようになったためです。

以前は、人々が静かにリアルモードや他の自由を奪うことを受け入れたときにも同じことが起こりました。 MMUは、コンテキストの切り替えとアドレス変換の待ち時間のために、大幅な速度低下を招きます。科学者が物理実験をサンプリングするために使用するような、パフォーマンスが重要なシステムではMMUは見つかりません。

文句を言わないのは、これらすべてのトレーニングホイールによってコードが障害を受けていることすら知らないからです。何と言えばいい? PICで2倍遅いソフトウェアを今すぐお楽しみください!さらに、LLVMの出現により、x86インラインアセンブリへのアクセスなしで、JIT(マネージコード)がまもなく施行され、C/C++コードの速度がさらに低下します。 「安全のために自由を犠牲にする者はどちらにも値しない。」

1
SmugLispWeenie

現在、オペレーティングシステムとコンパイラはデフォルトですべてのコードを位置に依存しないコードとして作成しています。 -fPICフラグなしでコンパイルすると、コードは正常にコンパイルされますが、警告が表示されるだけです。OSのようなウィンドウでは、メモリマッピングと呼ばれる手法を使用してこれを実現します。

0