- •Системное программное обеспечение
- •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
- •Контрольные вопросы
- •Заключение
- •Библиографический список
5.4. Использование свободно распространяемых утилит для Win32
С учетом стремления пользоваться некоммерческими продуктами, которые нередко более активно совершенствуются в последующих общедоступных версиях, рассмотрим современный библиотекарь для форматов файлов Windows. (Можно заметить, что 10–15 лет назад активно использовались и поддерживались выпуском новых версий, теперь почти забытые утилиты от фирмы Borland и Watcom и некоторых независимых производителей, на которых, как морально устаревших, останавливаться не будем.)
Наиболее интересным оказывается утилита системного компоновщика GoLink.exe (CopyrightJeremyGordon 2002–2016 – JG@JGnet.co.uk). Отличительной особенностью этой утилиты является полный отказ от библиотек объектных файлов и библиотек импорта. С формальной стороны отсюда вытекает отсутствие возможности использовать в качестве параметров файл, имеющий расширение .LIB. Отказ от библиотек импорта компенсируется решением использовать информацию об импортируемых именах (в первую очередь именах подпрограмм) непосредственно из DLL, задействованных в дальнейшем выполнении исполняемых файлов.
Практически такое решение значительно упрощает разработку, поскольку для будущей работы DLL обязательно должны быть в системе, а ориентация на библиотеки импорта требует наличия таких библиотек у разработчика, в том числе не имеющего коммерческих средств разработки. Другие корпоративные разработчики (Borland и Watcom) предоставляли стандартные для них средства оперативного преобразования имеющихся DLL в соответствующие им библиотеки импорта, но Microsoft целенаправлено избегала предоставления таких средств и ограничивала тем самым возможности сторонних разработчиков. Сами библиотеки импорта от Microsoft всегда специально строились так, чтобы обеспечивать взаимодействие только с определенной версией DLL для конкретного типа особенностей операционной системы, что неявно понуждала не очень профессиональных программистов пользоваться программными инструментами исключительно от MS и заметно снижала оперативность сторонних разработок.
Неподдержка программой GoLink библиотек объектных файлов не позволяет разработчику использовать такие библиотеки, поэтому очевидным образом автор указанной утилиты и не предлагает никакой собственный вариант утилиты библиотекаря. Фактически все это отражает современную ситуация отхода от широкого спектра инструментальных возможностей и от применения по возможности компактных и нерасточительных относительно запросов на аппаратурные ресурсы средств. В результате происходит подталкивание к использованию в качестве библиотечных наборов исключительно DLL, несмотря на то, что они в частных решениях иногда оказываются неэффективными (аналогично забиванию мелких гвоздей большим молотком).
Очень приятное свойство утилиты GoLink для 32-битных приложений заключается в том, что, как следствие принятых и кратко описанных выше технических решений, не нужно отвлекаться на модифицированные имена системных функций. Поскольку в DLL применяются «родные» имена системных функций, то никаких дополнительных подчеркиваний, специальных символов и числовых добавлений не требуется.
В результате для решения поставленной выше простейшей проблемы ввода и вывода формируются тексты, приведенные в листингах 5.4.1 и 5.4.2.
GLOBAL _start
EXTERN GetStdHandle, WriteFile, ExitProcess
EXTERN ReadFile
segment .text
_start: push dword STD_OUTPUT_HANDLE
call GetStdHandle
mov [hstdout],eax
push dword STD_INPUT_HANDLE
call GetStdHandle
mov [hstdin],eax
;--- ReadFile(hstdin, buf, 80, &actlen, NULL)
push dword 0
push dword actlen
push dword 80 ; number of bytes
push dword buf ; address of txt
push dword [hstdin] ; N handle=hstdout
call ReadFile
mov byte [buf+1],'!'
;---WriteFile(hstdout, buf, actlen, &actlen, NULL)
push dword 0; NULL
push dword actlen ; address of actual byte number
push dword [actlen]
push dword buf ; address of txt
push dword [hstdout]; N handle=hstdout
call WriteFile
; ExitProcess(0)
push dword 0
call ExitProcess
segment .data
buftimes 80 db 0
hstdin dd 0
hstdout dd 0
actlendd 0
STD_INPUT_HANDLE equ –10
STD_OUTPUT_HANDLE equ –11
Листинг 5.4.1. Программа на ассемблере для компоновщика GoLink
Командный файл разработки для этой программы имеет вид
nasm –f win32 %1.asm
golink /entry _start /console %1.obj kernel32.dll
Листинг 5.4.2. Командный файл для получения выполняемой программы
Таким образом, трансляция NASM не имеет никаких особенностей (транслятору все равно, какие внешние имена используются для функций, детализация их связей с местом реализации – это забота компоновщика). Вызов golink имеет ряд мелких, но приятных относительно link от MS особенностей. В опции /entry задается без раздражающего специального разделителя именно то имя точки входа, которое было написано в исходной программе на ассемблере (никаких закулисных соглашений и неявных договоренностей). Назначение результирующего файла задается как консольного более кратким вариантом содержательной опции /console. При ее отсутствии формируется по возможности исполняемый файл графического приложения.
Хотя утилита golink не позволяет использовать библиотеки объектных файлов, в ее вызове можно явно указать любое число объектных файлов. Эти объектные файлы опять же следует использовать с собственными именами системных функций. В результате для нашей задачи должны быть построены файлы wrstdg, rdstdg, exitprocg и на их основе получены объектные модули writestdg, readstdg, exitprocg (листинг 5.4.3, 5.4.4, 5.4.5):
segment .text
writestdg: ; регистр EBX – адрес выводимых данных, ECX – их длина
extern GetStdHandle, WriteFile
global writestdg
push dword –11;STD_OUTPUT_HANDLE
call GetStdHandle
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
mov eax, [actlen]
ret
SEGMENT .data
hstdout dd 0
actlendd 0
Листинг 5.4.3. Содержимое файла stdwrg.asm с процедурой writestd
segment .text
readstdg: ; регистр EBX – адресданных, ECX – ограничение на длину ввода
extern GetStdHandle,ReadFile
global readstdg
push dword –10 ;STD_INPUT_HANDLE
call GetStdHandle
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
mov eax, [actlen]
ret
SEGMENT .data
hstdin dd 0
actlen dd 0
Листинг 5.4.4. Содержимое файла stdrdg.asm с процедурой rditestdg
segment .text
exitprocg: ; параметр кода ошибки в регистре ECX
extern ExitProcess
global exitprocg
push ecx
call ExitProcess
ret
Листинг 5.4.5. Содержимое файла stdexg.asm с процедурой exitprocg
Главная программа будет задаваться текстом, приведенным в листинге 5.4.6.
GLOBAL _start
EXTERN writestdg, readstdg, exitprocg
segment .text
_start: mov ebx, prmpt
mov ecx, 20
call writestdg
mov ebx, buf
mov ecx, 80
call readstdg
mov byte [buf+1],'!'
mov ebx, buf
mov ecx, eax
call writestdg
mov ecx, 0
call exitprocg
segment .data
buf times 80 db 0
prmpt db 'Input text, please: '
Листинг 5.4.6. Главная программа prog3g, использующая writestd, readstd, exitstd
Вызов компилятора и компоновщика для построения выполняемого файла в данном случае должен задаваться в виде последовательности команд:
nasm –fwin32 prog3g.asm
golink /entry _start /console prog3g.obj stdwrg.obj stdrdg.obj stdexg.obj kernel32.dll
