Почему код PIC реализован для разыменования дважды, а не один раз?
Из Позиционно-независимого кода (PIC) в разделяемых библиотеках я узнал, что при вызове кода PIC в linux сначала вызывается функция plt, а затем она вызывает (tail call) фактическую функцию. При первом вызове функции будет загружена функция.
Вопрос в том, почему не разыменовывать и вызывать указатель на функцию в GOT-записи напрямую, поскольку это имеет ряд преимуществ:
- Улучшенная производительность;
- Меньше места в памяти;
- Функции plt могут быть выгружены, если не нужны.
Я не вижу причин, почему это так не реализовано.
Редактировать:
Текущий импл:
Вызовите функцию plt, перейдите по адресу, указанному в записи таблицы GOT.
При первом вызове точка входа точно указывает на следующую инструкцию того же функционала plt.
В остальной части функции plt он загрузит аргумент в загрузчик и вызовет загрузчик.
После загрузки соответствующая запись GOT будет содержать адрес функции.
Как вы можете видеть, я не думаю, что есть причина добавлять этот дополнительный слой, поскольку то, что делает plt funcs, это просто прыжок (хвостовой вызов), даже удаление первой инструкции перехода и прямой вызов записи GOT будут работать.
Так что я не могу понять, почему они разработали это в первый раз.
Примечание: я также разместил тот же контент в stackru: почему код PIC реализован для разыменования дважды, а не один раз? Вы можете ответить на мой вопрос там, если хотите.