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

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


Динамическая компоновка

Интерпретатор программ

У исполняемого файла, применяемого при динамической компоновке, должен быть один элемент PT_INTERP заголовка программы. Во время выполнения exec (базовой операционной системой) система получает значение пути из сегмента PT_INTERP и создает начальный образ процесса из сегментов файла интерпретатора. Таким образом, вместо использования исходного образа сегментов исполняемого файла, система составляет в памяти образ для интерпретатора. Затем интерпретатор получает от системы управление и создает среду для выполнения прикладной программы.

Как указано в разделе Инициализация процесса в Главе 32 документации по процессору, интерпретатор получает управление двумя способами. Во-первых, он может получить дескриптор исполняемого файла, установленный на его начало. Затем с помощью этого дескриптора интерпретатор считывает сегменты файла в память. Во втором способе, в зависимости от формата исполняемого файла, система загружает исполняемый файл в память, не передавая интерпретатору его дескриптор. В большинстве случаев начальное состояние процесса интерпретатора соответствует данным, полученным исполняемым файлом. Для самого интерпретатора второй интерпретатор может не потребоваться. Интерпретатор может находиться как в общем объекте, так и в исполняемом файле.

Динамический компоновщик

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

Примечание: Расположение системного динамического компоновщика зависит от процессора.

Exec (базовая операционная система) и динамический компоновщик совместно создают образ процесса для программы. При этом выполняются следующие действия:

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

Поскольку совместимая с ABI программа импортирует основные системные службы из библиотеки общих объектов [см. раздел Системная библиотека в Главе 32], динамический компоновщик принимает участие в выполнении каждой программы, совместимой с ABI.

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

Если среда процесса [см. exec (базовая операционная система)] содержит переменную LD_BIND_NOW с ненулевым значением, динамический компоновщик выполняет все необходимые перемещения перед передачей управления программе. Например, такое поведение будет вызвано следующими переменными:

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

Динамический раздел

Если объектный файл используется при динамической компоновке, в таблице заголовков программы будет присутствовать элемент типа PT_DYNAMIC. Этот элемент содержит раздел .dynamic. Этот раздел помечен специальным именем _DYNAMIC и содержит массив следующих структур:

Динамические структуры

typedef struct {
		 Elf32_Sword		 d_tag;
   		 union {
   		 		 Elf32_Word		 d_val;
   		 		 Elf32_Addr		 d_ptr;
		 } d_un;
} Elf32_Dyn;
extern Elf32_Dyn		 _DYNAMIC[];
typedef struct {
		 Elf64_Sxword		 d_tag;
   		 union {
   		 		 Elf64_Xword		 d_val;
   		 		 Elf64_Addr		 d_ptr;
		 } d_un;
} Elf64_Dyn;
extern Elf64_Dyn		 _DYNAMIC[];

Для каждого объекта этого типа d_tag управляет интерпретацией d_un.

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

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

В целях совместимости в файлах не применяются записи перемещения, исправляющие адреса в динамических структурах.

Для того чтобы упростить интерпретацию содержимого записей динамического раздела, значение каждого тега, за исключением содержащихся в двух специальных разделах, определяет способ интерпретации объединения d_un. Теги с четными значениями указывают на запись динамического раздела, использующую d_ptr. Теги с нечетными значениями указывают на запись динамического раздела, использующую d_val или не использующую ни d_ptr, ни d_val. Эти правила не относятся к тегам, значения которых меньше специального значения DT_ENCODING, и тегам, значения которых находятся между DT_HIOS и DT_LOPROC.

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

Теги динамических массивов, d_tag

Имя Значение d_un Исполняемый Общий объектный
DT_NULL 0 игнорируется обязательный обязательный
DT_NEEDED 1 d_val необязательный необязательный
DT_PLTRELSZ 2 d_val необязательный необязательный
DT_PLTGOT 3 d_ptr необязательный необязательный
DT_HASH 4 d_ptr обязательный обязательный
DT_STRTAB 5 d_ptr обязательный обязательный
DT_SYMTAB 6 d_ptr обязательный обязательный
DT_RELA 7 d_ptr обязательный необязательный
DT_RELASZ 8 d_val обязательный необязательный
DT_RELAENT 9 d_val обязательный необязательный
DT_STRSZ 10 d_val обязательный обязательный
DT_SYMENT 11 d_val обязательный обязательный
DT_INIT 12 d_ptr необязательный необязательный
DT_FINI 13 d_ptr необязательный необязательный
DT_SONAME 14 d_val игнорируется необязательный
DT_RPATH* 15 d_val необязательный игнорируется
DT_SYMBOLIC* 16 игнорируется игнорируется необязательный
DT_REL 17 d_ptr обязательный необязательный
DT_RELSZ 18 d_val обязательный необязательный
DT_RELENT 19 d_val обязательный необязательный
DT_PLTREL 20 d_val необязательный необязательный
DT_DEBUG 21 d_ptr необязательный игнорируется
DT_TEXTREL* 22 игнорируется необязательный необязательный
DT_JMPREL 23 d_ptr необязательный необязательный
DT_BIND_NOW* 24 игнорируется необязательный необязательный
DT_INIT_ARRAY 25 d_ptr необязательный необязательный
DT_FINI_ARRAY 26 d_ptr необязательный необязательный
DT_INIT_ARRAYSZ 27 d_val необязательный необязательный
DT_FINI_ARRAYSZ 28 d_val необязательный необязательный
DT_RUNPATH 29 d_val необязательный необязательный
DT_FLAGS 30 d_val необязательный необязательный
DT_ENCODING 32 не указан не указан не указан
DT_PREINIT_ARRAY 32 d_ptr необязательный игнорируется
DT_PREINIT_ARRAYSZ 33 d_val необязательный игнорируется
DT_LOOS 0x6000000D не указан не указан не указан
DT_HIOS 0x6ffff000 не указан не указан не указан
DT_LOPROC 0x70000000 не указан не указан не указан
DT_HIPROC 0x7fffffff не указан не указан не указан

* Указывает запись уровня 2.

DT_NULL
Запись с тегом DT_NULL помечает конец массива _DYNAMIC.

DT_NEEDED
Этот элемент содержит смещение строки, хранящей имя библиотеки, в таблице строк. Смещение - это индекс таблицы, записанный в коде DT_STRTAB. Более подробная информация об именах приведена в разделе Зависимости общих объектов. В динамическом массиве могут присутствовать несколько элементов этого типа. Относительный порядок этих записей имеет значение, хотя их положение относительно записей других типов значения не имеет.

DT_PLTRELSZ
В этом элементе хранится общий размер записей перемещения, связанных с таблицей компоновки процедур. Если указана запись типа DT_JMPREL, то должна также быть указана запись DT_PLTRELSZ.

DT_PLTGOT
В этом элементе указан адрес, связанный с таблицей компоновки процедур и глобальной таблицей смещения. Более подробная информация приведена в документации по процессору.

DT_HASH
В этом элементе указан адрес хэш-таблицы имен, описанной в Хэш-таблица. Хэш-таблица связана с таблицей имен, на которую ссылается элемент DT_SYMTAB.

DT_STRTAB
В этом элементе указан адрес таблицы строк, описанной в главе 32. В этой таблице хранятся определения имен, библиотек и другие строки.

DT_SYMTAB
В этом элементе хранится адрес таблицы имен, описанной в первой части этой главы, включая записи Elf32_Sym для 32-разрядных классов файлов и Elf64_Sym для 64-разрядных классов.

DT_RELA
В этом элементе указан адрес таблицы перемещения, описанной в главе 32. У записей в таблице есть явные добавления, например, Elf32_Rela для 32-разрядных классов и Elf64_Rela для 64-разрядных классов. В объектном файле может быть несколько разделов с таблицами перемещения. При создании таблицы перемещения для исполняемого или общего объектного файла компоновщик объединяет эти разделы в одну таблицу. Хотя записи остаются независимыми в объектном файле, для динамического компоновщика они представлены в виде единой таблицы. Когда динамический компоновщик создает образ процесса для исполняемого файла или добавляет общий объект к образу процесса, он считывает таблицу перемещения и выполняет все связанные с этим действия. Если элемент присутствует, в динамической структуре должны быть элементы DT_RELASZ и DT_RELAENT. Если перемещение в файле обязательно, то может быть указано значение DT_RELA или DT_REL (оба значения одновременно указать можно, но это не требуется).

DT_RELASZ
В этом элементе указан общий размер таблицы перемещения DT_RELA (в байтах).

DT_RELAENT
В этом элементе указан размер записи перемещения DT_RELA (в байтах).

DT_STRSZ
В этом элементе указан размер таблицы строк (в байтах).

DT_SYMENT
В этом элементе указан размер записи таблицы имен (в байтах).

DT_INIT
В этом элементе указан адрес функции инициализации, описанной в разделе Функции инициализации и завершения.

DT_FINI
В этом элементе указан адрес функции завершения, описанной в разделе Функции инициализации и завершения.

DT_SONAME
Этот элемент содержит смещение строки, хранящей имя общего объекта, в таблице строк. Смещение - это индекс таблицы, указанной в записи DT_STRTAB. Более подробная информация об именах приведена в разделе Зависимости общих объектов.

DT_RPATH
Этот элемент содержит смещение строки, в которой указано имя библиотеки для поиска, описанной в Зависимости общих объектов. Смещение - это индекс таблицы, указанной в записи DT_STRTAB. Это запись уровня 2. Больший приоритет имеет запись DT_RUNPATH.

DT_SYMBOLIC
Этот элемент изменяет алгоритм преобразования имен, применяемый динамическим компоновщиком при обращении к библиотеке. Вместо поиска нужных имен в исполняемом файле, динамический компоновщик начинает просмотр с общего объекта. Если в общем объекте нужное имя не будет найдено, поиск продолжается обычным образом в исполняемом файле и других общих объектных файлах. Это запись уровня 2. Больший приоритет имеет флаг DF_SYMBOLIC.

DT_REL
Этот элемент похож на DT_RELA, за исключением того, что в его таблице есть явные добавления, такие как Elf32_Rel для 32-разрядных классов файлов и Elf64_Rel для 64-разрядных классов. Если элемент присутствует, в динамической структуре должны быть элементы DT_RELSZ и DT_RELENT.

DT_RELSZ
В этом элементе указан общий размер таблицы перемещения DT_REL (в байтах).

DT_RELENT
В этом элементе указан размер записи перемещения DT_REL (в байтах).

DT_PLTREL
Этот элемент задает тип записи перемещения, на которую ссылается таблица компоновки процедур. В элементе d_val хранятся значения DT_REL или DT_RELA. Для всех перемещений в таблице компоновки процедур должно применяться одно и то же значение перемещения.

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

DT_TEXTREL
Если этот элемент отсутствует, то записи перемещения не должны вызывать изменения защищенных от записи сегментов, как указано в правах доступа к сегменту в таблице заголовков программы. Если указан этот элемент, записи перемещения могут запросить изменение защищенного от записи сегмента, и динамический компоновщик выполнит все необходимые действия. Это запись уровня 2. Больший приоритет имеет флаг DF_TEXTREL.

DT_JMPREL
Если указано это значение, то элемент d_ptr этой записи содержит адрес записей перемещения, связанных только с таблицей компоновки процедур. Отделение таких записей позволяет динамическому компоновщику пропускать их при инициализации процесса, если разрешена отложенная компоновка. Если указана эта запись, то должны также быть указаны связанные записи типов DT_PLTRELSZ и DT_PLTREL.

DT_BIND_NOW
Если эта запись указана в исполняемом или общем объекте, то динамический компоновщик выполняет все перемещения для всех объектов, содержащих данную запись, перед передачей управления программе. Эта запись имеет приоритет перед директивой отложенной компоновки данного объекта, заданной в среде или с помощью dlopen(BA_LIB). Это запись уровня 2. Больший приоритет имеет флаг DF_BIND_NOW.

DT_INIT_ARRAY
В этом элементе хранится адрес массива указателей на функции инициализации, описанные в Функции инициализации и завершения.

DT_FINI_ARRAY
В этом элементе хранится адрес массива указателей на функции завершения, описанные в Функции инициализации и завершения.

DT_INIT_ARRAYSZ
Этот элемент содержит размер (в байтах) массива функций инициализации, заданного записью DT_INIT_ARRAY. Если для объекта есть запись DT_INIT_ARRAY, то необходима также запись DT_INIT_ARRAYSZ.

DT_FINI_ARRAYSZ
Этот элемент содержит размер (в байтах) массива функций завершения, заданного записью DT_FINI_ARRAY. Если для объекта есть запись DT_FINI_ARRAY, то необходима также запись DT_FINI_ARRAYSZ.

DT_RUNPATH
Этот элемент содержит смещение строки, в которой указан путь к библиотеке, описанной в Зависимости общих объектов. Смещение - это индекс таблицы, указанной в записи DT_STRTAB.

DT_FLAGS
Этот элемент содержит значения флагов, зависящих от конкретного загружаемого объекта. Значение каждого флага указано в формате DF_имя_флага. Определенные значения и их описания приведены ниже. Все остальные значения зарезервированы.

DT_PREINIT_ARRAY
В этом элементе хранится адрес массива указателей на функции предварительной инициализации, описанные в Функции инициализации и завершения. Таблица DT_PREINIT_ARRAY обрабатывается только в исполняемом файле; в общем объектном файле она игнорируется.

DT_PREINIT_ARRAYSZ
Этот элемент содержит размер (в байтах) массива функций предварительной инициализации, заданного записью DT_PREINIT_ARRAY. Если для объекта есть запись DT_PREINIT_ARRAY, то необходима также запись DT_PREINIT_ARRAYSZ. Как и DT_PREINIT_ARRAY, эта запись игнорируется в общих объектных файлах.

DT_ENCODING
Для значений, больших или равных DT_ENCODING и меньших DT_LOOS применяются правила интерпретации объединения d_un, описанные выше.

DT_LOOS - DT_HIOS
Значения в этом диапазоне зависят от типа применяемой операционной системы. Для всех этих значений применяются правила интерпретации объединения d_un, описанные выше.

DT_LOPROC - DT_HIPROC
Значения в этом диапазоне зависят от типа процессора. Их применение описано в документации по процессору. Для всех этих значений применяются правила интерпретации объединения d_un, описанные выше.

За исключением элемента DT_NULL в конце массива и относительного порядка элементов DT_NEEDED, порядок следования записей не регламентируется. Значения тегов, не показанные в таблице, зарезервированы.

Значения DT_FLAGS

Имя Значение
DF_ORIGIN 0x1
DF_SYMBOLIC 0x2
DF_TEXTREL 0x4
DF_BIND_NOW 0x8

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

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

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

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

Зависимости общих объектов

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

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

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

Имена в списке зависимостей - это копии либо строк DT_SONAME, либо путей к общим объектам, применявшимся при создании объектного файла. Например, если компоновщик создает исполняемый файл с помощью одного общего объекта, имеющего запись DT_SONAME lib1, и другого общего объекта с именем /usr/lib/lib2, то в списке зависимостей исполняемого файла будут указаны записи lib1 и /usr/lib/lib2.

Если в имени пути есть символы косой черты (/), например /usr/lib/lib2 или directory/file, то динамический компоновщик принимает эту строку за полное имя файла. Если в имени нет символа косой черты, например, lib1, то полный путь определяется на основе трех факторов.

  1. Тег динамического массива DT_RUNPATH содержит строку со списком каталогов, разделенных двоеточиями (: ). Например, строка /home/dir/lib:/home/dir2/lib: указывает динамическому компоновщику, что при поиске зависимостей сначала нужно просмотреть каталог /home/dir/lib, затем /home/dir2/lib, а затем текущий каталог.

    Набор каталогов, заданный записью DT_RUNPATH, применяется только для поиска объектов, зависимых напрямую от исполняемого или общего объекта, содержащего запись DT_RUNPATH. Таким образом, он применяется только для поиска зависимостей, непосредственно указанных в записях DT_NEEDED динамической структуры, содержащей запись DT_RUNPATH. Запись DT_RUNPATH не влияет на поиск других зависимостей объекта.

  2. Переменная LD_LIBRARY_PATH среды процесса [см. exec (базовая операционная система)] может содержать несколько списков каталогов, разделенных точной с запятой (;).

    Следующие значения эквивалентны значениям, показанным в предыдущем примере:

    1. LD_LIBRARY_PATH=/home/dir/usr/lib:/home/dir2/usr/lib:
    2. LD_LIBRARY_PATH=/home/dir/usr/lib;/home/dir2/usr/lib:
    3. LD_LIBRARY_PATH=/home/dir/usr/lib:/home/dir2/usr/lib:;

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

    Все каталоги LD_LIBRARY_PATH просматриваются перед каталогами из DT_RUNPATH.

  3. Если необходимая библиотека не будет найдена ни в одной из перечисленных выше групп каталогов, динамический компоновщик просматривает каталоги по умолчанию ( /usr/lib или любые другие каталоги, указанные в документации ABI по процессору).

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

e_ident[EI_DATA], e_ident[EI_CLASS] , e_ident[EI_OSABI], e_ident[EI_ABIVERSION] , e_machine, e_type, e_flags и e_version.

Примечание: В целях безопасности динамический компоновщик игнорирует программы из LD_LIBRARY_PATH с флагами setuid и setgid. Однако он просматривает каталоги DT_RUNPATH и каталоги по умолчанию. Это ограничение также относится к процессам, которым предоставлено больше прав доступа, чем минимально требуется в системах с расширенной защитой.

Примечание: Четвертый объект для поиска, тег динамического массива DT_RPATH, перемещен на уровень 2 ABI. В этом теге хранится список разделенных двоеточиями каталогов для поиска. Каталоги, указанные в DT_RPATH, просматриваются перед каталогами из LD_LIBRARY_PATH.

Если в динамическом массиве одного объекта есть как DT_RPATH, так и DT_RUNPATH , то динамический компоновщик обрабатывает только запись DT_RUNPATH.

Последовательность подстановки

В строках, которые заданы тегами DT_NEEDED и DT_RUNPATH и содержат списки имен каталогов, передаваемых в качестве параметров процедуре dlopen(), последовательность подстановки начинается с символа ($). Эта последовательность состоит из знака доллара, за которым следует либо имя, либо имя, заключенное в фигурные скобки ({) и (}). Имя - это последовательность байтов, начинающаяся с буквы английского алфавита или символа подчеркивания, за которым могут следовать другие буквы, цифры и символы подчеркивания. Если за символом доллара не указано обычное или заключенное в скобки имя, то поведение динамического компоновщика будет непредсказуемо.

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

При загрузке объекта с переменной $ORIGIN динамический компоновщик должен вычислить имя каталога, в котором находится объект. Так как такие вычисления могут быть достаточно сложными, в конкретной реализации динамического компоновщика значение $ORIGIN может не вычисляться для объектов, где эта переменная не используется. Если объект вызывает dlopen() со строкой, содержащей $ORIGIN, и не использует $ORIGIN в записях динамического массива, то динамический компоновщик может не вычислять имя каталога до тех пор, пока явно не встретится вызов dlopen(). Приложение может изменить рабочий каталог перед вызовом dlopen(), поэтому результат вычисления может оказаться неправильным. Для того чтобы избежать этой ошибки, объект может заранее объявить свое намерение использовать $ORIGIN, указав флаг DF_ORIGIN. Динамический компоновщик может отклонить попытку использования $ORIGIN в вызове dlopen() для объекта, который не установил флаг DF_ORIGIN и не использовал $ORIGIN в динамическом массиве.

Примечание: В целях безопасности динамический компоновщик не позволяет использовать $ORIGIN в программах с флагами setuid и setgid. Для последовательностей, указанных в записях DT_RUNPATH динамического массива, список каталогов для поиска, содержащий последовательность $ORIGIN, игнорируется (остальные списки в той же строке обрабатываются обычным образом). Последовательности $ORIGIN в записях DT_NEEDED или каталоги, переданные в качестве параметра функции dlopen(), рассматриваются как ошибочные. Это ограничение также относится к процессам, которым предоставлено больше прав доступа, чем минимально требуется в системах с расширенной защитой.

Глобальная таблица смещения

Примечание: В этом разделе приведена информация, зависящая от процессора. Более подробная информация приведена в документации по ABI System V и процессору.

Таблица компоновки процедур

Примечание: В этом разделе приведена информация, зависящая от процессора. Более подробная информация приведена в документации по ABI System V и процессору.

Хэш-таблица

Хэш-таблица объектов Elf32_Word поддерживает доступ к таблице имен. Для 32- и 64-разрядных классов файлов применяется один и тот же формат таблицы. Ниже приведены метки, помогающие понять структуру хэш-таблицы, однако эти метки на являются частью спецификации.

Хэш имен

nbucket
nchain
bucket[0]
. . .
bucket[nbucket-1]
chain[0]
. . .
chain[nchain-1]

Массив bucket состоит из записей nbucket, а массив chain - из записей nchain; индексы начинаются с 0. В bucket и chain хранятся индексы таблицы имен.

Записи таблицы chain соответствуют таблице имен. Число записей таблицы имен должно равняться nchain, поэтому индексы таблицы имен также указывают на записи таблицы chain. Хэш-функция (показанная ниже) получает имя и возвращает значение, которое может применяться для вычисления индекса bucket.

Например, если хэш-функция возвращает для какого-либо имени значение x, то bucket[x%nbucket] представляет индекс y как в таблице имен, так и в таблице chain.

Если найдена неверная запись таблицы имен, chain[y] вернет следующую запись таблицы с тем же хэш-значением.

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

Хэш-функция

unsigned long
elf_hash(const unsigned char *name)
{
		 unsigned long		 h = 0, g;
		 while (*name)
		 {
		 		 h = (h << 4) + *name++;
		 		 if (g = h & 0xf0000000)
		 		 		 h ^= g >> 24;
		 		 h &= ~g;
		 }
		 return h;
}

Функции инициализации и завершения

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

Перед вызовом функций инициализации для объекта A вызываются функции инициализации для всех объектов, от которых зависит объект А. Объект А зависит от объекта В, если В указан в списке необходимых объектов объекта А (в записях DT_NEEDED динамической структуры). Порядок инициализации циклических зависимостей не определен.

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

Примечание: Каждый процессор может накладывать дополнительные ограничения на алгоритм инициализации. Однако эти ограничения не должны конфликтовать с описанными выше спецификациями.

Ниже приведен пример двух способов просмотра списка NEEDED. В этом примере a.out зависит от b, d и e. b зависит от d и f, а d зависит от e и g. На основании этих зависимостей можно составить схему. Описанный выше алгоритм допускает следующие последовательности инициализации.

Пример последовательности инициализации У общих и исполняемых файлов могут также быть функции завершения, которые вызываются функцией atexit (базовой операционной системы) после того, как базовый процесс начнет последовательность завершения. Функции завершения для объекта А должны быть вызваны перед вызовом функций завершения для объектов, от которых зависит объект А. Объект А зависит от объекта В, если В указан в списке необходимых объектов объекта А (в записях DT_NEEDED динамической структуры). Порядок обработки функций завершения для циклических зависимостей не определен.

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

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

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

Код инициализации и завершения общих объектов может указываться двумя способами. Во-первых, можно указать адрес выполняемой функции с помощью записей DT_INIT и DT_FINI динамической структуры, описанной в разделе Динамический раздел.

Во-вторых в объектах может быть указан адрес и размер массива указателей на функции. Каждый элемент массива - это указатель на функцию, которую должен выполнить динамический компоновщик. Размер каждого элемента массива определяется программной моделью объекта, содержащего массив. Адрес массива указателей на функции инициализации указан в записи DT_INIT_ARRAY динамической структуры. Аналогично, адрес массива функций предварительной инициализации указан в записи DT_PREINIT_ARRAY, а адрес функций завершения - в записи DT_FINI_ARRAY. Размер каждого массива указан записями DT_INIT_ARRAYSZ, DT_PREINIT_ARRAYSZ и DT_FINI_ARRAYSZ.

Функции, адреса которых указаны в массивах DT_INIT_ARRAY и DT_PREINIT_ARRAY, выполняются динамическим компоновщиком в том же порядке, в котором их адреса следуют в массиве; функции из массива DT_FINI_ARRAY выполняются в обратном порядке.

Если в объекте есть записи DT_INIT и DT_INIT_ARRAY, то функции, указанные в DT_INIT, обрабатываются до функций массива DT_INIT_ARRAY. Если в объекте есть записи DT_FINI и DT_FINI_ARRAY, то функции, указанные в DT_FINI_ARRAY, обрабатываются до функций из массива DT_FINI.

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

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


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