Я вижу, что никто не ответил на этот вопрос, поэтому я думаю, что я попробую.
Я попытаюсь показать на практическом примере, как это работает.Вот некоторый 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
Данные о перемещении выглядят следующим образом:
Relocation section '.rel.dyn' at offset 0x34c contains 6 entries:
Offset Info Type Sym.Value Sym. Name
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
<b>000016b4 00000d06 R_386_GLOB_DAT 000016e0 hello</b>
000016b8 00000406 R_386_GLOB_DAT 00000000 __cxa_finalize
Relocation section '.rel.plt' at offset 0x37c contains 5 entries:
Offset Info Type Sym.Value Sym. Name
000016c8 00000107 R_386_JUMP_SLOT 00000000 __gmon_start__
<b>000016cc 00000507 R_386_JUMP_SLOT 000004fc please_say</b>
<b>000016d0 00000807 R_386_JUMP_SLOT 00000540 say</b>
<b>000016d4 00000307 R_386_JUMP_SLOT 00000000 printf</b>
000016d8 00000407 R_386_JUMP_SLOT 00000000 __cxa_finalize
Элемент R_386_GLOB_DAT для hello - это запись GOT.Аналогично, элементы R_386_JUMP_SLOT для скажем, please_say и printf являются записями PLT.Они происходят от использования позиционно-независимого кода, а не от того, что мы создали общий объект.
После выполнения одного и того же процесса сборки без -fPIC мы получаем различные перемещения.Итак,
gcc -c *.c
gcc -shared -o libtemp.so *.o
readelf -r libtemp.so
дает нам
Relocation section '.rel.dyn' at offset 0x34c contains 9 entries:
Offset Info Type Sym.Value Sym. Name
00001674 00000008 R_386_RELATIVE
00001678 00000008 R_386_RELATIVE
<b>000004d3 00000802 R_386_PC32 000004f0 say</b>
<b>000004e0 00000502 R_386_PC32 000004cc please_say</b>
<b>000004f7 00000d01 R_386_32 00001678 hello</b>
<b>000004ff 00000302 R_386_PC32 00000000 printf</b>
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
Relocation section '.rel.plt' at offset 0x394 contains 2 entries:
Offset Info Type Sym.Value Sym. Name
0000166c 00000107 R_386_JUMP_SLOT 00000000 __gmon_start__
00001670 00000407 R_386_JUMP_SLOT 00000000 __cxa_finalize
Теперь общий объект имеет знакомые перемещения для всех определений.Существует абсолютное перемещение hello и относительное перемещение PC для функций.
Что это значит?Ну, таблицы GOT и PLT все еще там.Следует отметить две важные вещи.Во-первых, для скомпилированного кода нет записей GOT или PLT.Во-вторых, таблицы GOT и PLT все еще нужны.Они используются для инициализации и очистки (возможно, для стандартной библиотеки).Поскольку вы используете пользовательский загрузчик ELF, вероятно, было бы целесообразно реализовать некоторую базовую поддержку записей GOT и PLT, даже если вместо этого ваше основное приложение выполняет стандартные перемещения.
После этого ваше приложение будет платить стоимость перемещения., но не от позиции независимости.