Практическая Работа 11-12 принципы работы кэш-памяти 


Мы поможем в написании ваших работ!



ЗНАЕТЕ ЛИ ВЫ?

Практическая Работа 11-12 принципы работы кэш-памяти



ЦЕЛЬ РАБОТЫ

Приобретение навыков работы с кэш-памятью.

Проверить работу различных алгоритмов замещения при различных режимах записи в кэш-память.

ПОРЯДОК ВЫПОЛНЕНИЯ РАБОТЫ

- Прочитать методические указания

- Разобрать приведенные примеры

- Выполнить задания к работе

- Ответить на контрольные вопросы

Оформите отчет, который должен содержать:

- титульный лист (см. приложение);

постановку задачи;

формулировка варианта задания.

размещение данных в ОЗУ.

программа

результаты выполнения программы для нескольких значений аргумента, выбранных самостоятельно.

МЕТОДИЧЕСКИЕ УКАЗАНИЯ

В качестве задания предлагается некоторая короткая "программа" (табл. 9.14), которую необходимо выполнить с подключенной кэш-памятью (размером 4 и 8 ячеек) в шаговом режиме для следующих двух вариантов алгоритмов заме­щения (табл. 9.13).

 

 

 

 

  Таблица 1. Пояснения к вариантам задания
Номера вариантов Режим записи Алгоритм замещения
1,7, 11 Сквозная СЗ, без учета бита записи
Обратная О, с учетом бита записи
2,5,9 Сквозная БИ, без учета бита записи
Обратная О, с учетом бита записи
3,6, 12 Сквозная О, без учета бита записи
Обратная СЗ, с учетом бита записи
4, 8, 10 Сквозная БИ, без учета бита записи
Обратная БИ, с учетом бита записи

Таблица 2. Варианты задания 7

 

    Номера команд программы      
вари­анта                
  RD #12 WR 10 WR §10 ADD 12 WR R0 SUB 10 PUSH R0  
  RD #65 WRR2 MOV R4,R2 WR 14 PUSH R2 POP R3 CALL 002  
  RD #16 SUB #5 WR 9 WR @9 WR R3 PUSH R3 POP R4  
  RD #99 WR R6 MOV R7,R6 ADD R7 PUSH R7 CALL 006 POP R8  
  RD #11 WR R2 WR -@R2 PUSH R2 CALL 005 POP R3 RET  
  RD #19 SUB #10 WR9 ADD #3 WR ©9 CALL 006 POPR4  
  RD #6 CALL 006 WR11 WRR2 PUSH R2 RET JMP 002
  RD#8 WRR2 WR @R2+ PUSH R2 POP R3 WR -@R3 CALL 003
  RD #13 WR14 WR@14 WR@13 ADD 13 CALL 006 RET
  RD #42 SUB #54 WR16 WR@16 WRR1 ADD @R1+ PUSH Rl
  RD #10 WRR5 ADD R5 WRR6 CALL 005 PUSH R6 RET
  JMP 006 RD #76 WR 14 WRR2 PUSH R2 RET CALL 001
                           

He следует рассматривать заданную последовательность команд как фрагмент программы1. Некоторые конструкции, например, последовательность команд push R6, ret в общем случае не возвращает программу в точку вызова подпрограммы. Такие группы команд введены в задание для того, чтобы об­ратить внимание студентов на особенности функционирования стека.

Порядок выполнения работы

Ввести в модель учебной ЭВМ текст своего варианта программы (см. табл. 2), ассемблировать его и сохранить на диске в виде txt-файла.

Установить параметры кэш-памяти размером 4 ячейки, выбрать режим записи и алгоритм замещения в соответствии с первой строкой своего варианта из табл. 9.13.

В шаговом режиме выполнить программу, фиксируя после каждого шага состояние кэш-памяти.

Для одной из команд записи (WR) перейти в режим Такт и отметить, в каких микрокомандах происходит изменение кэш-памяти.

Для кэш-памяти размером 8 ячеек установить параметры в соответствии со второй строкой своего варианта из табл. 9.13 и выполнить программу в шаговом режиме еще раз, фиксируя последовательность номеров замещаемых ячеек кэш-памяти.

Напомним, что программа определяется как последовательность команд, выполнение кото­рых позволит получить некий результат.

Содержание отчета

Вариант задания — текст программы и режимы кэш-памяти.

Последовательность состояний кэш-памяти размером 4 ячейки при однократном выполнении программы (команды 1—7).

Последовательность микрокоманд при выполнении команды wr с отметкой тех микрокоманд, в которых возможна модификация кэш-памяти.

Для варианта кэш-памяти размером 8 ячеек — последовательность номеров замещаемых ячеек кэш-памяти для второго варианта параметров кэш памяти при двукратном выполнении программы (команды 1—7).

9.7.4. Контрольные вопросы

В чем смысл включения кэш-памяти в состав ЭВМ?

Как работает кэш-память в режиме обратной записи? Сквозной записи?

Как зависит эффективность работы ЭВМ от размера кэш-памяти?

В какую ячейку кэш-памяти будет помещаться очередное слово, если свободные ячейки отсутствуют?

Какие алгоритмы замещения ячеек кэш-памяти вам известны?

Тема: АЛГОРИТМЫ ЗАМЕЩЕНИЯ СТРОК КЭШ-ПАМЯТИ

Цель: изучение влияния параметров кэш-памяти и выбранного алгоритма замещения на эффективность работы системы. Эффективность в данном случае оценивается числом кэш-попаданий по отношению к общему числу обращений к памяти. Учитывая разницу в алгоритмах в режимах сквозной и обратной записи, эффективность использования кэш-памяти вычисляется выражениям (8.2) и (8.3) соответственно для сквозной и обратной записи.

Очевидно, эффективность работы системы с кэш-памятью будет зависеть не только от параметров кэш-памяти и выбранного алгоритма замещения, но и от класса решаемой задачи. Так, линейные программы должны хорошо ра­ботать с алгоритмами замещения типа очередь, а программы с большим чис­лом условных переходов, зависящих от случайных входных данных, могут да­вать неплохие результаты с алгоритмами случайного замещения. Можно предположить, что программы, имеющие большое число повторяющихся уча­стков (часто вызываемых подпрограмм и/или циклов) при прочих равных ус­ловиях обеспечат более высокую эффективность применения кэш-памяти чем линейные программы. И, разумеется, на эффективность напрямую дол­жен влиять размер кэш-памяти.

Для проверки высказанных выше предположений выполняется настоящая лабораторная работа.

Задание

В данной лабораторной работе все варианты задания одинаковы: исследовать эффективность работы кэш-памяти при выполнении двух разнотипных про­грамм, написанных и отлаженных вами при выполнении лабораторных работ № 2 и 4.

Порядок выполнения работы

Загрузить в модель учебной ЭВМ отлаженную программу из лабораторной работы № 2.

В меню Работа установить режим Кэш-память.

В меню Вид выбрать команду Кэш-память, открыв тем самым окно Кэш­память, в нем нажать первую слева кнопку на панели инструментов, открыв диалоговое окно Параметры кэш-памяти, и установить следующие параметры кэш-памяти: размер — 4, режим записи — сквозная, алгоритм замещения — случайное, без учета бита записи (W).

Запустить программу в автоматическом режиме; по окончании работы просмотреть результаты работы кэш-памяти в окне Кэш-память, вычислить значение коэффициента эффективности К и записать в ячейку табл. 9.15, помеченную звездочкой.

Выключить кэш-память модели (Работа | Кэш-память) и изменить один из ее параметров — установить флаг с учетом бита записи (в окне Параметры кэш-памяти).

Повторить п. 4, поместив значение полученного коэффициента эффективности в следующую справа ячейку табл. 9.15.

Последовательно меняя параметры кэш-памяти, повторить пп. 3—5, заполняя все ячейки табл. 9.15.

Совет_______________________________________________________

При очередном запуске программы не забывайте устанавливать про­цессор модели в начальное состояние, нажимая кнопку R в окне Процессор!

Повторить все действия, описанные в пп. 1—7 для программы из лабораторной работы № 4, заполняя вторую таблицу по форме табл. 9.15

Содержание отчета

Две таблицы по форме табл. 9.15 с результатами моделирования программ из лабораторных работ № 2 и 4 при разных режимах работы кэш-памяти.

Выводы, объясняющие полученные результаты.

9.8.4. Контрольные вопросы

Как работает алгоритм замещения очередь при установленном флажке С учетом бита записи в диалоговом окне Параметры кэш-памяти?

Какой алгоритм замещения будет наиболее эффективным в случае применения кэш-памяти большого объема (в кэш-память целиком помещается программа)?

Как скажется на эффективности алгоритмов замещения учет значения бита записи W при работе кэш-памяти в режиме обратной записи? Сквозной записи?

Для каких целей в структуру ячейки кэш-памяти включен бит использования. Как устанавливается и сбрасывается этот бит?

Таблица 3. Результаты эксперимента

 

Способ Сквозная запись
Алгоритм Случайное замещение Очередь Бит U
Размер безАУ cW 6e3\V cW без\У cW
  *          
             
             
             
             
             
             

 


 

Практическая работа №14-15 FASM (Flat Assembler).

ЦЕЛЬ РАБОТЫ

Приобретение навыков работы в FASM (Ассемблер)

ПОРЯДОК ВЫПОЛНЕНИЯ РАБОТЫ

Прочитать задания к работе

Оформите отчет, который должен содержать:

-титульный лист (см. приложение);

-постановку задачи;

- описание пошагового исполнения;

- отчет о полученном результате

МЕТОДИЧЕСКИЕ УКАЗАНИЯ

FASM (Flat Assembler). Этот компилятор достаточно прост в установке и использовании, отличается компактностью и быстротой работы, имеет богатый и емкий макросинтаксис, позволяющий автоматизировать множество рутинных задач. Его последнюю версию вы можете скачать по адресу: сайт выбрав flat assembler for Windows. Чтобы установить FASM, создайте папку, например, "D:\FASM" и в нее распакуйте содержимое скачанного zip-архива. Запустите FASMW.EXE и закройте, ничего не изменяя. Кстати, если вы пользуетесь стандартным проводником, и у вас не отображается расширение файла (например,.EXE), рекомендую выполнить Сервис -> Свойства папки -> Вид и снять птичку с пункта Скрывать расширения для зарегистрированных типов файлов. После первого запуска компилятора в нашей папке должен появиться файл конфигурации — FASMW.INI. Откройте его при помощи стандартного блокнота и допишите в самом низу 3 строчки:
[Environment]
Fasminc=D:\FASM\INCLUDE

Include=D:\FASM\INCLUDE

Если вы распаковали FASM в другое место — замените "D:\FASM\" на свой путь. Сохраните и закройте FASMW.INI. Забегая вперед, вкратце объясню, как мы будем пользоваться компилятором:
1. Пишем текст программы, или открываем ранее написанный текст, сохраненный в файле.asm, или вставляем текст программы из буфера обмена комбинацией.
2. Жмем F9, чтобы скомпилировать и запустить программу, или Ctrl+F9, чтобы только скомпилировать. Если текст программы еще не сохранен — компилятор попросит сохранить его перед компиляцией.
3. Если программа запустилась, тестируем ее на правильность работы, если нет — ищем ошибки, на самые грубые из которых компилятор нам укажет или тонко намекнет.
Ну, а теперь мы можем приступить к долгожданной практике. Запускаем наш FASMW.EXE и набираем в нем код нашей первой программы:

include '%fasminc%/win32ax.inc'

.data
Caption db 'Моя первая программа.',0
Text db 'Всем привет!',0

.code
start:
invoke MessageBox,0,Text,Caption,MB_OK

invoke ExitProcess,0

.end start

Жмем Run -> Run, или F9 на клавиатуре. В окне сохранения указываем имя файла и папку для сохранения. Желательно привыкнуть сохранять каждую программу в отдельную папку, чтобы не путаться в будущем, когда при каждой программе может оказаться куча файлов: картинки, иконки, музыка и прочее. Если компилятор выдал ошибку, внимательно перепроверьте указанную им строку — может, запятую пропустили или пробел. Также необходимо знать, что компилятор чувствителен к регистру, поэтому.data и.Data воспринимаются как две разные инструкции. Если же вы все правильно сделали, то результатом будет простейший MessageBox (рис. 1). Теперь давайте разбираться, что же мы написали в тексте программы. В первой строке директивой include мы включили в нашу программу большой текст из нескольких файлов. Помните, при установке мы прописывали в фасмовский ини-файл 3 строчки? Теперь %fasminc% в тексте программы означает D:\FASM\INCLUDE или тот путь, который указали вы. Директива include как бы вставляет в указанное место текст из другого файла. Откройте файл WIN32AX.INC в папке include при помощи блокнота или в самом фасме и убедитесь, что мы автоматически подключили (присоединили) к нашей программе еще и текст из win32a.inc, macro/if.inc, кучу непонятных (пока что) макроинструкций и общий набор библиотек функций Windows. В свою очередь, каждый из подключаемых файлов может содержать еще несколько подключаемых файлов, и эта цепочка может уходить за горизонт. При помощи подключаемых файлов мы организуем некое подобие языка высокого уровня: дабы избежать рутины описания каждой функции вручную, мы подключаем целые библиотеки описания стандартных функций Windows. Неужели все это необходимо такой маленькой программе? Нет, это — что-то вроде "джентльменского набора на все случаи жизни". Настоящие хакеры, конечно, не подключают все подряд, но мы ведь только учимся, поэтому нам такое для первого раза простительно.

Далее у нас обозначена секция данных —.data. В этой секции мы объявляем две переменные — Caption и Text. Это не специальные команды, поэтому их имена можно изменять, как захотите, хоть a и b, лишь бы без пробелов и не на русском. Ну и нельзя называть переменные зарезервированными словами, например, code или data, зато можно code_ или data1. Команда db означает "определить байт" (define byte). Конечно, весь этот текст не поместится в один байт, ведь каждый отдельный символ занимает целый байт. Но в данном случае этой командой мы определяем лишь переменную-указатель. Она будет содержать адрес, в котором хранится первый символ строки. В кавычках указывается текст строки, причем кавычки по желанию можно ставить и 'такие', и "такие" — лишь бы начальная кавычка была такая же, как и конечная. Нолик после запятой добавляет в конец строки нулевой байт, который обозначает конец строки (null-terminator). Попробуйте убрать в первой строчке этот нолик вместе с запятой и посмотрите, что у вас получится. Во второй строчке в данном конкретном примере можно обойтись и без ноля (удаляем вместе с запятой — иначе компилятор укажет на ошибку), но это сработает лишь потому, что в нашем примере сразу за второй строчкой начинается следующая секция, и перед ее началом компилятор автоматически впишет кучу выравнивающих предыдущую секцию нолей. В общих случаях ноли в конце текстовых строк обязательны! Следующая секция — секция исполняемого кода программы —.code. В начале секции стоит метка start:. Она означает, что именно с этого места начнет исполняться наша программа. Первая команда — это макроинструкция invoke. Она вызывает встроенную в Windows API-функцию MessageBox. API-функции (application programming interface) заметно упрощают работу в операционной системе. Мы как бы просим операционную систему выполнить какое-то стандартное действие, а она выполняет и по окончании возвращает нам результат проделанной работы. После имени функции через запятую следуют ее параметры. У функции MessageBox параметры такие:

1-й параметр должен содержать хэндл окна-владельца. Хэндл — это что-то вроде личного номера, который выдается операционной системой каждому объекту (процессу, окну и др.). 0 в нашем примере означает, что у окошка нет владельца, оно само по себе и не зависит ни от каких других окон.
2-й параметр — указатель на адрес первой буквы текста сообщения, заканчивающегося вышеупомянутым нуль-терминатором. Чтобы наглядно понять, что это всего лишь адрес, сместим этот адрес на 2 байта прямо в вызове функции: invoke MessageBox,0,Text+2,Caption,MB_OK и убедимся, что теперь текст будет выводиться без первых двух букв.
3-й — указатель адреса первой буквы заголовка сообщения.
4-й — стиль сообщения. Со списком этих стилей вы можете ознакомиться, например, в INCLUDE\EQUATES\ USER32.INC. Для этого вам лучше будет воспользоваться поиском в Блокноте, чтобы быстро найти MB_OK и остальные. Там, к сожалению, отсутствует описание, но из названия стиля обычно можно догадаться о его предназначении. Кстати, все эти стили можно заменить числом, означающим тот, иной, стиль или их совокупность, например: MB_OK + MB_ICONEXCLAMATION. В USER32.INC указаны шестнадцатеричные значения. Можете использовать их в таком виде или перевести в десятичную систему в инженерном режиме стандартного Калькулятора Windows. Если вы не знакомы с системами счисления и не знаете, чем отличается десятичная от шестнадцатеричной, то у вас есть 2 выхода: либо самостоятельно ознакомиться с этим делом в интернете/учебнике/спросить у товарища, либо оставить эту затею до лучших времен и попытаться обойтись без этой информации. Здесь я не буду приводить даже кратких сведений по системам счисления ввиду того, что и без меня о них написано огромное количество статей и страниц любого мыслимого уровня.

Вернемся к нашим баранам. Некоторые стили не могут использоваться одновременно — например, MB_OKCANCEL и MB_YESNO. Причина в том, что сумма их числовых значений (1+4=5) будет соответствовать значению другого стиля — MB_RETRYCANCEL. Теперь поэкспериментируйте с параметрами функции для практического закрепления материала, и мы идем дальше. Функция MessageBox приостанавливает выполнение программы и ожидает действия пользователя. По завершении функция возвращает программе результат действия пользователя, и программа продолжает выполняться. Вызов функции ExitProcess завершает процесс нашей программы. Эта функция имеет лишь один параметр — код завершения. Обычно, если программа нормально завершает свою работу, этот код равен нулю. Чтобы лучше понять последнюю строку нашего кода —.end start, — внимательно изучите эквивалентный код:

format PE GUI 4.0
include '%fasminc%/win32a.inc'
entry start
section '.data' data readable writeable
Caption db 'Наша первая программа.',0
Text db 'Ассемблер на FASM — это просто!',0
section '.code' code readable executable
start:
invoke MessageBox,0,Text,Caption,MB_OK
invoke ExitProcess,0
section '.idata' import data readable writeable

library KERNEL32, 'KERNEL32.DLL',\
USER32, 'USER32.DLL'

import KERNEL32,\
ExitProcess, 'ExitProcess'

import USER32,\
MessageBox, 'MessageBoxA'

Для компилятора он практически идентичен предыдущему примеру, но для нас этот текст выглядит уже другой программой. Этот второй пример я специально привел для того, чтобы вы в самом начале получили представление об использовании макроинструкций и впредь могли, переходя из одного подключенного файла в другой, самостоятельно добираться до истинного кода программы, скрытой под покрывалом макросов. Попробуем разобраться в отличиях. Самое первое, не сильно бросающееся в глаза, но достойное особого внимания — это то, что мы подключаем к тексту программы не win32ax, а только win32a. Мы отказались от большого набора и ограничиваемся малым. Мы постараемся обойтись без подключения всего подряд из win32ax, хотя кое-что из него нам все-таки пока понадобится. Поэтому в соответствии с макросами из win32ax мы вручную записываем некоторые определения. Например, макрос из файла win32ax:
macro.data { section '.data' data readable writeable }

во время компиляции автоматически заменяет.data на section '.data' data readable writeable. Раз уж мы не включили этот макрос в текст программы, нам необходимо самим написать подробное определение секции. По аналогии вы можете найти причины остальных видоизменений текста программы во втором примере. Макросы помогают избежать рутины при написании больших программ. Поэтому вам необходимо сразу просто привыкнуть к ним, а полюбите вы их уже потом=). Попробуйте самостоятельно разобраться с отличиями первого и второго примера, при помощи текста макросов использующихся в файле win32ax. Скажу еще лишь, что в кавычках можно указать любое другое название секции данных или кода — например: section 'virus' code readable executable. Это просто название секции, и оно не является командой или оператором. Если вы все уяснили, то вы уже можете написать собственный вирус. Поверьте, это очень легко. Просто измените заголовок и текст сообщения:
Caption db 'Опасный Вирус.',0

Text db 'Здравствуйте, я — особо опасный вирус-троян и распространяюсь по интернету.',13,\
'Поскольку мой автор не умеет писать вирусы, приносящие вред, вы должны мне помочь.',13,\
'Сделайте, пожалуйста, следующее:',13,\
'1.Сотрите у себя на диске каталоги C:\Windows и C:\Program files',13,\
'2.Отправьте этот файл всем своим знакомым',13,\
'Заранее благодарен.',0

Число 13 — это код символа "возврат каретки" в майкрософтовских системах. Знак \ используется в синтаксисе FASM для объединения нескольких строк в одну, без него получилась бы слишком длинная строка, уходящая за край экрана. К примеру, мы можем написать start:, а можем — и st\
ar\
t:

Компилятор не заметит разницы между первым и вторым вариантом.
Ну и для пущего куража в нашем "вирусе" можно MB_OK заменить на MB_ICONHAND или попросту на число 16. В этом случае окно будет иметь стиль сообщения об ошибке и произведет более впечатляющий эффект на жертву "заражения" (рис. 2).

Вот и все на сегодня. Желаю вам успехов и до новых встреч!
Все приводимые примеры были протестированы на правильность работы под Windows XP и, скорее всего, будут работать под другими версиями Windows, однако я не даю никаких гарантий их правильной работы на вашем компьютере

В прошлый раз мы познакомились с компилятором FASM для Windows — рассмотрели основы его синтаксиса и написали нашу первую программу. Самые любопытные уже, наверное, заглянули в папку EXAMPLES и обнаружили там с дюжину готовых примеров различного уровня сложности. Если вы еще не сделали этого — быстренько открывайте..\FASM\EXAMPLES\ и изучайте — даю вам 5 минут на это! Время пошло.

Ну что же, теперь мы можем приступать к очередной тренировке ввода с клавиатуры букв, цифр и знаков препинания. Ленивые могут скопировать исходный код из этой статьи. Помните анекдот про подставку для кофе? Когда секретарша звонит сисадмину и сообщает, что на ее компьютере сломалась подставка для кофе. Админ, не раздумывая, набирает другой номер и говорит: "Петрович, у секрятаря CD-ROM накрылся, надо заменить". Вот мы сейчас и оформим программку управления подставкой для кофе. За основу взят пример, идущий в комплекте с виндовской версией фасма.

format PE GUI 4.0

include 'win32a.inc'

; секции не обозначены, поэтому fasm автоматически создаст секцию.flat
; в которой разместятся и код, и данные, что позволит уменьшить размер файла

invokeMessageBoxA,0,_message,_caption,MB_ICONQUESTION+MB_YESNOCANCEL
cmpeax,IDNO
jeclose
cmpeax,IDYES
jneexit

;open:
invokemciSendString,_cd_open,0,0,0
jmpexit

close:
invokemciSendString,_cd_close,0,0,0

exit:
invokeExitProcess,0

_message db 'Вам нужна подставка для кофе?',0
_caption db 'Мастер Бытового Обслуживания.',0

_cd_open db 'set cdaudio door open',0
_cd_close db 'set cdaudio door closed',0

; импортируемые данные разместятся в этой же секции:

data import

library kernel32,'KERNEL32.DLL',\
user32,'USER32.DLL',\
winmm,'WINMM.DLL'

import kernel32,\
ExitProcess,'ExitProcess'

import user32,\
MessageBoxA,'MessageBoxA'

import winmm,\
mciSendString,'mciSendStringA'

end data

Вот такое окошко должно у нас получиться. Нажмете кнопку "Да" — лоток CD-ROM'а откроется. Нажмете "Нет" — закроется. А сейчас — традиционное разбирательство по вопросу "Как Это Работает":
Символ "точка с запятой" (;) означает, что в строке или в оставшейся ее части размещен комментарий. Когда компилятор встречает этот символ, то игнорирует текст, идущий после точки с запятой, и переходит к обработке следующей строки. Исключением из этого правила является точка с запятой, заключенная в кавычки. Старайтесь всегда вносить в код пояснения — в будущем это поможет вам не запутаться в собственных программах и упростит понимание ваших текстов другими людьми. Как вы могли понять из комментария, в этом примере секция кода и данных будет скомпилирована в одну секцию. В нашем случае это положительно скажется на размере исполняемого файла, точнее, отрицательно — короче, размер файла будет меньше. Каждая отдельная секция файла для ускорения доступа к ней операционной системы округляется до 512 байт. Даже если секция будет содержать лишь пару байт данных или кода, компилятор все равно допишет недостающее число нулевых байт. Значит, если у нас совсем немного кода и данных, мы можем разместить их в одной универсальной секции для уменьшения размера получаемого файла. Зачем вообще нужны эти секции? Ну, типа для повышения надежности и безопасности программного обеспечения. Каждая секция при запуске программы получает свой набор прав. Обычно секция данных может быть прочитана и записана, но не может быть исполнена, а секция кода имеет разрешение на исполнение, но не может быть перезаписана. Но это все формальности. При желании можно найти и способы изменения исполняемого кода, и исполнения команд прямо из секции данных. Однако не будем забегать слишком далеко вперед и продолжим разбор нового материала.
Что такое invoke MessageBox, вы знаете из предыдущего занятия. Однако здесь вы видите MessageBoxA. Не бойтесь, это ведь та же самая API-функция. Просто в тот раз мы импортировали ее командой import USER32,MessageBox,'MessageBoxA', а теперь — командой import user32,MessageBoxA,'MessageBoxA'. Название импортируемой функции, заключенное в кавычки, должно быть точным: оно будет передано операционной системе в момент запуска программы для получения адреса функции. А вот псевдоним, стоящий через запятую перед именем функции, может отличаться от имени — например: import USER32, Box, 'MessageBoxA'. Только в таком случае вы усложните понимание кода себе и другим людям. Так что не принимайте это за сигнал к действию, а просто имейте в виду, что псевдоним и реальное имя функции могут иногда различаться. Зачем же я изменил псевдоним этой функции и заострил на этом ваше внимание? Дело в том, что, читая код программ, написанных другими людьми, вы можете встретить как первый, так и второй вариант. А в редких случаях и третий, и еще какой-нибудь четвертый. Вообще функции Windows, работающие с текстовыми строками, бывают двух типов: A (кодировка ANSI) и W (кодировка Юникод). Мы в основном будем работать с кодировкой ANSI, но вам следует знать, что у каждой API-функции, использующей текст ANSI, есть брат-близнец для кодировки Unicode. Итак, вызов функции MessageBox выводит окно с сообщением и приостанавливает работу программы, ожидая реакцию пользователя. По завершении функция возвращает программе код нажатой пользователем кнопки или возвращает 0, если не хватило памяти для создания окна с сообщением. Возвращаемые значения могут быть следующими:

 

Псевдоним Значение Нажатая кнопка
IDOK   OK
IDCANCEL   Отмена (Cancel)
IDABORT   Прервать (Abort)
IDRETRY   Повтор (Retry)
IDIGNORE   Пропустить (Ignore)
IDYES   Да (Yes)
IDNO   Нет (No)

)

Так как же нам узнать, какая кнопка была нажата? Где найти это "возвращаемое значение", и под каким соусом его подавать на стол? Будем разбираться. В процессоре существуют ячейки высокоскоростной памяти, которые физически находятся вблизи его ядра. Эти ячейки называются регистрами. Если вы уже сейчас захотите узнать об этих регистрах более подробно, воспользуйтесь поиском в интернет (ключевые слова: регистры процессора). Однако на данный момент вам может хватить и приведенной здесь информации о регистрах. Основных регистров пользователя всего четыре: EAX(Accumulator), EBX(Base), ECX(Count), EDX(Data). Каждый из них имеет размер 4 байта (32 бита) и может использоваться в вычислениях целиком или частично. Например, можно обратиться к целому регистру EAX, можно работать с его младшей половинкой AX и даже с четвертинками AH и AL. Нельзя напрямую отдельно обратиться к старшей половинке регистра EAX, поэтому у нее нет собственного имени.

 

EAX (4 байта)    
  AX (2 байта)  
  AH(1) AL(1)

 

Аналогично устроены и регистры EBX, ECX, EDX, а их части называются соответственно BX/BH/BL, CX/CH/CL, DX/DH/DL. Существуют и другие регистры процессора, но мы будем говорить о них по ходу их появления в наших примерах. Большинство функций Windows возвращают результаты своих действий в регистр процессора EAX. Функция MessageBox поступает так же: после того, как пользователь нажмет на кнопку в окне с сообщением, она поместит в регистр EAX числовое значение нажатой кнопки. Теперь нам надо в зависимости от полученного значения выполнить то или иное действие. Для этого мы будем использовать команду сравнения (CMP) и команды условного перехода (JE и JNE).
CMP — сокращение от Compare (Сравнить). Синтаксис этой команды: [CMP приемник, источник]. Она сравнивает два числа, вычитая источник из приемника, не изменяя их содержимое.

JE — Jump if Equal (Переход, если равно). JNE — Jump if Not Equal (Переход, если не равно). Это команды-антонимы — они противоположны по значению. Синтаксис JE, JNE и других команд перехода такой: [JE метка]. Команды условного перехода используются после команд CMP и SUB (вычитание с сохранением результата в приемник). Переход на метку осуществляется только если соблюдено условие перехода. Если условие не соблюдено, то программа продолжает выполняться в обычном порядке. Команда JMP (Jump) является командой безусловного перехода, то есть переход на указанную метку осуществляется в любом случае. В нашей программе мы сначала сравниваем содержимое eax и IDNO (эквивалент числа 7) и переходим на метку close, если они равны (JE). Иначе — сравниваем eax и IDYES (эквивалент числа 6) и переходим на метку exit, если они не равны (JNE). По этой логике программа выполнит строки

invoke mciSendString,_cd_open,0,0,0
jmp exit

только при условии, что содержимое eax после функции MessageBox будет равно IDYES. Если eax=IDNO, то выполняются команды после метки close включая команды после метки exit. Если результат не равен ни IDYES, ни IDNO, то выполняется вызов функции завершения работы программы: invoke ExitProcess,0. API-функция mciSendString отправляет командную строку устройству MCI (Media Control Interface). Устройство, которому отправляется команда, должно быть определено в командной строке. У функции четыре параметра: указатель на командную строку, указатель на буфер для ответа, размер буфера для ответа (количество символов), хэндл окна, которому отправляется напоминание при ответе (для этого в командной строке должен присутствовать параметр notify). В нашем случае мы обойдемся без получения ответов от устройства, поэтому вместо последних трех параметров ставим нолики. А вот первый параметр — это целый раздел в интернет-библиотеке мелкомягких (MSDN), поэтому я приведу вам лишь общую информацию о командных строках мультимедиа. Если вы знаете английский, то можете ознакомиться с полной версией описания этих команд по адресу: сайт Командная строка MCI состоит из трех основных частей: команда, устройство, параметры. Эти части должны разделяться пробелами. Команда в нашем конкретном случае — это set. Бывают команды open, play, close и другие. Устройство у нас — cdaudio. Устройством также может являться полное имя файла, псевдоним, установленный параметром alias предшествующей команды open, слово new в команде open при открытии устройства на запись, слово all — для отправки команды всем открытым в программе устройствам. Параметры разделяются пробелами, перечисляются в произвольном порядке и могут вообще отсутствовать в некоторых командах. Теперь мы можем добавить к нашей сегодняшней программе звуковое сопровождение. Для этого необходимо дописать строку

invoke mciSendString,_wav_play,0,0,0
прямо перед вызовом функции MessageBox и строку
_wav_play db 'play c:\windows\media\tada.wav',0

 

где-нибудь после вызова функции ExitProcess, но перед импортом данных. Если у вас папка с windows находится в другом месте — укажите свой путь. Можете вообще указать путь к другому wav-файлу или даже попробовать другие форматы: все зависит от кодеков, установленных в вашей windows. На моей системе прокатило даже воспроизведение видео! Подобным образом вы можете озвучить открытие и закрытие лотка дискового привода. Только имейте в виду, что, если программа завершит работу раньше, чем закончится выбранный вами звук, то воспроизведение прервется тоже. Например, если поставить строку с командой воспроизведения прямо перед выходом из программы (ну перед invoke ExitProcess), то вы вообще не услышите никакого звука. Он попросту не успеет начаться, когда ему уже пора будет заканчиваться. Для такого случая предусмотрен параметр wait. Если в командной строке мультимедиа указан этот параметр, то MCI вернет управление программе только после полного исполнения команды. Будьте осторожны: если звук будет слишком длинный, вы рискуете надолго "подвесить" вашу программу в ожидании окончания воспроизведения. Пример строки с использованием параметра wait:
_wav_play db 'play c:\windows\media\tada.wav wait',0

Ну, а теперь переделаем нашу программку в полезную утилиту. Программа будет проверять статус лотка CD-ROM'а (открыт/закрыт) и изменять его на противоположный. В таком случае мы сможем вывести на рабочий стол ярлык для нашей программы, выбрать для него какой-нибудь подходящий значок (в свойствах ярлыка) и использовать его почти как кнопку "открыть/закрыть" на самом приводе:

format PE GUI 4.0

include 'win32a.inc'

invoke mciSendString,_cd_state,_ret,5,0
invoke lstrcmp,_ret,_ret_open

cmp eax,0
je close
;open:
invoke mciSendString,_cd_open,0,0,0
jmp exit

close:
invoke mciSendString,_cd_close,0,0,0
exit:
invoke ExitProcess,0

_cd_state db 'status cdaudio mode',0
_cd_open db 'set cdaudio door open',0
_cd_close db 'set cdaudio door closed',0
_ret_open db 'open',0
_ret db 5 dup (?)

data import

library kernel32,'KERNEL32.DLL',\
user32,'USER32.DLL',\
winmm,'WINMM.DLL'

import kernel32,\
ExitProcess,'ExitProcess',\
GetWindowsDirectory,'GetWindowsDirectory',\
lstrcmp,'lstrcmpA'

import user32,\
MessageBoxA,'MessageBoxA'

import winmm,\
mciSendString,'mciSendStringA',\
PlaySound,'PlaySoundA'
end data

В самом начале мы отправляем запрос о состоянии устройства cdaudio, поэтому указываем буфер для ответа и его размер. API-функция lstrcmp используется для посимвольного сравнения двух текстовых строк. Если строки одинаковые, она возвращает значение ноль. _ret_open — это указатель на строку-образец из пяти символов (нуль-терминатор на конце строки тоже считается). _ret — это указатель на пустой буфер из 5 байт. Только к моменту сравнения он уже не будет пустым: после вызова mciSendString в буфер будет помещено 5 символов из ответа о текущем состоянии CD-ROM'а — точнее, 4 буквы и завершающий строку нолик. Для слова open нам вполне хватит четырех букв, если же ответ будет другой и займет больше символов, нас это не волнует: не open — значит, открываем. Поэтому, если строки равны, и в eax находится ноль, мы переходим на метку close. Иначе — открываем лоток и проходим к выходу.



Поделиться:


Последнее изменение этой страницы: 2016-07-14; просмотров: 1292; Нарушение авторского права страницы; Мы поможем в написании вашей работы!

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 3.142.171.180 (0.088 с.)