位置独立コードは絶対位置ではなく相対位置のみを使用すると言われていますが、これは c とアセンブリでそれぞれどのように実装されていますか?
char test[] = "string";
例として、相対アドレスで参照する方法を考えてみましょう。
Cでは、位置に依存しないコードはコンパイラーの実装の詳細です。サポートされているかどうか、およびその方法については、コンパイラのマニュアルを参照してください。
アセンブリでは、位置に依存しないコードが命令セットアーキテクチャの詳細です。PC(プログラムカウンター)レジスタの読み取り方法、その効率、およびコードアドレスをデータアドレスに変換する際の推奨されるベストプラクティスについては、CPUのマニュアルを参照してください。
最近のほとんどのオペレーティングシステムでは、コードとデータが異なるページに分割されているため、位置相対データはあまり一般的ではありません。自己完結型の実行可能モジュールを実装するのは良い方法ですが、今日最も一般的なそのようなものはウイルスです。
x86 では、原則として、位置に依存しないコードは次のようになります。
call 1f
1: popl %ebx
その後、ebx
アクセスされるデータと命令のアドレスとの間の距離に等しいディスプレースメントを持つベース ポインターとして使用されますpopl
。
実際にはもっと複雑なことが多く、通常は小さなサンク関数を使用して PIC レジスタを次のようにロードします。
load_ebx:
movl 4(%esp),%ebx
addl $some_offset,%ebx
ret
ここで、オフセットは、サンクが返さebx
れたときに、プログラム/ライブラリ内の指定された特別なポイント (通常はグローバル オフセット テーブルの先頭) へのポインターが含まれるように選択され、その後のすべてのebx
-relative アクセスは単純に間の距離を使用できます。目的のデータとオフセットとして指定された特別なポイント。
他のアーチでも原則はすべて似ていますが、プログラムカウンターをロードするより簡単な方法があるかもしれません。多くの場合、単にレジスタpc
またはip
レジスタを相対アドレッシング モードで通常のレジスタとして使用できます。
擬似コードでは、次のようになります。
lea str1(pc), r0 ; load address of string relative to the pc (assuming constant strings, maybe)
st r0, test ; save the address in test (test could also be PIC, in which case it could be relative
; to some register)
前の回答で述べたように、コンパイラとCPUアーキテクチャに大きく依存します。調べる方法の1つは、適切なフラグ(gccの場合は-PIC -S)を使用してコンパイルし、取得したアセンブリ言語を確認することです。