Почему не все скомпилированные позиции кода независимы?
при компиляции общих библиотек в gcc опция-fPIC компилирует код как независимый от позиции. Есть ли какая-либо причина (производительность или иначе), почему вы не будете компилировать все позиции кода независимо?
8 ответов:
Это добавляет косвенность. С позиции независимого кода Вы должны загрузить адрес вашей функции, а затем перейти к нему. Обычно адрес функции уже присутствует в потоке команд.
Да есть причины производительности. Некоторые обращения эффективно находятся под другим уровнем косвенности, чтобы получить абсолютное положение в памяти.
есть также GOT (Global offset table), который хранит смещения глобальных переменных. Для меня это просто выглядит как таблица исправлений IAT, которая классифицируется как позиция, зависящая от Википедии и нескольких других источников.
в этой статье объясняет, как работает PIC и сравнивает его с альтернативой -загрузить время переезда. Я думаю, что это имеет отношение к вашему вопросу.
В дополнение к принятой ответ. Одна вещь, которая сильно вредит производительности кода PIC, - это отсутствие "относительной IP-адресации" на x86. С помощью "относительной IP-адресации" вы можете запросить данные, которые являются X байтами из текущего указателя инструкции. Это сделало бы PIC-код намного проще.
прыжки и вызовы, как правило, относительны EIP, поэтому они действительно не представляют проблемы. Тем не менее, доступ к данным потребует немного дополнительного обмана. Иногда регистрация будет временно зарезервировано как "базовый указатель" на данные, которые требуются коду. Например, распространенным методом является злоупотребление тем, как вызовы работают на x86:
call label_1 .dd 0xdeadbeef .dd 0xfeedf00d .dd 0x11223344 label_1: pop ebp ; now ebp holds the address of the first dataword ; this works because the call pushes the **next** ; instructions address ; real code follows mov eax, [ebp + 4] ; for example i'm accessing the '0xfeedf00d' in a PIC way
этот и другие методы добавляют уровень косвенности к доступам к данным. Например, GOT (глобальная таблица смещений), используемая компиляторами gcc.
x86-64 добавлен режим "RIP relative", который делает вещи много проще.
потому что реализация полностью независимого от позиции кода добавляет ограничение к генератору кода, который может предотвратить использование более быстрых операций или добавить дополнительные шаги для сохранения этого ограничения.
Это может быть приемлемым компромиссом, чтобы получить многопроцессорную обработку без системы виртуальной памяти, где Вы доверяете процессам, чтобы не вторгаться в память друг друга и, возможно, потребуется загрузить конкретное приложение по любому базовому адресу.
во многих современных системах компромиссы производительности различны, и перемещение загрузчика часто обходится дешевле (это стоит любого времени, когда код сначала загружается), чем лучшее, что может сделать оптимизатор, если у него есть свободное время. Кроме того, наличие виртуальных адресных пространств скрывает большую часть мотивации для независимости позиции в первую очередь.
кроме того, оборудование виртуальной памяти в большинстве современных процессоров (используемых большинством современных ОС) означает, что множество кода (все приложения пользовательского пространства, запрещающие изворотливое использование mmap или тому подобное) не должно быть независимым от позиции. Каждая программа получает свое собственное адресное пространство, которое, по ее мнению, начинается с нуля.
position-independent code
имеет накладные расходы производительности на большинстве архитектур, потому что он требует дополнительного регистра.Итак, это для целей исполнения.
В настоящее время операционная система и компилятор по умолчанию делают весь код как независимый от позиции код. Попробуйте выполнить компиляцию без флага-fPIC, код будет компилироваться нормально, но вы просто получите предупреждение.ОС, как и windows, используют метод, называемый сопоставлением памяти для достижения этой цели.