ЖУРНАЛ «СТА» №3/2005
мирования на ассемблере, и они связаны с изменившимся «лицом» операционной системы (ОС), осуществляющей встроенную поддержку многого из того, что ранее для DOS реализовывалось на уровне приложений и требовало суще- ственных усилий программиста [2]. Так как статья не посвя- щена глубокому анализу организации Windows, рассмотрим те моменты, которые существенны для решения поставлен- ной задачи. Первым приятным моментом является то, что операци- онная система Windows, работая в защищённом режиме, обеспечивает для каждого запущенного на выполнение приложения отдельное виртуальное адресное пространство размером в 4 Гбайт. Теперь, программируя на ассемблере, не приходиться беспокоиться о существовавшей в DOS проб- леме ограничения адресного пространства сегментов в 64 кбайт. Таким образом, в 32разрядный Windows исполь- зуется только одна модель памяти – «плоская», обозначае- мая ассемблерной директивой MODEL FLAT. Вторым приятным моментом, существенно изменяющим характер программирования в ОС Windows, является то, что при программировании приложения активно используется огромное количество функций интерфейса API (Application Programming Interface), предоставляемых в рамках самой операционной системы Windows и позволяющих значительно минимизировать труд программиста по реализации ка- кихлибо прикладных задач, будь то создание графического изображения окна или работа с файлом, сводя эту работу к простым вызовам в своей программе. Под DOS приходи- лось применять системные вызовы (системные прерывания INT 21H) или прибегать к прерываниям BIOS (особенно часто это касалось работы по созданию интерфейса поль- зователя). Большое богатство функций сосредоточено в системных библиотеках динамической компоновки DLL, основными из которых являются User32.dll, Gdi32.dll, Advapi32.dll и Kernel32.dll. Эти библиотеки предоставляют разработчику программ документированный интерфейс между программами и вызываемыми функциями подсис- тем. User32.dll реализует функции, связанные с поддержкой пользовательского интерфейса, Gdi32.dll обеспечивает гра- фический интерфейс, а Kernel32.dll отвечает за поддержку работы с памятью и взаимодействие с процессами. В отли- чие от статически компонуемых библиотек (раннее связы- вание), привычных нам при программировании в DOS, библиотеки динамической компоновки загружаются в па- мять и обращение к ним идёт динамически, по мере необ- ходимости. При этом распознавание необходимости DLL для загружаемой программы происходит либо автоматичес- ки при запуске программы, либо через вызов в этой прог- рамме соответствующей функции. Второй способ иногда удобней, так как программа может скорректировать своё выполнение по результатам загрузки DLL и продолжить выполнение, скажем, с ограничением своей функциональ- ности, или самостоятельно выгрузить ранее загруженную и ставшую ненужной DLL. В первом случае Windows сообщит об ошибке и выгрузит приложение. Разные способы загруз- ки вносят принципиальные изменения и в код программы. Для первого случая в коде программы необходимо наличие строки с директивой includelib и название так называемой библиотеки импорта (например User32.lib). Эта библиотека позволяет редактору связей получить информацию о требу- емой при динамической компоновке DLL, которая вносит- ся в исполняемый файл (библиотеки импорта по имени совпадают с именем представляемых ими DLL и имеют рас- ширение .lib). Кроме того, в исполняемом файле необходи- мо вызывать функцию GetProcAddress для каждой использу- емой функции, что несколько увеличивает код. При самос- тоятельной загрузке библиотеки импорта в тексте програм- мы не используются, при этом не исключается необходи- мость чёткого знания количества и формата передаваемых параметров в используемых функциях. Существует два ме- ханизма определения функции при её связывании: по но- меру и по имени этой функции. Чаще используется второй вариант, имеющий, как минимум, преимущество читабель- ности исходной программы, так как название отражает вы- полняемую функцию. Являясь разделяемым ресурсом в ОС Windows, DLL существенным образом экономят системные ресурсы, так как в оперативной памяти находится только одна копия DLL при обращении к ней нескольких прог- рамм. Кроме того, DLL существенно уменьшают объём са- мих создаваемых программ, тем самым экономя системный ресурс в части занимаемого программой места на жёстком диске. DLL, кроме исполняемого кода, могут содержать и другие данные, например, графические изображения, шрифты и.т.д. Мы подошли к третьему, очень важному положительному моменту, являющемуся одним из ключевых для ОС Windows, – многозадачности. Как мы помним, в DOS, что- бы написать программу, обеспечивающую параллельное (точнее, псевдопараллельное) выполнение программного кода, приходилось очень потрудиться, так как сама DOS была спроектирована как однозадачная ОС. В Windows эти проблемы в основном решаются на системном уровне, хотя определённые тонкие моменты при программировании ос- таются (вопросы синхронизации при межзадачном обмене и использовании общесистемных ресурсов, например COMпорта). Вопроса синхронизации доступа для разделя- емого участка программы при обращении к общим данным мы ещё коснёмся. При активном использовании вызовов функций необхо- димо помнить о порядке передачи параметров через стек (и не только через стек!) в вызываемые процедуры и функции. С этими моментами программисты должны были сталки- ваться и раньше, при написании процедур и функций на ас- семблере в программах, написанных на языках высокого уровня. Кроме того, при разных подходах является актуаль- ным вопрос о том кто «чистит» стек: вызывающая програм- ма или вызываемая подпрограмма. Для распространенных языков программирования C и Pascal существуют следую- щие соглашения по этим двум вопросам. По соглашению для С параметры в вызываемую функцию передаются спра- ва налево и вызывающая программа должна очистить стек. Например вызов функции Test Test (param_1, param_2) в ассемблерном виде выглядит как push [param_2] push [param_1] call Test add sp,8 По соглашению для Pascal всё с точностью до наоборот, то есть передача параметров в функцию осуществляется слева направо и вызываемая функция ответственна за очистку стека. Для платформ Win32 используется комбини- рованный вариант этих соглашений STDCALL. Согласно этому варианту соглашения данные в вызываемую функ- 75 СТА 3/2005 www.cta.ru В З АПИС Н УЮ К НИЖК У ИНЖЕ Н Е РА
Made with FlippingBook
RkJQdWJsaXNoZXIy MTQ4NjUy