この質問には誰も答えていないので、試してみようと思います。
実際の例を使用して、これがどのように機能するかを示します。これは、外部グローバル関数とデータを人為的ではあるが意図的に組み合わせた C コードです。これは、再配置の基本です。
/* hello.c */
char* hello = "hello";
/* say.c */
#include "stdio.h"
extern char* hello;
void say(void){
printf(hello);
}
/* main.c */
extern void say(void);
void please_say(void){
say();
}
int main(void){
please_say();
return 0;
}
共有オブジェクト/ライブラリを取得する通常の方法は、各 C ファイルを -fPIC でコンパイルし、ロットを -shared でリンクすることです。その後、readelf を使用して再配置を調べることができます。このようなもの:
gcc -fPIC -c *.c
gcc -shared -o libtemp.so *.o
readelf -r libtemp.so
移転データは以下の通りです。
オフセット 0x34c の再配置セクション '.rel.dyn' には 6 つのエントリが含まれています。
オフセット情報 タイプ Sym.Value Sym. 名前
000016dc 00000008 R_386_RELATIVE
000016e0 00000008 R_386_RELATIVE
000016ac 00000106 R_386_GLOB_DAT 00000000 __gmon_start__
000016b0 00000206 R_386_GLOB_DAT 00000000 _Jv_RegisterClasses
000016b4 00000d06 R_386_GLOB_DAT 000016e0 こんにちは
000016b8 00000406 R_386_GLOB_DAT 00000000 __cxa_finalize
オフセット 0x37c の再配置セクション '.rel.plt' には 5 つのエントリが含まれています。
オフセット情報 タイプ Sym.Value Sym. 名前
000016c8 00000107 R_386_JUMP_SLOT 00000000 __gmon_start__
000016cc 00000507 R_386_JUMP_SLOT 000004fc please_say 000016d0
00000807 R_386_JUMP_SLOT 00000540 say
000016d4 00000307 R_386_JUMP_SLOT 00000000 printf
000016d8 00000407 R_386_JUMP_SLOT 00000000 __cxa_finalize
hello の R_386_GLOB_DAT アイテムは GOT エントリです。同様に、say、please_say、printf の R_386_JUMP_SLOT アイテムは PLT エントリです。それらは、共有オブジェクトを作成したという事実ではなく、位置に依存しないコードの使用から生じます。
-fPIC を使用せずに同じビルド プロセスを実行すると、再配置が異なります。そう
gcc -c *.c
gcc -shared -o libtemp.so *.o
readelf -r libtemp.so
私たちに与える
オフセット 0x34c の再配置セクション「.rel.dyn」には、9 つのエントリが含まれています。
オフセット情報 タイプ Sym.Value Sym. 名前
00001674 00000008 R_386_RELATIVE
00001678 00000008 R_386_RELATIVE
000004d3 00000802 R_386_PC32 000004f0 say
000004e0 00000502 R_386_PC32 000004cc please_say 000004f7 00000d01
R_386_32 00001678 こんにちは
00001654 00000106 R_386_GLOB_DAT 00000000 __gmon_start__
00001658 00000206 R_386_GLOB_DAT 00000000 _Jv_RegisterClasses
0000165c 00000406 R_386_GLOB_DAT 00000000 __cxa_finalize
オフセット 0x394 の再配置セクション '.rel.plt' には 2 つのエントリが含まれています。
オフセット情報 タイプ Sym.Value Sym. 名前
0000166c 00000107 R_386_JUMP_SLOT 00000000 __gmon_start__
00001670 00000407 R_386_JUMP_SLOT 00000000 __cxa_finalize
これで、共有オブジェクトは、すべての定義に対しておなじみの再配置を行いました。hello の絶対再配置と、関数の PC 相対再配置があります。
これは何を意味するのでしょうか?まあ、GOT と PLT テーブルはまだそこにあります。注意すべき重要な点が 2 つあります。1 つ目は、コンパイルされたコードに GOT または PLT エントリがないことです。2 つ目は、GOT テーブルと PLT テーブルがまだ必要であることです。これらは初期化とクリーンアップに使用されています (おそらく標準ライブラリ用)。カスタム ELF ローダーを使用しているため、メイン アプリケーションが代わりに標準の再配置を行う場合でも、GOT および PLT エントリの基本的なサポートを実装することをお勧めします。
アプリケーションは、位置の独立性ではなく、再配置の代償を払います。