[ Страница назад | Страница вперед | Содержание | Индекс | Библиотека | Юридическая информация | Поиск ]

Программирование: Разработка и отладка программ


Общие объекты и динамическая компоновка

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

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

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

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

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

Начиная с версии 4.2, в большинстве общих модулей, поставляемых с AIX, задана опция динамической компоновки большинства экспортируемых переменных. Динамическая компоновка функций возможна только в случае вызова функции через указатель. Например, в текущей версии AIX вызовы процедуры malloc из общего объекта shr.o (библиотека /lib/libc.a) не могут быть перенаправлены для вызова другой процедуры, даже если определение malloc есть в главной программе или в другом общем модуле. Большинство поставляемых с системой общих модулей можно перекомпоновать с опцией динамической компоновки для функций и переменных. Для этого нужно воспользоваться командой rtl_enable.

Операции, выполняемые динамическим компоновщиком

Главная программа загружается и обрабатывается системным загрузчиком в обычном режиме. Если по каким-либо причинам главную программу загрузить не удается, процедура exec() завершается с ошибкой и динамический компоновщик не вызывается. При успешной загрузке главной программы управление передается динамическому компоновщику, который обрабатывает символы по схеме, описанной ниже. После завершения работы динамического компоновщика вызываются процедуры инициализации (если они предусмотрены), после чего вызывается функция main.

Динамический компоновщик обрабатывает модули в порядке прямой зависимости - начинает с главной программы, затем переходит к первому непосредственно зависящему от нее модулю, затем к первому зависящему от него и т.д. При поиске определения символа модули просматриваются в том же порядке. Кроме двух исключений описанных ниже, всегда применяется первое найденное определение. Если первое найденное определение относится к неопределенному отложенному символу, то символ считается неопределенным и обработка прекращается. Если первое найденное определение будет помечено как BSS (т.е. как символ типа XTY_CM, соответствующий неинициализированной переменной), то динамический компоновщик попытается найти другое определение, не помеченное как BSS и не являющееся неопределенным отложенным символом. Если такое определение будет найдено, то будет использоваться оно. В противном случае будет применяться первое найденное определение.

В разделе загрузки каждого модуля перечислены импортируемые символы, которые обычно бывают определены в другом модуле, а также экспортируемые символы, которые обычно определяются в данном модуле. Символы, которые импортируются и экспортируются одновременно, называются внешними. С такими символами можно работать так, как будто они определены в данном модуле, хотя на самом деле они определены в другом модуле.

Некоторые символы могут быть помечены как "отложенные". Такие символы не обрабатываются динамическим компоновщиком. Они обрабатываются системным загрузчиком либо с помощью процедуры loadbind(), либо путем явной загрузки дополнительного модуля с помощью процедуры load() или dlopen().

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

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

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

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

Если при компоновке возникли какие-либо ошибки, то после обработки всех модулей динамический компоновщик вызывает функцию exit и передает ей код возврата 144 (0x90). В противном случае вызываются процедуры инициализации или процедура main().

Создание общего объекта с поддержкой динамической компоновки

Для создания общего объекта с поддержкой динамической компоновки нужно указать флаг -G в командной строке компоновщика. В этом случае при компоновке объекта выполняются следующие действия:

  1. Экспортируемым символам присваивается атрибут nosymbolic, что в дальнейшем позволяет динамическому компоновщику обрабатывать эти символы.
  2. Допускается применение неопределенных символов (см. описание опции -berok). Такие символы помечаются как импортируемые из символьного модуля "..". Символы, импортируемые из модуля "..", должны обрабатываться динамическим компоновщиком, потому что системный загрузчик не может их обработать.
  3. Выходному файлу присваивается тип модуля SRE (как если бы в командной строке была указана опция -bM:SRE).
  4. Все общие объекты, указанные в командной строке, будут помещены как зависящие от выходного модуля (как и при компоновке программы с опцией -brtl).
  5. Общие объекты из архива указываются в командной строке в том случае, если для них задан атрибут autoload.

Флаг -G по умолчанию включает опцию -berok. Эта опция скрывает ошибки, которые могут быть обнаружены во время компоновки. Если вы хотите, чтобы все используемые символы были определены к моменту компоновки модуля, укажите с флагом -G опцию -bernotok. В этом случае будут выданы сообщения об ошибках для всех неопределенных символов.

Связанная информация

Команды ld, rtl_enable.

Функции dlclose, dlopen, exec, exit, malloc.


[ Страница назад | Страница вперед | Содержание | Индекс | Библиотека | Юридическая информация | Поиск ]