Анимация
JavaScript


Главная  Библионтека 

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 [ 52 ] 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88

include \masm32\include\windows.inc include \masra32\include\kernel32.inc includelib lcernel32 . lib include \roasra32\include\user32.inc includelib user32.1ib При их обработке транслятор MASM32, встретив строку include \masm32\include\windows.inc, открывает файл windows.inc, находящийся в директории \MASM32\INCLUDE, и зафужает его содержимое как часть нащей программы (по аналогии с включаемыми файлами в языке С).

Файл windows.inc содержит в себе определения системных констант и структур Windows. Что касается прототипов системных вызовов, необходимо включение дополнительных файлов из директории \masm32\include, соответствующих необходимым динамически зафужаемым библиотекам разрабатываемому проекту.

В нащей профамме мы вызываем функции, экспортированные из библиотек user32.dll и kernel32.dl!, и соответственно, для этого мы должны подключить прототипы функций из user32.dll и kemel32.dll. Это файлы - user32.inc и kemel32.inc. Если Вы откроете их в текстовом редакторе, Вы увидите, что они состоят из описаний прототиг функций этих DLL.

Подключение файлов директивой include еще не обеспечивает разрещения адресов фу ций, требующихся разрабатываемой профамме. Транслятору необходимо также сообщить имена библиотек экспорта. И тут мы встречаем новую директиву includelib. В отличие от директивы include, она является лишь способом сообщить ассемблеру, с какими библиотеками собираемая профамма должна связываться перед началом своей работы.

Возможно указание имен библиотек импорта и в командной строке при запуске компоновщика, но это малоудобно, да и командная сфока может вместить максимум 128 символов. Доступные библиотеки экспорта располагаются в директории \masm32\lib. Подробное описание системных вызовов и место их расположения в библиотеках экспорта ОС Windows можно найти в документации MSDN или другой справочной литературе по профаммированию для Windows, option casemap:none Данная строчка профаммы вынуждает транслятор MASM32 определять символические метки, чувствительные к регистру, таким образом, имена ExitProcess и exitprocess будут восприниматься как различные последовательности символов.

Итак, выполнение профаммы начинается со строки, находящейся за меткой start. И это вызов

invoke MessageBox, NULL,addr MsgBoxText, addr MsgCaption, MB OK Известно, что вызов подпрофамм на языке ассемблер осуществляется командой процессора call с указанием адреса подпрофаммы. Ассемблер MASM32 имеет в своем синтаксисе расширенную директиву вызова подпрофаммы (функции), которая, в конце концов,

push push push push call

offset MsgCaption offset MsgBoxText 0

MessageBoxA

Рассмотрим подробнее механизм прототипов функций. Для того чтобы MASM32 смог правильно транслировать вызов директивы INVOKE, необходимо перед ним сделать определение данной функции в виде прототипа, специфицирующего имя функции, количество и типы передаваемых параметров. Как уже отмечалось, это делается в соответствующих включаемых файлах. Например, функция MessageBoxA определяется в файле user32.inc в виде:

MessageBoxA PROTO :DWORD,:DWORD,:DWORD,:DWORD Строка выше называется прототипом функции. Прототип функции указывает ассемблеру/линковщику атрибуты функции, так что он может самостоятельно делать проверку этих типов. Формат записи прототипов функций следующий: ИмяФункции PROTO [ИмяПараметра]: ТипДанных, [ИмяПараметра] :ТипДанных, . . .

Говоря кратко, за именем функции следует ключевое слово PROTO, а затем список переменных с указанием типа данных, разделенных запятыми. В приведенном выше примере с MessageBoxA эта функция была определена как принимающая четыре параметра типа DWORD. Прототипы функций очень полезны, когда используется высокоуровневый синтаксический вызов - invoke с проверкой типов данных.

Следует пояснить, почему в тексте профаммы записан вызов MessageBox, а мы обсуждаем имя MessageBoxA. Дело в том что существует две категории API функций: одна для работы со строками формата ANSI, а другая для Unicode строк. На конце имен API функций ANSI ставится "А", например MessageBoxA. В конце имен функций дня Unicode ставится "W" - MessageBoxW. Транслятор в зависимости от используемой архитектуры автоматически делает замену «обобщенного» имени на специфическое -с должной буквой. Например, Windows 95 поддерживает только ANSI формат строк и в ней требуется использование функций, оканчивающихся на "А", Windows NT, наоборот, ориентирована на Unicode.

Мы обычно имеем дело с ANSI сфоками (например, массивы символов, оканчивающиеся нулем). Размер ANSI-символа - 1 байт. В то время как ANSI достаточна для европейских языков, она не поддерживает некоторые, восточные языки, в которых присутствуют несколько тысяч уникальных символов. Вот в этих случаях в дело вступает LlniCode. Размер символа UNICODE - 2 байта, и поэтому может поддерживать 65536 Уникальных символов.

.фзнслируется в упомянутую выше команду call, но при этом автоматизирует все работу по поддержанию интерфейса вызова функции (работу со стеком). В нашем случае это:



Следуя документации на функцию MessageBox в нашей профамме, мы передаем сле дующие парамефы:

NULL - (признак модальности) значение принадлежности нашего окна какому-либ другому окну (описатель окна) или рабочему столу Windows (в случае NULL); итак наше окно принадлежит рабочему столу;

addr MsgBoxText - адрес сфоки заголовка нашего окна (директива addr аналогична директиве offset для вычисления смещения в текущем сегменте, не забываем о модели памяти FLAT);

addr MsgCaption - адрес сфОки сообщения, отображаемого в окне;

МВОК - тип окна сообщения, определяющий внешний вид окна; нас интересует окно подтверждения с кнопкой "Ок".

Вызов функции MessageBox отобразит на экране компьютера окно рис. 4.4, которое может быть закрыто нажатием на кнопку "Ок" или на кнопку закрытия окна - "с крестиком",

Для корректного завершения работы нашей профаммы необходим вызов функции ExitProcess из библиотеки kemel32.dll. invoke ExitProcess,NULL

Функция принимает единственный параметр, являющийся кодом завершения пр фаммы, передаваемый Windows в виде возвращаемого значения стартовой функци NULL является признаком успешного завершения работы профаммы.

5.4. Динамически загружаемые библиотеки

Как уже было сказано, любая профамма для Windows во время своей работы польз}-ется сервисами ОС, экспортируемыми ее динамически зафужаемыми библиотеками. В этом разделе мы разработаем простейшую динамически зафужаемую библиотек), предоставляющую свои вызовы программе для Windows, и обсудим механизм ее работы.

Зачастую при написании различных профамм возникает необходимость использования в них одних и тех же общих подпрофамм (функций), повторяя их текст в каждой новой разработке. Во времена DOS профаммисты сохраняли эти общие фрагменты кода в одной или более библиотеках. Для подключения их в свой очередной проект они сообщали линковщику о необходимости связывания той или иной библиотеки с посфоенным транслятором объектным файлом, и линковщик извлекал фебующиеся функции прямо из этой библиотеки и вставлял их в результирующий исполняемый файл. Такой процесс называется статической компоновкой. Хорошим примером этого является стандартная библиотека языка С. Однако у этого метода есть изъян: в каждой профамме у вас находятся абсолютно одинаковые копии кода. Впрочем, для ДОСовских профамм это не очень большая проблема, так как только одна профамма могла быть активной в текушиЙ момент, и поэтому не происходила трата драгоценной памяти (не считая дисковой).

В Windows ситуация стала более критичной, так как в определенный момент времени Рет быть зафужено несколько профамм, выполняющихся одновременно, и проблема яционального использования оперативной памяти становится еще более значимой. Как говорилось, у Windows есть решение этой проблемы: динамические зафужаемые библиотеки. И в свете обсуждаемого вопроса можно сказать, что динамически зафужае-ая библиотека - это что-то вроде носителя общего кода для Windows профамм. И поэтому, ОС Windows не будет зафужать несколько копий DLL в память в случае работы нескольких профамм или копий одной профаммы, завязанных на некоторую динамически зафужаемую библиотеку.

В реальности, у всех процессов, использующих одну и ту же DLL, есть своя копия в виртуальном адресном просфанстве кода этой библиотеки, однако Windows делает так, чтобы все процессы разделяли одну копию этой DLL в физической памяти. Впрочем, секция данных библиотеки все же является уникальной для каждого процесса.

Профамма линкуется с DLL на этапе ее зафузки на выполнение, в отличие от того как это осуществлялось в случае статических библиотек во время сборки. Существует также возможность зафузить и, соответственно, выфузить DLL во время выполнения профаммы с помощью системных вызовов. Естественно, если только ваша профамма в данный момент использует некоторую библиотеку DLL, тогда она будет выфужена из памяти немедленно. Но если ее еще используют какие-нибудь другие профаммы, DLL останется в памяти, пока ее не выфузит последняя из использующих ее профамм.

При сборке профаммы, использующей динамически зафужаемые библиотеки, перед компоновщиком стоит сложная задача разрешения адресов в конечном исполняемом файле. Поскольку он не может "извлечь" функции и вставить их в финальный исполняемый файл, он должен каким-то образом сохранить достаточно информации для зафуз-чика Windows о фебуемых профаммой DLL и используемых функциях в выходном файле, чтобы тот смог найти и зафузить верную DLL во время выполнения.

Здесь в дело и вступают библиотеки импорта. Библиотека импорта содержит информацию о DLL, которую она описывает. Компоновщик может получить из нее необходимую информацию и вставить ее в исполняемый файл. Когда Windows загружает профамму в память, она видит, что профамма фебует ту или иную DLL, поэтому за-Фузчик ищет эту библиотеку и проецирует ее в адресное просфанство процесса (зафу-жаемой профаммы) и тогда уже выполняет разрешение адресов вызовов функций.

Как уже говорилось, возможна зафузка библиотеки DLL самостоятельно во время выполнения профаммы, не полагаясь на Windows-зафузчик. В этом случае Вам ш потребуется библиотека импорта и Вы сможете зафужать и использовать любую DLL даже если к ней не прилагается библиотеки импорта. Тем не менее, все равно необходимо располагать информацией о том, какие функции находятся внуфи библиотеки, числе и типы передаваемых и возвращаемых парамефов.



Когда вы «поручаете» Windows загружать DLL, и если та отсутствует, Windows выдаст соответствующее сообщение и ваща программа не сможет сделать ничего, да) если наличие данной DLL не является критичным, поскольку будет закрыта. Если же вы будете зафужать DLL самостоятельно и библиотека не будет найдена, ваща программа может самостоятельно обработать данную ошибку и выдать пользователю сообщение уведомляющее об этом, и, возможно, продолжить работу.

Вы можете вызывать недокументированные функции, которые не включены в официальные библиотеки импорта, главное, чтобы у вас было достаточно информации о семантике этих функций. Для организации профаммной зафузки библиотеки DLL требуются навыки работы с системными вызовами Windows, знание LoadLibrary и GetProcAddress (об этом ниже).

Итак, начнем разработку простейшей динамически загружаемой библиотеки для Windows, экспортирующей единственную тестовую функцию.

В среде разработки RadAsm выбираем в меню File пункт New Project. В появившемся окне (рис. 5.4.1) выбираем тип нового проекта, обратите внимание на то, что это должен быть проект динамически загружаемой библиотеки (D11 Project), и заполняем соответствующие поля в имени проекта (Project Name) и строки его описания (Project Description).

Project Wizard Туре 8> Name

Assemble!


Рго[ес1 Type

О Win32 App О Dos App

О Console App О Dos App [ com)

Э Dll Piojecl

G UB Proiecl

CNMAKEPraiecl

О Win32 App (no res)

Proiecl Name; TeslDll

Piojecl Descriplion; The lesl DLL

Projecls Folder; i:;\fiaii4sm\Masm\Proiecls Q

Template; Cl

Далее >

Puc. 5.4.1. Мастер проектов - тип u имя

Нажимаем кнопку "Далее" (Next). Содержимое следующего окна (рис. 5.4.2) создан! проекта динамически зафужаемой библиотеки требует некоторого пояснения.

Как уже известно, в этом окне осуществляется выбор файлов и каталогов, которь -будут созданы для нашего нового проекта. Что касается именно проекта DLL, то в не появились новые опции создания Inc и Def файлов. Файлы с расширением .inc, как и вестно, носят имена соответствующих библиотек экспорта и используются для описанг сфуктур данных и прототипов функций включаемых в соответствующую библиотек


Рис. 5.4.2. Мастер проектов - Файлы и директории

Как уже говорилось, последнее окно (рис. 5.4.3) предназначено для тонкой настройки окружения сборки, а в нашем случае все установки по умолчанию являются достаточными. Поэтому нажимаем на кнопку "Готово" (Finish) и набираем текст соответствующих исходных файлов.

;rgect Wizard

Make Menu


Assemble

Link

Runm/debug □ Assembte Modules

4,Q.JB\HC,EXE /v.l

3,Q.1B\MLEXE /с /call /Cp /nologo /Г$ 7,Q.1B\LINK,EXE /SUBSYSTEM.v/INDD 0,0„5

Rixrw/debug 0.0.\0lyDbg4OlljCbg.5 Res To Dbj rsrc.obi.Q,tB\CVTRES.EXEjsic.res AsmModule; ob,0.$B»WLEXE /с/coll/Cp/nologoЛ

<№mj Jl Готово Отг«™

Puc. 5.4.3. Мастер проектов ~ Настройка меню Make

PLL. Файлы с расширениями .def являются файлами установок модулей разрабатываемых DLL и описывают их структуру и характеристики.

Р„,йД Wizard-



0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 [ 52 ] 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88