- •Системное программное обеспечение
- •Isbn 978-5-8149-2441-4
- •Введение
- •1. Основы программирования на ассемблере
- •1.1. Принципы построения ассемблерных программ
- •1.2. Понятие архитектуры компьютера
- •1.3. Регистры программиста в ia32
- •1.4. Описание сегментной структуры программы
- •2. Простейшие средства ассемблера
- •2.1. Средства описания данных
- •2.2. Обращения к функциям операционной системы посредством прерываний
- •2.3. Средства преобразования в исполняемый файл
- •2.4. Управление строками при выводе и вводе данных
- •2.5. Простейшие способы адресации
- •3. Архитектурные элементы для построения программ
- •3.1. Организация условных переходов
- •Команды условных переходов
- •3.2. Средства организации циклов
- •3.3. Особенности команд умножения и деления
- •3.4. Организация процедур
- •3.5. Неарифметические операции над кодами
- •3.6. Архитектура amd64 процессоров в ассемблерных Linux программах
- •4. Использование неэлементарных способов адресации
- •4.1. Косвенно-регистровая адресация и ее использование
- •4.2. Использование индексной адресации данных
- •4.3. Базовая и индексно-базовая адресации
- •5. Взаимодействие программных компонентов
- •5.1. Многомодульная разработка программ
- •5.2. Организация стекового кадра подпрограммы
- •5.3. Программный доступ к системным функциям Win32
- •5.4. Использование свободно распространяемых утилит для Win32
- •5.5. Вызов функций из стандартных библиотек Linux
- •6. Библиотеки объектных модулей
- •6.1. Использование библиотек объектных модулей в Linux
- •6.2. Использование библиотек объектных модулей в Win32
- •7. Разделяемые библиотеки выполняемых программ
- •7.1. Понятие о статической и динамической компоновке
- •7.2. Конструкция библиотеки динамической компоновки
- •7.3. Компоновка времени загрузки с использованием GoLink
- •Контрольные вопросы
- •Заключение
- •Библиографический список
6. Библиотеки объектных модулей
6.1. Использование библиотек объектных модулей в Linux
Когда объектных модулей, необходимых для компоновки программы, оказывается много, программисту становится неудобным перечислять их все при вызове компоновщика. Ситуация становится почти катастрофической, когда таких модулей многие десятки и даже сотни.
Выход был найден с помощью специализированных наборов объектных модулей, хранимых как отдельные файлы и называемых обычно библиотеками объектных модулей. В ОС Unix для аналогичных целей вначале использовался еще термин архив объектных модулей. Применение библиотек требует служебных утилит обслуживания, называемых обычно библиотекарями или архиваторами (последний термин характерен для Unix и, как уже объяснялось, несколько устарел).
Утилита обслуживания библиотек в Unix называется ar, и ее вызовы имеют в упрощенной форме общий вид
ar опции модификаторы имя_библиотеки объектные_файлы
где компонент объектные_файлы представляет собой перечисление имен файлов, разделяемых пробелами. Заметим, что данная утилита может применяться для сохранения в виде компактного набора не только объектных файлов, но и любых других файлов, но именно библиотеки объектных файлов являются мощным вспомогательным средством при разработке сложных программ.
Основными опциями данной утилиты, которые мы рассмотрим, являются опции -r, -d, -m, -t. Первая из них задает добавление нового объектного файла или файлов к библиотеке, вторая опция задает удаление указанных в перечне файлов из библиотеки, третья опция задает перемещение указанных в перечне файлов из библиотеки в текущий каталог, а опция -t приказывает выдать на стандартный вывод перечень файлов, содержащихся в библиотеке. Модификаторы призваны повысить эффективность использования и построения библиотек и записываются непосредственно за опцией. Модификатор, задаваемый буквой 'c', предназначен для указания, что библиотеку нужно создать. Стандартное расширение имени библиотек объектных модулей в Unix содержит единственную букву 'a' (строчную латинскую букву).
Следующий пример демонстрирует использование библиотеки объектных модулей. Сами модули формируются из исходных файлов с именами stwrite, stread, stexit, содержащих, соответственно, процедуры stdread, stdwrite, stdexit, и приведены в листингах 6.1.1, 6.1.2 и 6.1.3.
GLOBAL stdread
SEGMENT.text
stdread: ;<adress into ecx, max len into edx, actlen ->eax >
;--- read(1, buf, len) == <3>(ebx, ecx, edx)
push ebx
mov eax,3 ; N function=read
mov ebx,0 ; 0 handle=0 (stdin)
int 80h
pop ebx
ret
Листинг 6.1.1. Процедура stdread в файле stread.asm для библиотеки Linux
GLOBAL stdwrite
SEGMENT.text
stdwrite: ;<adress into ecx, max len into edx>
;--- write(1, buf, len) == <4>(ebx, ecx, edx)
push eax
push ebx
mov eax,4 ; N function=write
mov ebx,1 ; N handle=1 (stdout)
int 80h
pop ebx
pop eax
ret
Листинг 6.1.2. Процедура stdwrite в файле stwrite.asm для библиотеки Linux
GLOBAL stdexit
SEGMENT.text
stdexit: mov eax,1
int 80h ; function=exit
ret
Листинг 6.1.3. Процедура stdexit в файле stexit.asm для библиотеки Linux
Формирование объектных файлов проще всего выполнить с помощью командного файла, имеющего для дальнейшего использования имя nasmc, содержимое которого приведено в листинге 6.1.4.
nasm –f elf$1.asm –l $1.lst
Листинг 6.1.4.Командный файл nasmc для раздельной трансляции
Далее с помощью командного вызова
ar –rcmyliba.astwrite.o stread.o stexit.o
нужно построить библиотеку с именем myliba.a. Использование библиотеки предполагает программа, приведенная в листинге 6.1.5.
GLOBAL _start
EXTERN stdread, stdwrite, stdexit
SEGMENT .text
_start:
;--- stdread(buf, 80) == call stdread < ecx, edx >, result into eax
mov ecx, buf ; address of buf
mov edx,80 ; number of byte
call stdread; arguments into ECX, EDX – адрес области для данных и ее длина
; число прочитанных байтов в регистре EAX
mov [len],eax
mov byte [buf+2],'!'
;--- stdwrite(buf, [len]) == call stdwrite < ecx, edx >
mov ecx, buf ; address of buf
mov edx,[len] ; number of byte
call stdwrite ; arguments into ECX, EDX – адрес области данных и ее длина
call stdexit
SEGMENT .bss
buf resb 80
SEGMENT .data
len dd 0
Листинг 6.1.5. Программа prim5e.asm использования собственной библиотеки
Изготовление исполняемой программы из исходного текста в листинге 6.1.5 может осуществляться двумя командными вызовами, приведенными в следующих строках:
./nasmc prim5e
ld –o prime.exe prim5e.o myliba.a
Процесс изготовления исполняемой программы примера можно автоматизировать, применяя командный файл, текст которого дан в листинге 6.1.6.
./nasmc stwrite
./nasmc stread
./nasmc stexit
ar –rc myliba.a stwrite.o stread.o stexit.o
ar –t myliba.a
./nasmc prim5e
ld –o prime.exe prim5e.o myliba.a
Листинг 6.1.6. Файл komfil построения и использования библиотеки
Заметим, что имена процедур в объектных модулях библиотеки никак не связаны (кроме возможных ассоциаций разработчика) с именами соответствующих объектных файлов. Более того, один библиотечный файл может содержать множество процедур и, в общем случае, любых внешних имен, используемых в дальнейшем из этой библиотеки. Установление связей между компонентами будущей исполняемой программы в процессе компоновки осуществляется исключительно по внешним именам в модулях, занесенных в библиотеку, а имена объектных модулей существенны только для приказов вставки или удаления объектных модулей в (из) библиотеки. В частности, процедуры stdread, stdwrite, stdexit целесообразно поместить в один исходный файл и, как следствие, в один объектный файл. В общем случае разнесение процедур по различным объектным модулям приводит к тому, что к машинным кодам компонуемой программы подключаются машинные коды только тех объектных модулей библиотеки, которые действительно необходимы, а остальные не подключаются.
При компоновке исполняемой программы при вызове компоновщика может быть указано столько библиотек, сколько необходимо. Для этого их следует просто включить в перечень обрабатываемых компоновщиком файлов, компоновщик сам определяет, что с ними делать, используя их внутренний формат.