- •Системное программирование на макроассемблере masm32
- •«Системное программирование» (часть 1)
- •Вступление
- •1Организация среды исполнения для масм
- •1.1Цель работы
- •1.2 Теоретические сведения
- •If errorlevel 0 команда2
- •If errorlevel 0 goto метка
- •1.3Выполнение работы
- •1.4Состав отчета по работе
- •1.5Контрольные вопросы
- •2.2.2Состав пакета масм
- •2.2.3Центр масм – редактор Quick Editor
- •2.3Выполнение работы
- •2.4Состав отчета по работе
- •2.5Контрольные вопросы
- •3Высокоуровневый интерфейс языка масм
- •3.1Цель работы
- •3.2 Теоретические сведения
- •3.2.1Процедуры и макросы в ассемблере
- •3.2.2Синтаксис высокого уровня масм
- •3.2.3Макрос invoke
- •3.3Выполнение работы
- •4.2.2Потоки вывода и ввода
- •4.2.3Вывод и ввод в консольных приложениях
- •4.3Выполнение работы
- •4.4Состав отчета по работе
- •4.5Контрольные вопросы
- •5Ввод и вывод в ассемблерных приложениях с графическим интерфейсом
- •5.1Цель работы
- •5.2Теоретические сведения
- •5.3Выполнение работы
- •6.3.1Фрейм кода (области 1-5)
- •6.3.2Фрейм дампа памяти (области 9,10 и 11)
- •6.3.3Фрейм регистров процессора (области 6, 7 и 8)
- •6.3.4Фрейм стека (области 12, 13 и 14)
- •6.4Выполнение работы
- •6.5Состав отчета по работе
- •6.6Контрольные вопросы
- •Приложение а Префиксы «венгерской» нотации типов данных WinApi
- •Рекомендованная литература
4.3Выполнение работы
Откройте в QE файл \MASM32\examples\exampl02\textio\ textio.asm и пересохраните его в свою рабочую папку под именем lab4.asm. Он будет подвергаться дальнейшему анализу и комментированию, поэтому исходный файл textio.asm портить не надо.
Выполните Project > Console Assemble & Link. Просмотрите, что выведено в окно консоли с протоколом компиляции и компоновки. Нет ли сообщений об ошибках? Выполните Project > Run Program.
После приглашения Enter Some Text > вы что-то напечатали и на следующей строке программа повторила ваш ввод эхо-выводом. Ниже появилось приглашение Type something > и вы опять что-то напечатали. Что произошло после нажатия Enter?
Перейдите в lab4.asm на строки 94-96. Изучив текст программы, определите, что должно делаться строками 94-96. А вы видели эти результаты при исполнении программы? Сформулируйте для отчета возможную причину наблюдаемого эффекта.
Откройте \MASM32\m32lib\stdout.asm и распечатайте его для отчета.
Откройте \MASM32\m32lib\stdin.asm и распечатайте его для отчета.
Имея перед глазами файлы stdout.asm и stdin.asm, подробно построчно прокомментируйте файл lab4.asm.
Письменно ответьте на контрольные вопросы. Писать сначала текст вопроса, затем ответ на него.
Оформить отчет по лабораторной работе.
4.4Состав отчета по работе
Название и номер работы, фамилия и группа студента.
Цель работы.
Протокол выполнения работы с текстами ответов на все вопросы в заданиях пункта «Выполнение работы».
Ответы на контрольные вопросы.
Личная подпись автора отчета.
4.5Контрольные вопросы
Каково назначение макроса print в файле lab4.asm? Контейнером какой процедуры он является? В чем удобство использования print?
Каково назначение макроса input? Опишите словами, что происходит в программе при исполнении команд макроса input? В чем состоит удобство его применения?
В строке 50 написано «Main PROTO». Что это значит и зачем это нужно?
В строках 90 и 94 вызывается процедура locate. Используя файл \MASM32\m32lib\locate.asm, определите, какую функцию WinAPI она инкапсулирует? Найдите в MSDN (можно в другом источнике) ее описание приведите его в отчете.
5Ввод и вывод в ассемблерных приложениях с графическим интерфейсом
5.1Цель работы
Изучить технику использования элементов графического пользовательского интерфейса (Graphic User Interface, GUI), которые применимы для ввода данных в программу и вывода текстов.
5.2Теоретические сведения
Применение графического пользовательского интерфейса означает правильное использование интерфейсных возможностей операционной системы (например, Windows), которые она способна предоставить любой программе, которая выполняется под ее управлением. Все сводится, в общем, к правильному вызову нужных функций программного интерфейса WinAPI.
К сожалению, вокруг этого, в общем, простого положения наслаивается большое количество разных частностей, нюансов и особенностей, которые отчасти объясняются архитектурами ОС и среды разработки приложений. Другая причина всех этих сложностей в том, что любая ОС есть продукт исторического развития от версии к версии, и при этом разработчики стараются по возможности обеспечить обратную совместимость новых версий с программами, написанными для предыдущих версий. Из-за этого множатся всякие варианты выполнения одних и тех же действий, а прописывание их во всякого рода настройках, увы, осложняет разработку программ. Сказанное приводит к пониманию, что этого избежать, по большому счету, практически невозможно, поэтому постараемся просто разобраться в этом.
Типичную структуру папки ассемблерного приложения с GUI можно увидеть, например, в MASM32\examples\dialogs_later\basic. Откройте ее. В ней содержатся файлы:
basicdlg.asm – текст программы на МАСМ;
basicdlg.ico – файл иконки программы;
manifest.xml – файл «манифеста»;
rsrc.rc – ресурсный файл.
Эти файлы представляют собой настоящий набор «исходных файлов», из которых с помощью пакетного файла makeit.bat создается исполняемый модуль basicdlg.exe.
Файлы basicdlg.asm, manifest.xml, rsrc.rc и makeit.bat можно открыть и просмотреть текстовым редактором, лучше всего Notepad++. Файл basicdlg.ico можно просмотреть, например, через Paint. Что делает программа в целом, можно увидеть, просто запустив basicdlg.exe.
Файлы basicdlg.ico, manifest.xml и rsrc.rc – вспомогательные. Они поставляют программе информацию и данные, необходимые для правильного показа элементов GUI. Главным среди них является ресурсный файл rsrc.rc. Откройте его и обратите внимание на строчки
1 24 "manifest.xml"
5 ICON "basicdlg.ico"
Этими строками вспомогательные ресурсы программы связываются воедино – ресурсный файл содержит в себе ссылки на иконку и на файл манифеста.
Для чего нужна иконка (файл basicdlg.ico) и как она создается, студент 2-го курса компьютерной специальности, скорее всего, знает. А вот что касается файла манифеста manifest.xml, то, скорее всего, такой ясности нет и надо сделать необходимые пояснения.
Манифест (manifest) - это текст на языке XML, описывающий программу и графические библиотеки, необходимые для ее работы. До выхода Windows XP часть оконных классов - так называемые базовые классы окон - кнопки, статические тексты (static text), поля ввода (editbox), скроллбары, списки и комбобоксы - хранилась в основной библиотеке (версия 5.80), отвечающей за элементы пользовательского интерфейса - user.exe. А вот в Windows XP новую версию библиотеки этих классов (версия 6.0) поместили в библиотеку comctl32.dll. Таким образом обеспечена обратная совместимость со старыми программами. Но чтобы сообщить программе, какую из двух библиотек следует использовать, и нужен манифест.
Чтобы было понятно, как ресурсы связываются с основной программой, нужно открыть файл makeit.bat (строки мы пронумеровали для наглядности):
@echo off
if not exist rsrc.rc goto over1
\masm32\bin\rc /v rsrc.rc
\masm32\bin\cvtres /machine:ix86 rsrc.res
:over1
if exist "template.obj" del "basicdlg.obj"
if exist "template.exe" del "basicdlg.exe"
\masm32\bin\ml /c /coff "basicdlg.asm"
if errorlevel 1 goto errasm
if not exist rsrc.obj goto nores
\masm32\bin\Link /SUBSYSTEM:WINDOWS "basicdlg.obj" rsrc.res
if errorlevel 1 goto errlink
dir "basicdlg.*"
goto TheEnd
:nores
\masm32\bin\Link /SUBSYSTEM:WINDOWS "basicdlg.obj"
if errorlevel 1 goto errlink
dir "basicdlg.*"
goto TheEnd
:errlink
echo _
echo Link error
goto TheEnd
:errasm
echo _
echo Assembly Error
goto TheEnd
:TheEnd
pause
Обратим внимание на выделенные строки 3,4, 8 и 11.
Строка 3. \masm32\bin\rc /v rsrc.rc – это компиляция ресурсного файла из исходного представления в формат Windows Resource.
Строка 4. \masm32\bin\cvtres /machine:ix86 rsrc.res – это конвертация ресурсного файла в объектный формат (результат – файл rsrc.res), чтобы потом этот формат понял компоновщик Link.
Строка 8. \masm32\bin\ml /c /coff "basicdlg.asm" – это компиляция исходного текста программы в объектный формат (результат – файл basicdlg.obj).
И, наконец, строка 11. \masm32\bin\Link /SUBSYSTEM:WINDOWS "basicdlg.obj" rsrc.res – это компоновка исполняемого ЕХЕ-модуля из объектных файлов basicdlg.obj и rsrc.res. Результатом будет файл basicdlg.exe.
Программа, которая будет загружаться из этого ехе-файла, будет строить GUI, используя всю переданную ей ресурсную информацию и производя правильные вызовы процедур и функций WinAPI, которые и реализуют в данной ситуации сервис операционной системы.
Остается разобраться, как организуются упомянутые выше «правильные вызовы процедур и функций WinAPI».
В принципе, ничто не мешает, изучив по MSDN (Microsoft Developer’s Network – справочный ресурс по средствам программирования под Windows) всё многообразие функций WinApi, прописывать их вызовы с «нулевого уровня вложенности», т.е. прямо из asm-файла исходного текста программы. Это путь возможный, но крайне громоздкий и трудоемкий. И при этом мы игнорируем огромный труд, который проделан создателями МАСМ для облегчения этих действий и придания им прозрачности и понятности. Понятно, что отбрасывать подобное богатство просто нелепо.
Поэтому мы на простом примере посмотрим, как практически программа «дотягивается» до функций WinApi через цепочки промежуточных вызовов макросов и процедур. Для этой работы нам понадобится, кроме обычного Windows Проводника еще и доступ к MSDN. Если вам доступен интернет, то мы рекомендовали бы ресурс http://msdn.microsoft.com/ru-ru/library/ms123401, дающий доступ к русскоязычной версии MSDN.
Рассмотрим наипростейший пример в папке \MASM32\examples\dialogs\simple. Откроем в Notepad++ файл simple.asm:
; ««««««««««««««««««««««««««««««««
.486 ; create 32 bit code
.model flat, stdcall ; 32 bit memory model
option casemap :none ; case sensitive
include \masm32\include\dialogs.inc
include simple.inc
dlgproc PROTO :DWORD,:DWORD,:DWORD,:DWORD
.code
; ««««««««««««««««««««««««««««««««
start:
mov hInstance, FUNC(GetModuleHandle,NULL)
call main
invoke ExitProcess, eax
; ««««««««««««««««««««««««««««««««
main proc
Dialog "Simple Dialog","MS Sans Serif",10, \ ; caption,font,pointsize
WS_OVERLAPPED or WS_SYSMENU or DS_CENTER, \ ; style
2, \ ; control count
50,50,150,80, \ ; x y co-ordinates
1024 ; memory buffer size
DlgButton "&OK",WS_TABSTOP,48,40,50,15,IDCANCEL
DlgStatic "Simple Dialog Written In MASM32",SS_CENTER,2,20,140,9,100
CallModalDialog hInstance,0,dlgproc,NULL
ret
main endp
; ««««««««««««««««««««««««««««««««
dlgproc proc hWin:DWORD,uMsg:DWORD,wParam:DWORD,lParam:DWORD
.if uMsg == WM_INITDIALOG
invoke SendMessage,hWin,WM_SETICON,1,FUNC(LoadIcon,NULL,IDI_ASTERISK)
.elseif uMsg == WM_COMMAND
.if wParam == IDCANCEL
jmp quit_dialog
.endif
.elseif uMsg == WM_CLOSE
quit_dialog:
invoke EndDialog,hWin,0
.endif
xor eax, eax
ret
dlgproc endp
; ««««««««««««««««««««««««««««««««
end start
В тексте этой программы мы выделили полужирным имена вызываемых макросов и процедур, условно говоря, «нулевого» уровня, т.е. находящиеся в этом тексте.
Для того, чтобы разобраться с последовательными вызовами, составим их таблицу. Для нашего примера она получается такая:
Таблица 5.1 – Таблица вызовов для программы simple.asm
Тип |
Имя пр/макро |
Вызвано |
Вызвано |
Описано в |
1 |
2 |
3 |
4 |
5 |
p |
GetModuleHandle |
|
|
MSDN |
p |
ExitProcess |
|
|
MSDN |
m |
Dialog |
|
|
dialogs.inc |
p |
|
GlobalAlloc |
|
MSDN |
m |
|
ustring |
|
dialogs.inc |
p |
|
|
MultiByteToWideChar |
MSDN |
m |
DlgButton |
|
|
dialogs.inc |
m |
|
ustring – см.выше |
|
|
m |
DlgStatic |
|
|
dialogs.inc |
Продолжение таблицы 5.1
1 |
2 |
3 |
4 |
5 |
m |
|
ustring – см.выше |
|
|
m |
CallModalDialog |
|
|
dialogs.inc |
p |
|
DialogBoxIndirectParam |
|
MSDN |
p |
|
GlobalFree |
|
MSDN |
p |
SendMessage |
|
|
MSDN |
p |
|
LoadIcon |
|
MSDN |
p |
EndDialog |
|
|
MSDN |
Колонка «Тип» содержит «p» для процедур, «m» для макросов. Колонки 3 и 4 (их могло бы быть и больше, если бы цепочки вызовов были длиннее) содержат имена вызывемых макросов или процедур, последняя колонка указывает, где описан соответствующий макрос или процедура. Если процедура описана в MSDN, то она из WinAPI, дальше вызовы не прослеживаются.
Поясним, как составлялась таблица, на примере вызова макроса Dialog и далее того, что из него вызывается (отмеченная часть таблицы 5.1).
Итак, в тексте программы находим вызов
Dialog "Simple Dialog","MS Sans Serif",10, \ ; caption,font,pointsize
WS_OVERLAPPED or WS_SYSMENU or DS_CENTER, \ ; style
2, \ ; control count
50,50,150,80, \ ; x y co-ordinates
1024 ; memory buffer size
Чтобы найти его определение, открываем папку MASM32 и задаем поиск с параметрами:
Рисунок 5.1 – Поиск файла с определением макроса Dialog.
Результат поиска покажет, что этот макрос определен в файле \MASM32\include\dialogs.inc.
Открываем этот файл и читаем определение макроса:
Dialog MACRO quoted_text_title,quoted_font,fsize,dstyle,ctlcnt,tx,ty,wd,ht,bsize
push esi
push edi
invoke GlobalAlloc,GMEM_FIXED or GMEM_ZEROINIT,bsize
mov esi, eax
mov edi, esi
mov DWORD PTR [edi+0], DS_SETFONT or dstyle
mov WORD PTR [edi+8], ctlcnt
mov WORD PTR [edi+10], tx
mov WORD PTR [edi+12], ty
mov WORD PTR [edi+14], wd
mov WORD PTR [edi+16], ht
add edi, 22
ustring quoted_text_title
mov WORD PTR [edi], fsize
add edi, 2
ustring quoted_font
ENDM
Видим, что в нем макросом invoke, изученным раньше, вызывается процедура GlobalAlloc и дважды вызывается макрос ustring.
Сначала обращаемся к MSDN и поиском в ней находим подтверждение предположению, что это функция из WinAPI.
Поиском в папке MASM32 находим, что макрос ustring определен в том же файле dialogs.inc. Открываем и читаем определение этого макроса:
ustring MACRO quoted_text
LOCAL asc_txt
.data
asc_txt db quoted_text,0
.code
invoke MultiByteToWideChar,CP_ACP,MB_PRECOMPOSED,
ADDR asc_txt,-1,edi,LENGTHOF asc_txt
add edi, LENGTHOF asc_txt*2
ENDM
Видим, что из него вызывается только процедура MultiByteToWideChar, описание которой находим в MSDN. Таким образом, мы проследили цепочки всех вызовов по макросу Dialog до уровня WinAPI (процедур, описанных в MSDN). Как результат этого прослеживания можно сделать вывод, что в макросе Dialog, помимо действий, выраженных командами ассемблера, содержатся, в конечном итоге, вызовы функций GlobalAlloc() и MultiByteToWideChar().
Описанный порядок действий будет применяться при выполнении самостоятельной части данной лабораторной работы.