すべてのコードが位置に依存しないのはなぜですか?


85

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


2
しかし、wowestは完全に正しいわけではありません。多くの関数呼び出しとジャンプは相対ジャンプを使用するため、移動した後にジャンプテーブルを必要としません。
不明

生成されたアセンブリコードを見ると、関数のアドレスがロードされているように見えますが、非fpicコードは単なるジャンプであるように見えます。私はあなたの発言を誤解していますか?
ojblass 2009年

@ojblassの意味は、一部のジャンプは、「0x400000にジャンプ」ではなく、「ここから50命令先にジャンプ」または「5命令後方にジャンプ」のようなものです。したがって、-fPICを使用して毎回アドレスをロードする必要があると言うのは、完全に正しいわけではありません。
不明

ウィキペディアの記事は良い説明を提供します。基本的に、一部のアーキテクチャでは、相対アドレスにジャンプする直接的な方法がありません。したがって、PICはこれらのarhcで使用するのに費用がかかります。詳細については、@ EvanTeranの回答を参照してください。
Alexei Sholik 2013

回答:


67

間接参照を追加します。位置に依存しないコードでは、関数のアドレスをロードしてからジャンプする必要があります。通常、関数のアドレスはすでに命令ストリームに存在します。


33

この記事では、PICがどのように機能するかを説明し、PICを代替手段であるロード時の再配置と比較します。それはあなたの質問に関連していると思います。


16
@ニック:私は同意しません。それが質問者を助けるなら、それは答えです。関連する記事を1つか2つ指すと、豊富な情報が得られます。
Eli Bendersky 2013年

5
この投稿には結論はなく、記事へのリンクだけです。パフォーマンスの問題のためにPICがデフォルトで使用されていないという手がかりすらありません。
ニック

10
このリンクは質問に答えることができますが、ここに答えの本質的な部分を含めて、参照用のリンクを提供することをお勧めします。リンクされたページが変更されると、リンクのみの回答が無効になる可能性があります。
ロブ

4
@Rob:生産的なことは、編集を提案し、泣き言にコメントを使用しないことです。この答えは4歳です。当時、SOには、答えがどのように見えるかについてそれほど厳格なルールがありません
でした

6
この投稿は「レビュー」の下に表示され、私がそうするように要求しました。他の誰かがそれにフラグを立てました。「泣き言コメント」は私ではなくSOが自動制作したものです。
ロブ

27

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

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

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


23

受け入れられた答えに加えて。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は、物事をはるかに簡単にする「RIP相対」モードを追加しました。


1
IIRC MIPSには、相対ジャンプを除いて、PC相対アドレス指定もありません
phuclv 2014

1
これは、実行中のアドレスを取得するためにシェルコードで使用される一般的な手法です。私はこれをいくつかのCTFソリューションで使用しました。
sherrellbc 2018年

2

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

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

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


1

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


4
ただし、VM-MMUの場合でも、異なる実行可能ファイルで使用されるときに同じ.soライブラリがメモリに1回だけロードされるようにするには、PICコードが必要です。
mmmmmmmm

1

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

したがって、これはパフォーマンスを目的としています。


0

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


-5

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

人々がリアルモードや他の自由を奪うことを黙って受け入れたとき、同じことが以前に起こりました。また、コンテキストスイッチとアドレス変換の遅延により、MMUの速度が大幅に低下します。科学者が物理実験をサンプリングするために使用するような、パフォーマンスが重要なシステムにはMMUはありません。

コードがこれらすべての補助輪によってハンディキャップされていることすら知らないので、文句を言うことはありません。何と言えばいい?今すぐPICで2倍遅いソフトウェアをお楽しみください!さらに、LLVMの登場により、すぐにJIT(マネージコード)が適用され、x86インラインアセンブリにアクセスできなくなり、C / C ++コードの速度がさらに低下します。「安全のために自由を犠牲にする人はどちらにも値しない。」


これは事実の表明にすぎません。10年前はPICはオプションでしたが、現在はデフォルトで必須です。非PIEコードが今後のOSリリースでサポートされるとは思えません。リアルモードのサポートがWindows9xの後に廃止されたように。したがって、何らかの方法でOSのロックを解除し、OSのサポートを再度有効にしない限り、PICを使用するかどうかの問題は理論的なコンピュータサイエンスのトピックになります。PICについて人々が知っておく必要がある最も重要なことは、これまでコンパイラが静的コンパイルをサポートするのに十分遅いことと、ほとんどのDLLの静的バージョンがあったことです。
SmugLispWeenie

1
あなたの最初のカップルの文章は単なる事実の陳述です。残りは、陰謀に隣接する意見です。
ミッチリンドグレン

まあ、ただ人々と話し、それについて彼らの意見を聞いてください。私は個人的に、PIC対非PICもイデオロギーの問題になっていることに気づきました。PICは、コードが大量生産され、全員が同じコピーを取得する共産主義と同等のプログラミングです。Non-PICは、同じコードの競合するバージョンが多数存在する資本主義と同等のプログラミングです。したがって、より左派的な考え方を持つ人々は、無意識のうちにPICをサポートして、お気に入りのイデオロギーが少なくともコンピューティングで機能する可能性があることを証明します。これらの同じ人々は、個人的に変更されたlibpngを使用することを言わないようにアドバイスします。
SmugLispWeenie

2
プログラミングのウェブサイトで政治的な暴言を出すことはできませんか?ありがとうございます
Ryan McCampbell
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.