Чтение онлайн

на главную - закладки

Жанры

Разработка приложений в среде Linux. Второе издание

Троан Эрик В.

Шрифт:

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

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

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

Здесь подразумевается, что загружать модули нужно всегда в обратном порядке по отношению к их зависимостям: если объект А зависит от объекта В в некоторых его символах, вы должны загрузить объект В до загрузки объекта А, и должны выгрузить объект А до выгрузки объекта B. К счастью, многие приложения с динамически загружаемыми разделяемыми объектами не имеют подобных взаимозависимостей.

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

Управление всеми этими действиями осуществляется через аргумент

flags
. Он должен иметь значение
RTLD_LAZY
для отложенного разрешения и
RTLD_NOW
для немедленного разрешения. Любое из этих значений может быть объединено битовым "ИЛИ" с
RTLD_GLOBAL
, чтобы разрешить экспортирование символов в остальные модули.

Если разделяемый объект экспортирует программу

_init
, то она будет выполняться до того, как функция
dlopen
вернет результат.

Функция

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

Функция

dlsym
производит поиск символа в библиотеке:

void * dlsym(void * handle, char * symbol);

handle
должен представлять собой дескриптор, возвращенный функцией
dlopen
, a
symbol
должен содержать строку с завершающим
NULL
, которая именует искомый символ. Функция
dlsym
возвращает адрес определенного вами символа или
NULL
в случае возникновения неустранимой ошибки. Если вы будете знать, что
NULL
не является правильным адресом символа (например, при поиске адреса функции), можно выполнить проверку на наличие ошибок, посмотрев, возвращает ли она
NULL
. Однако в общем случае некоторые символы могут иметь нулевые значения и быть равными
NULL
. Тогда вам нужно будет узнать, не возвращает ли функция
dlerror
ошибку. Поскольку функция
dlerror
возвращает ошибку только один раз, возвращая после этого
NULL
, вы должны организовать свой код следующим образом.

/* удалить любое состояние ошибки, которое еще не было прочитано */

dlerror;

p = dlsym(handle, "this_symbol");

if ((error = dlerror) != NULL) {

 /* обработка ошибки */

}

Так как функция

dlsym
возвращает
void *
, вам необходимо использовать приведение типов, чтобы компилятор С не выдавал сообщений об ошибках. Если вы сохраняете указатель, возвращенный функцией
dlsym
, сохраните его в переменной того типа, который вы хотите использовать, и выполните приведение типа во время вызова функции
dlsym
. Не сохраняйте результат в переменной
void *
; вам придется выполнять приведение типов каждый раз во время ее использования.

Функция

dlclose
закрывает библиотеку.

void * dlclose(void * handle);

Функция

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

27.1.1. Пример

В главе 8 был представлен пример использования обычной разделяемой библиотеки. Библиотеку

libhello.so
, которую нам удалось создать, можно загружать во время выполнения. Программа
loadhello
загружает
libhello.so
динамически и вызывает функцию
print_hello
, которая находится в библиотеке.

Ниже показан код

loadhello.с
.

 1: /* loadhello.с */

 2:

 3: #include <dlfcn.h>

 4: #include <stdio.h>

 5: #include <stdlib.h >

 6:

 7: typedef void (*hello_function) (void);

 8:

 9: int main(void) {

10: void * library;

11: hello_function hello;

12: const char * error;

13:

14: library = dlopen("libhello.so", RTLD_LAZY);

15: if (library == NULL) {

16: fprintf (stderr, "He удается открыть libhello.so: %s\n",

17: dlerror);

18: exit(1);

19: }

20:

21: /* Хотя в данном случае мы знаем, что символ print_hello никогда

22: * не должен быть равен NULL, при поиске произвольных символов

23: * все происходит иначе. Поэтому вместо проверки результата функции dlsym

Поделиться:
Популярные книги

Воевода

Ланцов Михаил Алексеевич
5. Помещик
Фантастика:
альтернативная история
5.00
рейтинг книги
Воевода

Девятый

Каменистый Артем
1. Девятый
Фантастика:
боевая фантастика
попаданцы
9.15
рейтинг книги
Девятый

Совершенный: пробуждение

Vector
1. Совершенный
Фантастика:
боевая фантастика
рпг
5.00
рейтинг книги
Совершенный: пробуждение

Кодекс Крови. Книга Х

Борзых М.
10. РОС: Кодекс Крови
Фантастика:
фэнтези
юмористическое фэнтези
попаданцы
аниме
5.00
рейтинг книги
Кодекс Крови. Книга Х

Дайте поспать! Том IV

Матисов Павел
4. Вечный Сон
Фантастика:
городское фэнтези
постапокалипсис
рпг
5.00
рейтинг книги
Дайте поспать! Том IV

Ротмистр Гордеев

Дашко Дмитрий Николаевич
1. Ротмистр Гордеев
Фантастика:
фэнтези
попаданцы
альтернативная история
5.00
рейтинг книги
Ротмистр Гордеев

Как я строил магическую империю 2

Зубов Константин
2. Как я строил магическую империю
Фантастика:
попаданцы
аниме
5.00
рейтинг книги
Как я строил магическую империю 2

Тройняшки не по плану. Идеальный генофонд

Лесневская Вероника
Роковые подмены
Любовные романы:
современные любовные романы
6.80
рейтинг книги
Тройняшки не по плану. Идеальный генофонд

Специалист

Кораблев Родион
17. Другая сторона
Фантастика:
боевая фантастика
попаданцы
рпг
5.00
рейтинг книги
Специалист

Не грози Дубровскому! Том IX

Панарин Антон
9. РОС: Не грози Дубровскому!
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Не грози Дубровскому! Том IX

Неудержимый. Книга III

Боярский Андрей
3. Неудержимый
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Неудержимый. Книга III

Изгой. Пенталогия

Михайлов Дем Алексеевич
Изгой
Фантастика:
фэнтези
9.01
рейтинг книги
Изгой. Пенталогия

Жена по ошибке

Ардова Алиса
Любовные романы:
любовно-фантастические романы
7.71
рейтинг книги
Жена по ошибке

Пистоль и шпага

Дроздов Анатолий Федорович
2. Штуцер и тесак
Фантастика:
альтернативная история
8.28
рейтинг книги
Пистоль и шпага