Добавление контрапункта: да, в этом есть реальное применение, но я думаю, что оно действительно сломано не только с динамическими библиотеками, но и с независимыми от позиции исполняемыми файлами.
ld
сам будет использовать символы для встраивания бинарных файлов в исполняемые файлы:
ld -r -b binary hello_world.txt -o hello_world.o
это создаст объектный файл со следующими символами:
000000000000000c g .data 0000000000000000 _binary_hello_world_txt_end
000000000000000c g *ABS* 0000000000000000 _binary_hello_world_txt_size
0000000000000000 g .data 0000000000000000 _binary_hello_world_txt_start
, чтобы исполняемый файл, который включает их, мог просто использовать extern
переменные для доступа к ним. (... как в случае: наш текст "hello world" из hello_world.txt является единственным в разделе .data
длиной 0xc
).
При связывании этого объектного файла с исполняемым файлом (а не с разделением символов) получается
0000000000411040 g .data 0000000000000000 _binary_hello_world_txt_start
000000000041104c g .data 0000000000000000 _binary_hello_world_txt_end
000000000000000c g *ABS* 0000000000000000 _binary_hello_world_txt_size
и мы можем делать такие вещи, как
extern char _binary_hello_world_txt_start;
extern char _binary_hello_world_txt_size; // "char" is just made up in this one
// (...)
printf("text: %s\n", &_binary_hello_world_txt_start);
printf("number of bytes in it: %d\n", (int) (&_binary_hello_world_txt_size));
(да, выглядит довольно странно, что мы ищем адрес чего-то (для чего обычно используются символы), а затем мы рассматриваем его как целое число ... но на самом деле это работает.)
Обратите внимание, как компоновщик знает, что он должен перемещать, а что нет; указатели данных относятся к .data
, в то время как размер равен *ABS*
, который, как описывает Гил, не должен перемещаться (... поскольку он не рассчитан относительно чего-либо).
Однако, это работает только в не зависящих от позиции исполняемых файлах . Как только вы перейдете от -fPIE
(который по умолчанию в современных дистрибутивах Linux используется по умолчанию для gcc) к -no-pie
, динамический компоновщик переместит все, включая символы *ABS*
. Это происходит во время выполнения во время выполнения: таблицы символов выглядят одинаково, независимо от того, как исполняемый файл был скомпилирован.
Тот факт, что то же самое происходит с разделяемыми библиотеками, кажется, является следствием одного и того же: перемещение динамически размещаемых двоичных файлов (независимо от позиции исполняемого файла или совместно используемой библиотеки) приводит к аналогичным перемещениям, которые имеют смысл для функций, включенных в сам двоичный файл, но не для *ABS*
данных.
К сожалению, у меня нет ответа ни на один из вопросов: я также думаю, что это сделано неправильно, и я не знаю, как это исправить (см. Получение значения символов * ABS * от C для другой проблемы, сталкивающейся с той же самой проблемой).
Однако, учитывая, что даже сама GNU ld выбирает таким образом вставлять размер в качестве символа ... Я думаю, что это приложение / вопрос полностью допустимо, так что ответьте:
- ... это сделано, потому что на самом деле реализация не верна
- в качестве обходного пути приходит на ум «генерация заголовочного файла с абсолютными адресами в строке» после ответа Employed Russian
... но на самом деле мне было бы интересно узнать, как именно пропатчить таблицу перемещений, как Гил упоминал в вопросе!