
- •Системное программное обеспечение
- •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.2. Использование библиотек объектных модулей в Win32
Переход к сложным разработкам даже еще в немногопрограммных ОС потребовал разбиения программ на модули. Разработка программ из многих модулей для Windows на основе изложенного выше материала не вызывает никаких новых сложностей, поскольку компоновщик link.exe может использовать в строке вызова не один, а сколько угодно отдельных объектных файлов. Для базового примера можно упростить ближайшее применение функций стандартного ввода-вывода, построив отдельные программы и разместив их в отдельных исходных файлах. Введем в использование подпрограммы writestd, readstd, exitproc (листинги 6.2.1, 6.2.2, 6.2.3).
writestd: ; аргументы в регистрах: регистр EBX — адрес выводимых данных, ECX – их длина
push dword STD_OUTPUT_HANDLE
call _GetStdHandle@4
mov [hstdout],eax
;--- WriteFile(hstdout, prmpt, actlen, &actlen, NULL)
push dword 0
push dword actlen ; address of actual byte number
push ecx ; number of bytes (value !)
push ebx ; address of txt
push dword [hstdout]; N handle=hstdout
call _WriteFile@20
mov eax, [actlen]
ret
Листинг 6.2.1. Программа процедуры writestd в файле writestd.pasm
readstd: ; аргументы в регистрах: регистр EBX – адрес вводимых данных, ECX – ограничение на длину ввода
push dword STD_INPUT_HANDLE
call _GetStdHandle@4
mov [hstdin],eax
;--- ReadFile(hstdin, buf, 80, &actlen, NULL)
push dword 0
push dword actlen
push ecx ; number of bytes
push ebx; address of txt
push dword [hstdin] ; N handle=hstdout
call _ReadFile@20
mov eax, [actlen]
ret
Листинг 6.2.2. Программа процедуры readstd в файле readstd.pasm
exitproc: ; параметр кода ошибки в регистре ECX
push ecx
call _ExitProcess@4
ret
Листинг 6.2.3. Программа процедуры exitproc в файле exitproc.pasm
Эти процедуры можно включить в общий с главной частью программ командный текст, обеспечить описание данных с именами в области данных и главную часть построить в виде файла prog2.asm, приведенного в листинге 6.2.4.
GLOBAL _start
EXTERN _GetStdHandle@4, _WriteFile@20, _ExitProcess@4
EXTERN _ReadFile@20
segment .text
_start: mov ebx, prmpt
mov ecx, 20
call writestd
mov ebx, buf
mov ecx, 80
call readstd
mov byte [buf+1],'!'
mov ebx, buf
mov ecx, eax
call writestd
mov ecx, 0
call exitproc
%include “writestd.pasm”
%include “readstd.pasm”
%include “exitproc.pasm”
segment .data
buf times 80 db 0
prmpt db 'Input text, please: '
hstdin dd 0
hstdout dd 0
actlen dd 0
STD_INPUT_HANDLE equ –10
STD_OUTPUT_HANDLE equ –11
Листинг 6.2.4. Программа prog2.asm
Приведенные изменения позволяют отстраниться от деталей построения процедур writestd, readstd, exitstd, но желательно, чтобы в дальнейшем все эти детали просто не попадались на глаза при написании других программ, использующих эти процедуры. Для этого указанные процедуры целесообразно вынести в отдельные файлы, а далее применять только их объектные результаты – файлы которые назовем хотя бы stdwr.obj, stdrd.obj, stdex.obj.
С этой целью построим файлы stdwre.asm, stdrd.asm, stdex.asm, приведенные на следующих листингах 6.2.5, 6.2.6 и 6.2.7:
GLOBAL writestd
EXTERN _GetStdHandle@4, _WriteFile@20
segment .text
%include “writestd.pasm” ; вставка текста из листинга 6.2.1
segment .data
hstdout dd 0
actlen dd 0
STD_OUTPUT_HANDLE equ -11
Листинг 6.2.5. Программа stdwr.asm
GLOBAL readstd
EXTERN _GetStdHandle@4, _ReadFile@20
segment .text
%include “readstd.pasm” ; вставка текста из листинга 6.2.2
segment .data
hstdin dd 0
actlen dd 0
STD_INPUT_HANDLE equ –10
Листинг 6.2.6. Программа stdrd.asm
GLOBAL exitproc
EXTERN _ExitProcess@4
segment .text
%include “exitproc.pasm” ; вставка текста из листинга 6.2.3
Листинг 6.2.7. Листинг программы stdex.asm
Заметим, что все необходимое для изолированной трансляции последних файлов включено в них (области данных, данные hstdin, hstdout, actlen, нужные для содержания директив extern, и именованные константы).
Теперь, выполнив команды
nasm –fwin32 stdwr.asm
nasm –fwin32 stdrd.asm
nasm –fwin32 stdex.asm
получаем объектные файлы stdwr.obj, stdrd.obj, stdex.obj.
Главная программа, которую назовем prog3.asm, должна строиться с указанием доступа к другим модулям, используя соответствующие директивы extern (листинг 6.2.8).
GLOBAL _start
EXTERN writestd, readstd, exitproc
segment .text
_start: mov ebx, prmpt
mov ecx, 20
call writestd
mov ebx, buf
mov ecx, 80
call readstd
mov byte [buf+1],'!'
mov ebx, buf
mov ecx, eax
call writestd
mov ecx, 0
call exitproc
segment .data
buf times 80 db 0
prmpt db 'Input text, please: '
Листинг 6.2.8. Программа prog3.asm использования writestd, readstd, exitproc
Осуществив компиляцию файла prog3.asm и выполнив вызов компоновщика в виде
link /ENTRY:start /SUBSYSTEM:CONSOLE prog3.obj stdwr.obj stdrd.obj stdex.obj kernel32.lib
получим исполняемый файл prog2.exe, который решает поставленную задачу действий над информацией.
Непосредственно видно, что перечисление многих файлов в строке вызова link неудобно и утомительно, хочется сделать что-то покомпактней. Для решения такой задачи были придуманы библиотеки (наборы) объектных модулей.
В Microsoft для манипуляции с библиотеками объектных модулей служит утилита lib.exe, которая также требует доступного при выполнении файла mspdbномер0.DLL.
Для создания своей библиотеки объектных модулей используем вызов
lib.exe /out:mylib.libstdwr.obj stdrd.obj stdex.obj
В результате должна сформироваться библиотека mylib.lib.
Для ее использования с исходным текстом программы prog3.asm нужны командные вызовы
nasm –f win32 prog3.asm –o %1.obj –l %1.lst
link /ENTRY:start /SUBSYSTEM:CONSOLEprog3.obj mylib.lib kernel32.lib
Утилита библиотекаря Microsoft дает множество дополнительных возможностей, краткую справку по которым можно получить, вызвав ее без каких-либо параметров. Как уже показывалось, параметр /out служит для задания имени результирующего объекта – библиотеки объектных модулей. Заметим, что сложившийся в разработках Microsoft стиль параметров утилит требует (для командного режима) задания опций не с предшествующим дефисом, как в Unix и Linux, а с помощью символов слэш – «косая черта», использующегося в качестве синтаксического признака опции. Кроме того, опять же в отличие от классического стиля, значение опции отделяет от ключевого слова опции вспомогательный символ «двоеточие» (а не пробел).
Для выдачи пользователю информации о составе библиотеки, а именно того, какие объектные файлы входят в ее состав, применяется опция /LIST, которая при необходимости включает дополнительную информаци. об имени файла, где следует сохранить информацию о составе библиотеки (опция в виде /LIST:имя_файла).