При компиляции разделяемых библиотек в gcc опция -fPIC компилирует код как независимый от позиции. Есть ли причина (производительность или нет), по которой вы не скомпилируете все позиции кода независимо?
При компиляции разделяемых библиотек в gcc опция -fPIC компилирует код как независимый от позиции. Есть ли причина (производительность или нет), по которой вы не скомпилируете все позиции кода независимо?
Ответы:
Это добавляет косвенность. С независимым от позиции кодом вы должны загрузить адрес своей функции, а затем перейти к нему. Обычно адрес функции уже присутствует в потоке команд.
В этой статье объясняется, как работает PIC, и сравнивается его альтернатива - перемещение во время загрузки . Думаю, это имеет отношение к вашему вопросу.
Да, есть соображения производительности. Некоторые обращения фактически находятся под другим уровнем косвенного обращения, чтобы получить абсолютную позицию в памяти.
Также существует GOT (глобальная таблица смещений), в которой хранятся смещения глобальных переменных. Для меня это просто похоже на таблицу исправлений IAT, которая классифицируется как зависимая от позиции в Википедии и некоторых других источниках.
В дополнение к принятому ответу. Одна вещь, которая сильно ухудшает производительность кода 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», который значительно упрощает работу.
Поскольку реализация полностью независимого от позиции кода добавляет ограничение к генератору кода, которое может предотвратить использование более быстрых операций или добавить дополнительные шаги для сохранения этого ограничения.
Это может быть приемлемым компромиссом для многопроцессорной обработки без системы виртуальной памяти, когда вы доверяете процессам не вторгаться в память друг друга и, возможно, потребуется загрузить конкретное приложение по любому базовому адресу.
Во многих современных системах компромиссы производительности различны, и перемещение загрузчика часто обходится дешевле (он стоит каждый раз при первой загрузке кода), чем лучшее, что может сделать оптимизатор, если у него есть свобода действий. Кроме того, наличие виртуальных адресных пространств скрывает большую часть мотивации в первую очередь к независимости позиции.
Кроме того, оборудование виртуальной памяти в большинстве современных процессоров (используемых в большинстве современных операционных систем) означает, что большая часть кода (все приложения пользовательского пространства, за исключением необычного использования mmap и т.п.) не должна быть независимой от позиции. Каждая программа получает собственное адресное пространство, которое, по ее мнению, начинается с нуля.
position-independent code
имеет накладные расходы на производительность в большинстве архитектур, потому что для этого требуется дополнительный регистр.
Итак, это для повышения производительности.
В настоящее время операционная система и компилятор по умолчанию делают весь код независимым от позиции кодом. Попробуйте скомпилировать без флага -fPIC, код будет компилироваться нормально, но вы просто получите предупреждение. В операционных системах Windows для этого используется метод, называемый отображением памяти.
Вопрос датируется 2009 годом. Прошло десять лет, и теперь весь код фактически независим от позиции. Теперь это обеспечивается операционными системами и компиляторами. Нет возможности отказаться. Весь код принудительно компилируется с помощью PIE, и флаг -no-pic / -no-pie игнорируется как часть этого оправдания ASLR. Причина этого в том, чтобы замедлять работу приложений, которые раньше были быстрыми, и продавать новое оборудование под видом повышения безопасности. Это совершенно иррационально, потому что теперь большие объемы памяти позволяют нам вообще избавиться от ада динамического связывания, компилируя все приложения статически.
Так было и раньше, когда люди молча принимали реальный режим и отнятие других свобод. И я имею в виду, что MMU сильно замедляется из-за переключения контекста и задержки трансляции адресов. Вы не найдете MMU в системах, критичных к производительности, вроде тех, которые используются учеными для физических экспериментов.
Вы не жалуетесь, потому что даже не подозреваете, что все эти обучающие колеса мешают вашему коду. Что я могу сказать? Наслаждайтесь в 2 раза более медленным программным обеспечением с их PIC прямо сейчас! Более того, с появлением LLVM скоро появится принудительный JIT (управляемый код) без доступа к встроенной сборке x86, что еще больше замедлит любой код C / C ++. «Те, кто жертвуют свободой ради безопасности, не заслуживают того же».