Опция GCC -fPIC

Я читал о Опции GCC для условных обозначений кода, но не мог понять, что делает "Создавать независимый по положению код (PIC)". Пожалуйста, дайте пример, чтобы объяснить мне, что это значит.

Ответ 1

Независимый код позиции означает, что сгенерированный машинный код не зависит от того, что он находится на определенном адресе, чтобы работать.

например. скачки будут генерироваться как относительные, а не абсолютные.

Псевдо-сборки:

PIC: Это будет работать, был ли код указан по адресу 100 или 1000

100: COMPARE REG1, REG2
101: JUMP_IF_EQUAL CURRENT+10
...
111: NOP

Non-PIC: Это будет работать, только если код находится по адресу 100

100: COMPARE REG1, REG2
101: JUMP_IF_EQUAL 111
...
111: NOP

EDIT: в ответ на комментарий.

Если ваш код скомпилирован с -fPIC, он подходит для включения в библиотеку - библиотека должна быть перемещена из своего предпочтительного места в памяти на другой адрес, может быть другая уже загруженная библиотека по адресу вашей библиотеки предпочитает.

Ответ 2

Я попытаюсь объяснить, что уже было сказано более простым способом.

Всякий раз, когда загружается общая библиотека, загрузчик (код в ОС, который загружает любую запущенную программу) изменяет некоторые адреса в коде, в зависимости от того, где был загружен объект.

В приведенном выше примере "111" в коде, отличном от ПОС, записывается загрузчиком при первом загрузке.

Для не общих объектов вы можете захотеть, чтобы это было так, потому что компилятор может сделать некоторые оптимизации для этого кода.

Для общего объекта, если другой процесс захочет "связать" с этим кодом, он должен прочитать его на одни и те же виртуальные адреса или "111" не имеет смысла. но это виртуальное пространство уже может быть использовано во втором процессе.

Ответ 3

Код, который встроен в разделяемые библиотеки, обычно должен быть независимым от позиции кодом, так что общая библиотека может быть легко загружена (более или менее) любым адресом в памяти. Опция -fPIC гарантирует, что GCC создает такой код.

Ответ 4

Добавление далее...

Каждый процесс имеет одно и то же виртуальное адресное пространство (если рандомизация виртуального адреса останавливается с использованием флага в ОС Linux) (Для более подробной информации Отключите и снова включите рандомизацию размещения адресного пространства только для себя)

Итак, если его один exe без общей привязки (гипотетический сценарий), то мы всегда можем дать тот же виртуальный адрес той же инструкции asm без какого-либо вреда.

Но когда мы хотим связать общий объект с exe, мы не уверены в стартовом адресе, назначенном для общего объекта, поскольку он будет зависеть от порядка, в котором были связаны общие объекты. Как сказано, инструкция asm внутри .so всегда будет иметь различный виртуальный адрес в зависимости от процесса, к которому он привязан.

Таким образом, один процесс может дать начальный адрес .so как 0x45678910 в своем собственном виртуальном пространстве, а другой процесс в то же время может дать начальный адрес 0x12131415 и если они не используют относительную адресацию .so вообще не будет работать.

Поэтому они всегда должны использовать режим относительной адресации и, следовательно, вариант fpic.

Ответ 5

Ссылка на функцию в динамической библиотеке разрешается при загрузке библиотеки или во время выполнения. Таким образом, исполняемый файл и динамическая библиотека загружаются в память при запуске программы. Адрес памяти, в который загружается динамическая библиотека, не может быть определен в поскольку фиксированный адрес может столкнуться с другой динамической библиотекой, требующей того же адреса.


Существует два часто используемых метода решения этой проблемы:

1.Relocation. Все указатели и адреса в коде изменяются, если необходимо, для соответствия фактическому адресу нагрузки. Перемещение выполняется компоновщиком и загрузчиком.

2. Независимый от кода код. Все адреса в коде относятся к текущей позиции. Общие объекты в Unix-подобных системах по умолчанию используют независимый по позиции код. Это менее эффективно, чем перемещение, если программа работает в течение длительного времени, особенно в 32-битном режиме.


Название " независимый от позиции код" на самом деле подразумевает следующее:

  • Раздел кода не содержит абсолютных адресов, которые нуждаются в перемещении, но только самооценка адреса. Поэтому секцию кода можно загружать с произвольным адресом памяти и совместно использовать несколько процессов.

  • Раздел данных не разделяется между несколькими процессами, поскольку он часто содержит записываемые данные. Поэтому раздел данных может содержать указатели или адреса, которые необходимо переместить.

  • Все публичные функции и общедоступные данные могут быть переопределены в Linux. Если функция в главном исполняемом файле имеет то же имя, что и функция в общем объекте, тогда версия в главном случае будет иметь приоритет не только при вызове из основного, но и когда вызывается из общего объекта. Аналогично, когда глобальная переменная в основном имеет тот же самый имя как глобальная переменная в общем объекте, тогда основной экземпляр будет используется даже при доступе к общему объекту.


Это так называемое интерполяция символов предназначено для имитации поведения статических библиотек.

Общий объект имеет таблицу указателей на свои функции, называемую таблицей привязки процедур (PLT) и таблицей указателей на его переменные, называемые глобальной таблицей смещения (GOT), чтобы реализовать эту функцию "переопределения". Все обращения к функциям и общедоступным переменным проходят через эти таблицы.

p.s. В тех случаях, когда невозможно избежать динамической компоновки, существуют различные способы избежать использования временных параметров для независимого от позиции кода.

Вы можете прочитать больше из этой статьи: http://www.agner.org/optimize/optimizing_cpp.pdf

Ответ 6

Незначительное дополнение к уже опубликованным ответам: объектные файлы, не скомпилированные для независимой позиции, являются перемещаемыми; они содержат записи таблицы перемещений.

Эти записи позволяют загрузчику (этот бит кода, который загружает программу в память), чтобы переписать абсолютные адреса для настройки фактического адреса загрузки в виртуальном адресном пространстве.

Операционная система попытается совместно использовать одну копию "общей библиотеки объектов", загружаемую в память, всеми программами, которые связаны с той же библиотекой общих объектов.

Так как адресное пространство кода (в отличие от разделов пространства данных) не обязательно должно быть смежным, и поскольку большинство программ, которые ссылаются на определенную библиотеку, имеют довольно фиксированное дерево зависимостей библиотеки, это выполняется в большинстве случаев. В тех редких случаях, когда есть расхождение, да, может быть необходимо иметь две или более копии библиотеки общих объектов в памяти.

Очевидно, что любая попытка рандомизировать адрес загрузки библиотеки между программами и/или экземплярами программы (чтобы уменьшить возможность создания шаблона с возможностью использования) сделает такие случаи общими, а не редкими, поэтому, когда система активировала эта возможность должна сделать каждую попытку скомпилировать все библиотеки общих объектов независимо от положения.

Поскольку вызовы в эти библиотеки из основной программы также будут перемещены, это значительно снижает вероятность того, что нужно будет скопировать общую библиотеку.