
- •Раздел 8. Управление информацией в операционных системах
- •8.1. Общая характеристика связывания объектов
- •8.2. Загрузка абсолютной программы
- •8.3. Загрузка перемещаемой программы
- •8.4. Редактирование связей
- •8.5. Динамическое связывание
- •8.5.1. Организация оверлейных программ
- •8.5.2. Общая характеристика динамического связывания
- •8.5.3. Механизмы динамического связывания
8.5.2. Общая характеристика динамического связывания
В этом случае загрузка и связывание подпрограммы происходят в момент первого обращения к ней.
Механизм реализации динамического связывания похож на реализацию оверлейной программы с учетом того, что менеджер оверлеев и таблица сегментов превращаются в средство, которое называется ДИНАМИЧЕСКИМ ЗАГРУЗЧИКОМ и которое является средством операционной системы.
Краткое описание процесса динамического связывания выглядит следующим образом.
При динамическом связывании вместо выполнения команды СALL программа выполняет запрос к операционной системе. Параметром запроса является символическое имя вызываемой подпрограммы. Операционная система по своим внутренним таблицам определяет, загружена ли данная подпрограмма или нет. Если подпрограмма не загружена, то она загружается, после чего операционная система ее вызывает. Возврат из подпрограммы осуществляется в операционную систему, которая в свою очередь возвращает управление программе.
Повторный вызов уже загруженной программы осуществляется без перезагрузки. Динамический загрузчик может просто передать на нее управление.
Как уже говорилось, существует два вида динамического связывания:
неявное связывание, на этапе загрузки программы
явное связывание, на этапе выполнения программы.
Динамическая библиотека поставляется двумя файлами:
.dll – собственно библиотека;
.lib – заглушка библиотеки, предназначенная для связи программы с библиотекой.
При неявном связывании необходимо к проекту подсоединить файл .lib библиотеки, а вызываемую функцию описать как импортируемую. Это делается специальной строкой следующего вида:
extern "C" __declspec(dllimport) void Func_Hello();
В исходном коде самой библиотеки функция декларируется строкой
extern "C" __declspec(dllexport) void Func_Hello()
При явном связывании требуется загрузить библиотеку вызовом:
HINSTANCE hDLL = AfxLoadLibrary("dll");
Затем необходимо получить адрес точки входа в функцию. Это делается вызовом:
FARPROC ProcAddr = GetProcAddress(hDLL,"Func_Hello");
Затем надо преобразовать тип возвращаемых данных (FARPROC) преобразовать к типу данных функции.
Например, для описанной функции необходимо выполнить следующие действия:
Описать переменную: void (*Func)();
Получить ее значение: Func = (void(*)())ProcAddr;
Воспользоваться этой переменной, как именем функции: Func();
После использования библиотеки ее можно выгрузить вызовом
AfxFreeLibrary(hDLL);
Как такие же действия делаются в Linux:
Есть функция dlopen(const char *filename, int flag), которая загружает динамическую библиотеку, имя которой указано в строке filename, и возвращает прямой указатель на начало динамической библиотеки.
void *handle = dlopen("libm.so", RTLD_LAZY);
Затем используем функцию dlsym, которая использует указатель на динамическую библиотеку, возвращаемую dlopen, и оканчивающееся нулем символьное имя функции, а затем возвращает адрес, указывающий на эту функцию.
double (*cosine)(double);
cosine = dlsym(handle, "cos");
double dbl_cos = (*cosine)(2.0);//вызов самой функции
Выгрузка динамической библиотеки:
int dlclose(void *handle);