LINUX.ORG.RU

История изменений

Исправление KivApple, (текущая версия) :

Дело в том, что в статической линковке при вызове функции или обращении к глобальной переменной происходит адресация по абсолютному адресу, а в динамической — обычно адресация относительно instruction pointer'а.

На архитектуре x86 действительно нет адресации относительно IP. Только всякими косвенными методами (типа вычислить базу кода каким-нибудь костылём, а затем прибавить смещение). Только вот есть такая штука как релокации. Можно обойтись без всякого PIC-кода, а просто заполнить таблицу релокаций, указав все места, где обращаются к глобальным переменным. И линкер заботливо прибавит ко всем нужным адресам базу, по которой загружен код. Команды переходов на x86 и так всегда относительные (кроме «дальних» вызовов, но многосегментная модель кода не поддерживается ни одним современными компилятором). Так что чисто теоретически можно не терять производительность.

А вот на x86_64 ситуация ещё интереснее. Нет там инструкций абсолютной адресации. Там вся адресация строится относительно RIP (теперь это стало возможно делать напрямую и без костылей), либо другого регистра. Хочешь обратиться по абсолютному адресу - грузи его в регистр как константу, а затем обращайся относительно этого регистра. Так что x86_64 код уже по дефолту почти PIC. Проблемы лишь с адресами, которые заданы явно в секции данных. Например, если ты инициализируешь глобальную переменную адресом другой глобальной переменной. Но эта проблема отлично решается релоками.

Таким образом написание PIC-кода если и приводит к просадкам производительности, то лишь в особых случаях. А если компилятор достаточно умён, то лишь ОС придётся поработать чуть дольше при загрузке бинарника.

Исходная версия KivApple, :

Дело в том, что в статической линковке при вызове функции или обращении к глобальной переменной происходит адресация по абсолютному адресу, а в динамической — обычно адресация относительно instruction pointer'а.

На архитектуре x86 действительно нет адресации относительно IP. Только всякими косвенными методами (типа вычислить базу кода каким-нибудь костылём, а затем прибавить смещение). Только вот есть такая штука как релокации. Можно обойтись без всякого PIC-кода, а просто заполнить таблицу релокаций, указав все места, где обращаются к глобальным переменным. И линкер заботливо прибавит ко всем нужным адресам базу, по которой загружен код. Команды переходов на x86 и так всегда относительные (кроме «дальних» вызовов, но многосегментная модель кода не поддерживается ни одним современными компилятором). Так что чисто теоретически можно не терять производительность.

А вот на x86_64 ситуация ещё интереснее. Нет там инструкций абсолютной адресации. Там вся адресация строится относительно RIP (теперь это стало возможно делать напрямую и без костылей), либо другого регистра. Хочешь обратиться по абсолютному адресу - грузи его в регистр как константу, а затем обращайся относительно этого регистра. Так что x86_64 код уже по дефолту почти PIC. Проблемы лишь с адресами, которые заданы явно в секции данных. Например, если ты инициализируешь глобальную переменную адресом другой глобальной переменной. Но эта проблема отлично решается релоками.

Таким образом написание PIC-кода если и приводит к просадкам производительности, то лишь в особых случаях.