ний. Каждое открытие увеличивает его на 1, а каждое освобождение - уменьшает на 1. После обнуления этого счетчика библиотека выгружается из памяти.
Для освобождения библиотеки в операционной системе Linux служит функция с прототипом
int dlclose(int hdll);
Эта функция в качестве единственного параметра используют хэндл освобождаемой библиотеки, а возвращаемое значение определяет успешность выполнения операции, причем неуспех кодируется обычным для рассматриваемой ОС образом, а именно значением -1.
В операционной системе Linux программа использования библиотеки динамической компоновки путем компоновки времени выполнения может быть задана примером, представленном в листинге 11.
#include <stdio.h> #include <dlfcn.h> int main()
{int k; void *libc;
void (*fun)(char*); printf("Before call DLL\n");
libc = dlopen("mydll1.so.1", RTLD_LAZY); if (!libc)
{printf("Error Load DLL\n"); fputs(dlerror(), stderr); getchar(); exit();
}
fun = dlsym(libc, "wiwoda"); if (!fun)
{printf("Error Load Function\n"); fputs(dlerror(), stderr); getchar(); exit();
}
(*fun)("My Text For DLL mmmm"); //sleep(10); printf("After DLL mmm k=%d\n",k); dlclose(libc);
return;
}
Листинг 11. Программа для DLL с процедурами инициализации в Unix.
Заметим, что в Unix компилятор с языка Си не приписывает никаких дополнительных символов внешним именам и поэтому при запросе адреса процедуры из библиотеки DLL используется именно то имя wiwoda, которое было явно присвоено программистом при написании программы процедуры.
Для использования личной разделяемой библиотеки, например библиотеки myd.so.1 в некоторой программе prim возможны два различных решения. В первом при создании (или компоновке) исполняемого файла prim непосредственно в
51
командной строке создания этого файла задается и полное имя этой библиотеки. Например, в виде
gcc -o prim prim.c /home/student/myd.so.1
Второй способ заключается в задании дополнительной информации для автоматического поиска разделяемых библиотек. Это дополнение записывается в конфигурационный файл индивидуального пользователя, в частности при использовании командной оболочки bash в файл .bash-profile. Дополнение заключается в переопределении специальной переменной LD_LIBRARY_PATH. Это переопределение может быть выполнено следующими двумя строчками командного файла
LD_LIBRARY_PATH=`pdw`:$LD_LIBRARY_PATH; export LD_LIBRARY_PATH
Более подробную информацию о настройке пути к личной разделяемой библиотеке следует смотреть в файле GCC_HOWTO встроенной справочной системы Linux или ее эквивалентах для других клонов Unix.
В операционной системе Unix процедуры инициализации и завершения работы библиотеки DLL разделены и называются _init и _fini. Они не имеют никаких аргументов и получают управление строго при загрузке библиотеки в память и непосредственно перед выгрузкой ее из памяти. Пример использования этих процедур приведен в программе листинга 12.
GLOBAL wiwoda:function,_init:function,_fini:function
SEGMENT |
.data |
|
frmt db 'Text argument is <%s>',10,0 |
||
txtinit db 'Inialize DLL-so-library..',10 |
||
lentxtinit equ $-txtinit |
||
txtfini db 'Terminate this DLL-so-library..',10 |
||
lentxtfini equ $-txtfini |
||
SEGMENT |
.text |
|
wiwoda: |
;;аналог функции wiwoda(char *pt), написанный на ассемблере |
|
. . . |
|
|
ret _init:
pusha
.. .
popa
ret _fini:
pusha
. . .
popa ret
Листинг 12. Программа upd4.asm со служебными процедурами
Аналогичная программа на языке Си может быть задана программой, приведенной в листинге 13.
#include <stdio.h> int wiwoda(char* text)
52
{printf("'We are into Dll ...\n");
printf("Text argument is <%s>\n", text); return 37;} void _init()
{printf("\033[1m\033[34m""Initialize Dll...\033[0m\033[37m\n"); return;} void _fini()
{printf("\033[1m\033[34m""Finitize Dll ...\033[0m\033[37m\n"); return;} Листинг 13. Программа upd4.c для Unix
Из нее видно, что для включения процедур инициализации и завершения программисту следует просто включить такие процедуры со стандартными именами в исходный текст программы для вызываемых функций библиотеки. Компиляция и компоновка в этом случае ничем не отличается от уже рассмотренных действий по построению разделяемых библиотек в Unix.
При отсутствии в программе для Linux процедур инициализации и завершения, они просто не будут использоваться, но такое отсутствие не порождает никаких проблем и ошибок. Это утверждение справедливо как для исходных программ на языке Си, так и для ассемблерных программ.
ВОС Linux перечень каталогов, автоматически просматриваемых для загрузки разделяемой библиотеки, находится в конфигурационном файле /etc/ld.so.conf. Дополнительно к нему может использоваться переменная командной оболочки с именем LD_LIBRARY_LD, которая должна содержать перечисленные через двоеточия имена каталогов такого поиска.
Очень важные особенности связаны с использованием DLL при программировании на языке C++. Непосредственное использование функций (называемых для классов методами) в этом объектно-ориентированном варианте влечет неявное построение действительных их имен, существенно отличных от записанных программистом. Самое неприятное, что построение таких действительных имен существенно зависит от транслятора и никаких стандартов на этот случай не выработано. Оказывается, что DLL, построенная из программ C++, разработанных в одной системе программирования, совершенно не годится для программ другой системы программирования. Поэтому в большинстве случаев, даже программируя на С++, функции для DLL описывают как отвечающие строгому соответствию обычного Си. Для этих целей служит вспомогательных модификатор объявления С++ функций, записываемый как
extern "C" дальнейшее описание функции или ее прототипа
Вобщем случае следует избегать экспорта C++-классов, если программист не уверен, что разработчики исполняемых модулей будут пользоваться тем же транслятором.
Задание. Построить разделяемую библиотеку в Linux, функции которой позволяют запомнить внутри нее текст данных, а затем - в другой функции - прочитать этот текст в вызывающую программу. Использовать эту библиотеку в двух параллельно работающий процессах, где основная программа использует динамическую компоновку времени выполнения, один из программных модулей – либо разделяемая библиотека, либо основная программа - написан на языке ассемблера, а другой из этих модулей – на языке Си, разделяемая библиотека обеспечивает выдачу сообщений о подключении к ней процесса и об отключении его от нее.
53
БИБЛИОГРАФИЧЕСКИЙ СПИСОК
1.Абель П. Язык Ассемблера для IBM PC и программирования. -М.: Высшая школа. 1992. -447с.
2.Бек Л. Введение в системное программирование. - М: Мир,1988. - 448 с.
3.Брэдли Д. Программирование на языке ассемблера для персональной ЭВМ
фирмы IBM. -М.: Радио и связь, 1988. -448с.
4.Гордеев А.В., Молчанов А.Ю. Системное программное обеспечение. - СПб.: Питер, 2001. -736 с.
5.Данкан Р. Профессиональная работа в MS-DOS. - М.: Мир, 1993. -509 с.
6.Зубков С.В. Ассемблер для DOS, Windows и UNIX. - М.: ДМК Пресс, 2000.
7.Использование Turbo Assembler при разработке программ. - Киев: Диалектика, 1994. -288 с.
8.Нортон П., Соухэ Д. Язык ассемблера для IBM PC. -М.: Компьютер, 1993. -352с.
9.Рихтер Дж. Windows для профессионалов. - М:. Издательский отдел "Русская редакция ТОО Channel Trading Ltd", 1995. - 720 с.
10.Рихтер Дж. Windows для профессионалов: создание эффективных Win32-при-
ложений с учетом специфики 64-разрядной версии Windows. - СПб:. Питер; М.: Изд.-торг. дом "Русская редакция", 2001. - 752 с.
11.Рудаков П.И., Финогенов К.Г. Программируем на языке ассемблера IBM PC. -Обнинск: Изд-во "Принтер", 1997. -584 с.
12.Рудаков П.И., Финогенов К.Г. Язык ассемблера: уроки программирования. - М.: ДИАЛОГ-МИФИ, 2001. -640 с.
13.Сван Т. Освоение Turbo Assembler. - Киев: Диалектика, 1996. -544 с.
14.Скэнлон Л. Персональные ЭВМ IBM PC и XT. Программирование на языке ассемблера. -М.: Радио и связь, 1989. -336с.
15.Финогенов К.Г. Справочник по системным функциям MS-DOS. М.: Радио и связь. Энтроп. 1995. -382с.
16.Финогенов К.Г. Основы языка ассемблера. - М.: Радио и связь, 1999. -288 с.
17.Флоренсов А.Н. Введение в системное программирование на основе 16-бит- ных компьютеров типа IBM PC: Учеб. пос. - Омск, Изд-во ОмГТУ, 1996. -108 с.
18.Флоренсов А.Н. Введение в системное программирование для 32-разрядных компьютеров: Учеб. пос. - Омск, Изд-во ОмГТУ, 1998. -144 с.
19.Флоренсов А.Н. Операционные системы для программиста. Учеб. пос. - Омск, Изд-во ОмГТУ, 2005. -240 с.
20.Флоренсов А.Н. Аппаратно-ориентированное программирование. Учеб. пос. - Омск, Изд-во ОмГТУ, 2005. -128 с.
20.Юров В. Assembler. - СПб.: Питер, 2000. - с.
21.Юров В. Ассемблер: практикум. - СПб.: Питер, 2001. - 400 с.
22.Юров В. Assembler: Специальный справочник. - СПб.: Питер, 200.
23.Юров В., Хорошенко С. Ассемблер: учебный курс. -СПб: Изд-во Питер, 1999. -672 с.
24.Кулаков В. Программирование на аппаратном уровне. Специальный справочник. -СПб.: Питер, 2001. -496 с.
25.http://www.phoenix.gb.net
54
ПРИЛОЖЕНИЕ 1.
Программирование на стандартном ассемблере AT&T
Программирование для операционной системы Linux, как и для всех ОС семейства Unix, производится в подавляющем большинстве случаев на универсальном ассемблере AT&T. Ассемблер этот был разработан в той же фирме, где была создана ОС Unix, и для целей поддержки программирования на нижнем уровне для практически любого процессора. Этот ассемблер создавался как многоплатформенный, но, конечно, для каждого типа процессора должна быть использована модификация такого ассемблера, ориентированная на конкретную систему команд и организацию памяти.
Для выполнения компиляции рассматриваемым ассемблером служит исполняемый файл as, вызываемый для обработки исходного файла prim в командной строки в виде
as prim
Исходный файл ассемблера для Unix традиционно имеет односимвольное расширение s, так что типичным именование исходного файла будет prim.s и т.п. При вызове для компиляции исходного ассемблерного файла с типовым расширением последнее можно опускать. По стандартным допущениям в Unix результирующий объектный файл получается с постоянным стандартным именем a.out. В большинстве случаев для современных программистов это кажется не очень удобным, поэтому целесообразно задать типовое расширение объектного файла, изображаемое в Unix одним символом o, и используя для этого опцию -o. Для получения листинга служит опция -a, а для запрета сообщений о предупреждениях - опция -W. Поэтому вызов компиляции исходного файла prim.s с описанными только что режимами следует задавать в виде prim.s
as -o prim.o prim.s -Wa > prim.lst
В общем случае желательно подготовить файл командного сценария для компиляции произвольных ассемблерных файлов, задав его содержимое в виде
as -o "$1".o "$1".s -Wa >"$1".lst
Здесь макропеременная $1 соответствует первому или единственному параметру вызова сценария. Если этот сценарий как файл назван именем fasm, то для нашего примера вызов должен производиться в виде
fasm prim
Для последующей компоновки объектного файла в исполняемый файл должен осуществляется вызов стандартного компоновщика ld. Для нашего примера его достаточно выполнить в виде
ld -o prim.exe prim.o
который формирует исполняемый файл prim.exe. В общем случае удобно построить файл сценариев обработки для последовательной компиляции и компоновки, назвав его, например, asm2exe и заполнив двумя строками определения действий
as -o "$1".o "$1".s -Wa >"$1".lst ld -o "$1".exe "$1".o
55