
Микропроцессоры
.pdf
∙ директива IFE аналогично директиве IF анализирует значениелогического_выражения. Но теперь для включенияфрагмент_программы_1 в объектный модуль требуется, чтобылогическое_выражение имело значение “ ложь”.
Директивы IF и IFE очень удобно использовать при необходимости изменения текста программы в зависимости от некоторых условий.
Директивы IFDEF и IFNDEF
Синтаксис этих директив следующий:
IF(N)DEF символическое_имя фрагмент_программы_1
ELSE
фрагмент_программы_2 ENDIF
Директивы IFB и IFNB
Синтаксис этих директив следующий:
IF(N)B аргумент фрагмент_программы_1
ELSE
фрагмент_программы_2 ENDIF
Директивы IFIDN, IFIDNI, IFDIF и IFDIFI
Эти директивы позволяют не просто проверить наличие или значение аргументов макрокоманды, но и выполнить идентификацию аргументов как строк символов.
Синтаксис этих директив:
IFIDN(I) аргумент_1,аргумент_2 |
фрагмент_программы_1 |
ELSE |
фрагмент_программы_2 |
ENDIF |
IFDIF(I) аргумент_1,аргумент_2 |
фрагмент_программы_1 |
ELSE |
фрагмент_программы_2 |
ENDIF |
Директивы генерации ошибок
В языке TASM есть ряд директив, называемых директивами генерации пользовательской ошибки. Их можно рассматривать и как самостоятельное средство, и как метод, расширяющий возможности директив условной компиляции. Они предназначены для обнаружения различных ошибок в программе, таких как неопределенные метки или пропуск параметров макроса.
Директивы генерации пользовательской ошибки по принципу работы можно разделить на два типа:
∙безусловные директивы, генерирующие ошибку трансляции без проверки каких-либо условий;
∙условные директивы, генерирующие ошибку трансляции после проверки определенных условий. Большинство директив генерации ошибок имеют два обозначения, хотя принцип их работы одинаков. Второе название отражает их сходство с директивами условной компиляции. При дальнейшем обсуждении такие парные директивы будут приводиться в скобках.
Безусловная генерация пользовательской ошибки
К безусловным директивам генерации пользовательской ошибки относится только одна директива — это ERR (.ERR).
Данная директива, будучи вставлена в текст программы, безусловно приводит к генерации ошибки на этапе трансляции и удалению объектного модуля. Она очень эффективна при ее использовании с директивами условной компиляции или в теле макрокоманды с целью отладки.
Условная генерация пользовательской ошибки
Набор условий, на которые реагируют директивы условной генерации пользовательской ошибки, такой же,
как и у директив условной компиляции. Поэтому и количество этих директив такое же. К их числу относятся следующие директивы:
∙.ERRB (ERRIFB) и .ERRNB (ERRIFNB)
∙.ERRDEF (ERRIFDEF) и .ERRNDEF (ERRIFNDEF)
∙.ERRDIF (ERRIFDIF) и .ERRIDN (ERRIFIDN)
∙.ERRE (ERRIFE) и .ERRNZ (ERRIF)
Заметим только, что как и директивы условной компиляции, использовать большинство директив условной генерации пользовательской ошибки можно как в макроопределениях, так и в любом месте программы.
47. АССЕМБЛЕР И ЯЗЫКИ ВЫСОКОГО УРОВНЯ.
Существуют следующие формы комбинирования программ на языках высокого уровня с ассемблером:
Использование ассемблерных вставок (встроенный ассемблер, режимinline). Ассемблерные коды в виде команд ассемблера вставляются в текст программы на языке высокого уровня. Компилятор языка распознает их как команды ассемблера и без изменений включает в формируемый им объектный код. Эта форма удобна, если надо вставить небольшой фрагмент.
Использование внешних процедур и функций. Это более универсальная форма комбинирования. У нее есть ряд преимуществ:
- написание и отладку программ можно производить независимо; - написанные подпрограммы можно использовать в других проектах; - облегчаются модификация и сопровождение подпрограмм.
Встроенный ассемблер
При написании ассемблерных вставок используется следующий синтаксис: _asm КодОперации операнды ; // комментарии
КодОперации задает команду ассемблера, операнды – это операнды команды.
В конце записывается ;, как и в любой команде языка Си. Комментарии записываются в той форме, которая принята для языка Си.
Если требуется в текст программы на языке Си вставить несколько идущих подряд команд ассемблера, то их объединяют в блок:
_asm
{
текст программы на ассемблере ; комментарии
}
Внутри блока текст программы пишется с использованием синтаксиса ассемблера, при необходимости можно использовать метки и идентификаторы. Комментарии в этом случае можно записывать как после ;, так и после
//.
Использование внешних процедур
Для связи посредством внешних процедур в общем случае возможны два варианта вызова:
программа на языке высокого уровня вызывает процедуру на языке ассемблера;
программа на языке ассемблера вызывает процедуру на языке высокого уровня.
48.ИНТЕРФЕЙС С ЯЗЫКАМИ ВЫСОКОГО УРОВНЯ.
Наиболее общим использованием языка Ассемблер в настоящее время является применение его в качестве приложения к языку программирования высокого уровня. При разработке программы, как правило, обычно используют язык высокого уровня и лишь небольшую часть модулей пишут на языке Ассемблер. Язык Ассемблер используется тогда, когда критичны скорость работы программы или ее размер, или когда язык высокого уровня не обеспечивает доступ к полным возможностям или к аппаратным средствам.
Имеется три главных области, относящихся к связи программ на языке Ассемблер с программами на языке высокого уровня. Это - согласование имен между двумя модулями; обработка любых специальных установок, которые могут требовать язык программирования и компилятор языка; настройка модулей языка Ассемблер для надлежащей последовательности вызова и инструмента передачи параметров, используемых компилятором конкретного языка высокого уровня.
В прошлом, для языков высокого уровня было достаточно мало правил регулировки соглашений о присвоении имен и последовательностей вызова. Сегодня ситуация во многом изменилась, т.к. многие компиляторы следуют стандартам Американского национального института стандартов (ANSI). В связи с широким использованием компиляторов языков высокого уровня фирмы "Майкрософт" и в связи с тем, что они придерживаются стандартов ANSI, оказалось возможным выбрать компиляторы фирмы "Майкрософт" с языков программирования: Бэйсик, Си, Фортран и Паскаль для иллюстрации соглашений вызова подпрограмм.
Соглашения о связях для языка Си фирмы "Майкрософт"
Соглашения о связях, проиллюстрированные в листинге 2-8, представляют типичную программу на языке программирования Си. Если бы программу Example перетранслировать на язык Си, то ее начальные предложения были бы похожи на следующие:
void Example (Param1, Param2, Param3) int Param1, Param2, Param3 ;
{
int LocIndx ;
char LocChar [14] ; int LocWord ;
В языке Си все подпрограммы являются также функциями; любая подпрограмма может возвращать значение в вызывающую программу. В связи с тем, что приведенная функция не возвращает значение, она объявлена как пустая функция (void).
Язык программирования Си обеспечивает использование автоматических (automatic) переменных для запоминания локальных данных. Заметим, однако, что отсутствует стандарт, предписывающий порядок размещения в стеке локальных переменных.
Соглашения о связях для языка Паскаль фирмы "Майкрософт"
Если листинг 2-8 приближается к синтаксису вызова для языка Си фирмы "Майкрософт", то соглашения о связях для компилятора языка Паскаль фирмы "Майкрософт" лучше выражаются с помощью примера, приведенного в листинге 2-4. Вызов на Паскале эквивалентен вызову процедуры myproc (моя процедура), закодированному следующим образом:
procedure MyProc (Param1, Param2, Param3 : integer) ; begin
...
Главное отличие между языками Си и Паскаль состоит в том, что Паскаль выполняет гораздо больше строгих проверок. Эти проверки гарантируют: что при вызове передается правильное количество и типы параметров; что значения функции используются способом, соответствующим их типу и т.д. Таким образом, в отличие от языка Си, в языке Паскаль программа должна быть объявлена либо процедурой (подпрограмма, которая не возвращает значения), либо функцией.
Язык Паскаль также обеспечивает использование автоматических переменных для памяти локальных данных. Как и в языке Си, в языке Паскаль нет стандартных решений о назначении порядка локальных переменных в стеке. Также, как и в языке Си, в Паскале память для локальных переменных распределяется при вершине стека на входе в вызываемую программу. Если процедура MyProc использует локальные переменные LocIndx, LocChar и LocWord, то они должны будут ссылаться так, как показано в структуре StackFrame листинга 2-8. Паскаль эквивалентен программе, похожей на ниже приведенную:
procedure MyProc (Param1, Param2, Param3 : integer) ; var
LocIndx, LocWord : integer ; LocChar [1..14] : character ;
begin
...
Соглашения о связях языков Фортран и Бэйсик фирмы "Майкрософт"
Стандартные компиляторы языков программирования Бэйсик и Фортран фирмы "Майкрософт" очень похожи на компилятор языка Паскаль фирмы "Майкрософт". Таблица 2-3 справедливо показывает, как много имеется сходства при стандартных вызовах. Однако, имеются и отличия. Главным отличием от соглашений о связях языка Паскаль состоит в том, что и Бэйсик и Фортран передают свои аргументы по ссылкам. Так как эти языки программирования передают адреса переменных, любые манипуляции переменными, выполняемые вызываемой программой, также изменяют значения переменных в вызывающей программе.
В действительности, сходство между всеми четырьмя интерфейсами означает, что как легко написать подпрограмму на языке Ассемблер для Бэйсика и Фортрана, также легко и для Паскаля или языка Си. Однако, в программах языков Бэйсик и Фортран для установки правильного интерфейса требуются большие усилия.
49. АССЕМБЛЕРНЫЕ ВСТАВКИ НА С И PASCAL
В тексте программы на языке Паскаль, может быть, использована ассемблерная вставка либо подпрограмма на языке Ассемблер.
Procedure <имя>(<список параметров>); Assembler;
asm
<Текст на Ассемблере > end;
50.ИСПОЛЬЗОВАНИЕ ПРОЦЕДУР НА АССЕМБЛЕРЕ.
Ассемблер поддерживает использование процедур. Процедура в ассемблере – это относительно самостоятельный фрагмент, к которому возможно обращение из разных мест программы. На других языках такие фрагменты оформляют соответствующим образом и называют подпрограммами: функциями или процедурами. Поддержка процедурного программирования для ассемблера означает, что в языке существуют специальные команды вызова подпрограммы и обратной передачи управления. Однако, в отличие от языков высокого уровня, ассемблер не требует специального оформления процедур. На любой адрес программы можно передать управление командой вызова процедуры, и оно вернется к вызвавшей процедуре, как только встретится команда возврата управления. Такая организация может привести к трудночитаемым программам, поэтому в язык Ассемблера включены директивы логического оформления процедур:
<метка> PROC <язык> <тип> USES <регистры> ; для ассемблера TASM фирмы Borland
. . .
<метка> ENDP
или
<метка> PROC <тип> <язык> USES <регистры> ; для ассемблеров MASM и WASM3
. . .
<метка> ENDP
где <тип> – может принимать значение NEAR (процедура ближнего вызова) или FAR (процедура дальнего вызова). По умолчанию подразумевается, что процедура имеет тип NEAR в моделях памяти
TINY, SMALL, COMPACT и тип FAR в остальных моделях памяти MS DOS. Процедуры ближнего типа должны находиться в том же сегменте, что и вызывающая процедура. Дальний тип процедуры означает, что к ней можно обратиться из любого другого сегмента кода; <язык> – определяет взаимодействие процедуры с языками высокого уровня. В некоторых ассемблерах директива PROC позволяет указывать параметры, передаваемые вызывающей программой. В этом случае указание языка необходимо, так как различные языки используют разные способы передачи параметров.
USES <регистры> – список регистров, значение которых изменяет процедура. Ассемблер поместит в начало процедуры набор команд PUSH, для сохранения в стеке перечисленных регистров, а
перед командой RET – набор команд POP, которые восстановят значения этих же регистров. Все операнды директивы PROC не обязательны.
51. ЗАЩИЩЕННЫЙ РЕЖИМ РАБОТЫ МИКРОПРОЦЕССОРА
Любой сегмент памяти в защищенном режиме имеет следующие атрибуты:
1.Расположение сегмента в памяти.
2.Размер сегмента.
3.Уровень привилегий – определяет права данного сегмента относительно других сегментов.
4.Тип доступа – определяет назначение сегмента.
Состав перечисленных атрибутов показывает, что в защищенном режиме микропроцессор поддерживает два типа защиты – по привилегиям и по доступу к памяти. В отличие от реального режима, в защищенном режиме программа уже не может

обратиться по любому физическому адресу памяти. Для этого она должна иметь определенные полномочия и удовлетворять ряду требований.
Ключевым объектом защищенного режима является специальная структура – дескриптор сегмента, который представляет собой 8-байтовый дескриптор непрерывной области памяти. Любая область памяти, которая логически может являться сегментом данных, стека или кода, должна быть описана таким дескриптором. Все дескрипторы собираются в одну из трех дескрипторных таблиц. В какую именно таблицу должен быть помещен дескриптор, определяется его назначением. Адрес, по которому размещаются дескрипторные таблицы может быть любым: он хранится в специально предназначенном для этого адреса сегментном регистре.
52. ХАРАКТЕРИСТИКИ ЗАЩИЩЕННОГО РЕЖИМА РАБОТЫ МИКРОПРОЦЕССОРОВ INTEL.
Защищённый режим (режим защищённой виртуальной адресации) — режим работы x86-
совместимых процессоров. Частично был реализован уже в процессоре80286, но там существенно отличался способ работы с памятью, так как процессоры ещё были 16-битными и не была реализована страничная организация памяти. Первая 32-битная реализация защищенного режима — процессор Intel 80386. Применяется в совместимых процессорах других производителей. Данный режим используется в современных многозадачных операционных системах, Microsoft Windows, Linux, OS X.
Первоначально в персональных компьютерах фирмы IBM использовались микропроцессоры i8086 или i8088. Эти процессоры были 16-ти разрядными и могли адресовать 1Мбайт памяти, из которыэ ОЗУ занимало неболее 640Кбайт.
Совершенствование оборудования шло по двум направлениям: увеличение быстродействия и повышение помехоустойчивости (с программной точки зрения) вычислительной системы в целом.
В результате был создан микропроцессор i80286. Для обеспечения совместимости с действующими системами этот микропроцессор мог работать в двух режимах:
1.РЕАЛЬНЫЙ РЕЖИМ - процессор является полным аналогом i8086, но имеет большее быстродействие. В этот режим процессор переключается после аппаратного сброса;
2.ЗАЩИЩЕННЫЙ РЕЖИМ - процессор использует иной метод адресации памяти, большее адресное пространство (i286 - 16Мбайт, i386 и i486 -4Гбайта), встроенную поддержку мультизадачных ОС и изолированные адресные пространства выполняемых задач. Переход в защищенный режим осуществляется специальной командой.
Помимо этого МП i386 и i486 реализованна концепция ВИРТУАЛЬНОЙ ПАМЯТИ. Она заключается в том, что не вся информация нужна в каждый конкретный момент.
В ЗАЩИЩЕННОМ РЕЖИМЕ логический адрес образуют две компаненты:
1.Селектор - являющийся индексом в таблице, содержащей базовые физические адреса сегментов;
2.Смещение - значение смещения от начала базового адреса.
Физический адрес получается путем сложения базового адреса, извлеченного при помощи значения селектора из таблицы, и смещения:
Значение селектора берется из сегментного регистра, но рассматривается оно не как в реальном режиме. Как индекс (Index) в таблице используется только старшая часть, три младших бита имеют специальное назначение:
∙Биты 0 и 1 (Requested Privilede Level) - уровень запрашиваемых привилегий, используются системой защиты памяти;
∙Бит 2 (Table Indicator) - определяет одну из двух таблиц преобразования адресов.
Дескриптор с нулевым индексом называется НУЛЕВЫМ ИНДИКАТОРОМ при работе не используется, а обращение к нему вызывает прерывание.
53. СЕГМЕНТНЫЕ РЕГИСТРЫ И СТРУКТУРЫ ДАННЫХ ЗАЩИЩЕННОГО РЕЖИМА
Сегментные регистры можно разделить на три группы:
1.4 регистра управления
2.4 регистра системных адресов
3.8 регистров отладки.
В состав сегментных регистров микропроцессоров Pentium введены изменения:
1.задействован ранее зарезервированный регистр управления cr4
2.введена группа MSR-регистров (модельно-зависимые регистры), назначение и возможности которых привязаны к конкретной модели микропроцессора. Регистры управления. В группу регистров управления входят пять регистров cr0-
cr4. Эти регистры предназначены для общего управления системой. Регистры управления доступны только программам с уровнем привилегий 0. Хотя микропроцессор имеет 5 регистров управления, доступны из них только 4. cr1 исключается, потому что его функции пока не определены, он зарезервирован для будущего использования.
Регистр cr0 содержит системные флаги, управляющие режимами работы микропроцессора и отражающие его состояние глобально, независимо от конкретных выполняющихся задач. Назначение системных флагов:
pe – разрешение защищенного режима работы. Состояние этого флага
показывает в каком из двух режимов реальном (pe=0) или защищенном (pe=1) работает микропроцессор в данный момент.
Регистр cr2 используется при страничной организации оперативной памяти для регистрации ситуации, когда текущая команда обратилась по адресу, содержащемуся в странице памяти, отсутствующей в данный момент в памяти. В такой момент в
микропроцессоре возникает исключительная ситуация и линейный 32-битный адрес команды, вызвавшей это исключение, записывается в регистр cr2. Имея эту информацию,
обработчик исключения определяет нужную страницу, осуществляет ее подкачку в память и возобновляет нормальную работу программы.
Регистр cr3 также используется при страничной организации памяти. Это так называемый регистр каталога страниц первого уровня. Он содержит 20-битный физический базовый адрес каталога страниц текущей задачи.
Регистр cr4 содержит признаки, в основном разрешительного характера, которые характеризуют те или иные архитектурные элементы. Устанавливая те или иные биты в регистре cr4, можно включать и отключать поддержку этих свойств.
54.ПЕРЕВОД МИКРОПРОЦЕССОРА В ЗАЩИЩЕННЫЙ РЕЖИМ.
Перед тем, как переключить процессор в защищённый режим, надо выполнить некоторые подготовительные действия, а именно:
∙Подготовить в оперативной памяти глобальную таблицу дескрипторов GDT. В этой таблице должны быть созданы дескрипторы для всех сегментов, которые будут нужны программе сразу после того, как она переключится в защищённый режим. Впоследствии, находясь в защищённом режиме, программа может модифицировать GDT (если, разумеется, она работает в нулевом кольце защиты). Программа может модифицировать имеющиеся дескрипторы или добавить новые, загрузив заново регистр GDTR.
∙Для обеспечения возможности возврата из защищённого режима в реальный необходимо записать адрес возврата в реальный режим в область данных BIOS по адресу 0040h:0067h, а также записать в CMOSпамять в ячейку 0Fh код 5. Этот код обеспечит после выполнения сброса процессора передачу управления по адресу, подготовленному нами в области данных BIOS по адресу 0040h:0067h.
∙Запретить все маскируемые и немаскируемые прерывания.
∙Открыть адресную линию A20.
∙Запомнить в оперативной памяти содержимое сегментных регистров, которые необходимо сохранить для возврата в реальный режим, в частности, указатель стека реального режима.
∙Загрузить регистр GDTR.
Это самый простой этап. Для перевода процессора i80286 из реального режима в защищённый можно использовать специальную команду LMSW, загружающую регистр состояния процессора (Mashine Status Word). Младший бит этого регистра указывает режим работы процессора. Значение, равное 0, соответствует реальному режиму работы, а значение 1 - защищённому.
Если установить младший бит регистра состояния процессора в 1, процессор переключится в защищённый режим:
mov |
ax, 1 |
lmsw |
ax |
Для того, чтобы вернуть процессор 80286 из защищённого режима в реальный, необходимо выполнить аппаратный сброс (отключение) процессора. Это можно сделать следующим образом:
mov |
ax, 0FEh |
; команда отключения |
out |
64h, ax |
|
Перед выдачей команды отключения необходимо запомнить содержимое регистра SP, так как после передачи управления по адресу, записанному в области данных BIOS 0040h:0067h, регистры SS:SP будет указывать на стек BIOS.
После выдачи команды отключения надо подождать, когда произойдёт сброс процессора. Это можно сделать, выдавая в цикле команду HLT.
55.ОСОБЕННОСТИ РАБОТЫ В ЗАЩИЩЕННОМ РЕЖИМЕ
Взащищенном режиме программа оперирует адресами, которые могут относиться к физически отсутствующим ячейкам памяти, поэтому такое адресное пространство называется виртуальным. Размер виртуального адресного пространства программы может превышать емкость физической памяти и достигать 64Тбайт. Для адресации виртуального адресного пространства используется сегментированная модель, в которой адрес состоит из двух элементов: селектора сегмента и смещения внутри сегмента. С каждым сегментом связана особая структура, хранящая информацию о нем, - дескриптор. Кроме "виртуализации" памяти на уровне сегментов существует возможность "виртуализации" памяти при помощи страниц - страничная трансляция. Страничная трансляция предоставляет удобные средства для реализации в операционной системе функций подкачки, а кроме того в процессорах P6+ обеспечивает 36-битную физическую адресацию памяти (64Гбайт).
Встроенные средства переключения задач обеспечивают многозадачность в защищенном режиме. Среда задачи состоит из содержимого регистров МП и всего кода с данными в пространстве памяти. Микропроцессор способен быстро переключаться из одной среды выполнения в другую, имитируя параллельную работу нескольких задач. Для некоторых задач может эмулироваться управление памятью как у процессора 8086. Такое состояние задачи называется режимом виртуального 8086 (Virtual 8086 Mode). О пребывании задачи в таком состоянии сигнализирует бит VM в регистре флагов. При этом задачи виртуального МП 8086 изолированы и защищены, как от друг друга, так и от обычных задач защищенного режима.
Защита задач обеспечивается следующими средствами: контроль пределов сегментов, контроль типов сегментов, контроль привилегий, привилегированные инструкции и защита на уровне страниц. Контроль пределов и типов сегментов обеспечивает целостность сегментов кода и данных. Программа не имеет права обращаться к виртуальной памяти, выходящей за предел того или иного сегмента. Программа не имеет права обращаться к сегменту данных как к коду и наоборот. Архитектура защиты микропроцессора обеспечивает 4 иерархических уровня привилегий, что позволяет ограничить задаче доступ к отдельным сегментам в зависимости от ее текущих привилегий. Кроме того, текущий уровень привилегий задачи влияет на возможность выполнения тех или иных специфических команд (привилегированных инструкций). Функции страничной трансляции, впервые появившиеся в МП Intel386, обеспечивают дополнительные механизмы защиты на уровне страниц.
Взащищенном режиме любой запрос к памяти, как со стороны операционной
системы, так и со стороны прикладных программ должен быть санкционирован. Микропроцессор аппаратно контролирует доступ программ к любому адресу в оперативной памяти. Для получения доступа целевой адрес, к которому хочет получить доступ программа, должен быть описан для программы. Это означает что участок физической памяти, содержащий нужный адрес, должен быть описан с помощью некоторого дескриптора сегмента. Программе, которая желает использовать данный участок памяти, должен быть сообщен указатель на соответствующий дескриптор в одной из дескрипторных таблиц. В защищенном режиме меняется роль сегментного регистра – теперь он содержит уже не адрес, а индекс в таблице дескрипторов сегментов. Но само назначение сегментных регистров не меняется – они по-прежнему указывают на сегменты команд, данных и стека, но делают это используя принципиально другие механизмы. Размер сегмента в защищенном режиме может достигать 4Гбайт, то есть занимать все возможное физическое пространство памяти. Выведение информации о базовом адресе сегмента и его размере на уровень микропроцессора позволяет аппаратно контролировать работу программ с памятью и предотвращать обращения по
несуществующим адресам, либо адресам, находящимся вне предела, разрешенного полем размера сегмента limit.
Сегменты неравноправны в правах доступа к ним. Три аппаратно поддерживаемые дескрипторные таблицы:
1. GDT – глобальная дескрипторная таблица. Это основная общесистемная
таблица, к которой допускается обращение со стороны программ, обладающих достаточными привилегиями. Расположение таблицы в памяти произвольно 2. Таблица LDT – локальная дескрипторная таблица. Для любой задачи в системе может быть создана своя дескрипторная таблица. Тем самым адресное
пространство задачи локализуется в пределах установленных набором дескрипторов таблицы. Расположение таблицы в памяти также произвольно. В таблице могут содержаться следующие типы дескрипторов:
дескрипторы сегментов кодов программ
56. АССЕМБЛЕР ДЛЯ WINDOWS. СТРУКТУРА WINDOWS – ПРОГРАММЫ НА ЯЗЫКЕ АССЕМБЛЕРА.
Директива .686 указывает компилятору ассемблера, что необходимо использовать набор операций процессора определённого поколения.
Директива .model позволяет указывать используемую модель памяти и соглашение о вызовах. Как уже было сказано, на архитектуре Win32 используется только одна модель памяти – flat, что и указано в приведённом примере. Соглашения о вызовах определяют порядок передачи параметров и порядок очистки стека.
Директива option casemap: none заставляет компилятор языка ассемблера различать большие и маленькие буквы в метках и именах процедур.
Директивы .data, .data?, .const и .code определяют то, что называется секциями. В Win32 нет сегментов, но адресное пространство можно поделить на логические секции. Начало одной секции отмечает конец предыдущей. Есть две группы секций: данных и кода.
Секция .data содержит инициализированные данные программы.
Секция .data? содержит неинициализированные данные программы. Иногда нужно только предварительно выделить некоторое количество памяти, не инициализируя её. Эта секция для этого и предназначается. Преимущество неинициализированных данных в том, что они не занимают места в исполняемом файле. Вы всего лишь сообщаете компилятору, сколько места вам понадобится, когда программа загрузится в память.
Секция .const содержит объявления констант, используемых программой. Константы не могут быть изменены. Попытка изменить константу вызывает аварийное завершение программы.
Задействовать все три секции не обязательно.
Есть только одна секция для кода: .code. В ней содержится весь код.
Предложения <метка> и end <метка> устанавливают границы кода. Обе метки должны быть идентичны. Весь код должен располагаться между этими предложениями.
Любая программа под Windows должна, как минимум, корректно завершится. Для этого необходимо вызвать функцию Win32 API ExitProcess.
.686
.model flat, stdcall option casemap: none
include \masm32\include\windows.inc include \masm32\include\kernel32.inc includelib \masm32\lib\kernel32.lib
.code
program: push 0
call ExitProcess end program
Выше приведён пример минимальной программы на языке ассемблера, которая делает только одно – корректно завершается. В ней появились две новые директивы: include и includelib. Первая позволяет включать в программу файлы, содержащие прототипы процедур, а также определения констант и структур, которые могут понадобиться для программирования под Win32. Вторая директива указывает, какие библиотеки использует программа. Компоновщик должен будет прилинковать их. Без указания включаемого файла kernel2.inc и библиотеки импорта kernel32.lib невозможно будет вызвать процедуру ExitProcess. Файл windows.inc в данном случае включать не обязательно, но он требуется достаточно часто, а включаемые файлы не увеличивают размер получаемой программы.
Команда PUSH кладёт в стек параметр для процедуры ExitProcess. Этот параметр определяет код завершения. Значение 0 – это код нормального завершения программы.
Команда CALL вызывает процедуру ExitProcess.
Если вы используете компилятор MASM32, то пункт меню Project содержит команды Assemble & Link и Console Assemble & Link, которые позволяют скомпилировать обычное и консольное приложение под Windows. Приведённую программу можно откомпилировать обоими способами.
57. ПРОГРАММИРОВАНИЕ НА АССЕМБЛЕРЕ С ИСПОЛЬЗОВАНИЕМ WIN32 API.
Программирование на ассемблере под Win32 воспринимается весьма не однозначно. Считается, что написание приложений слишком сложно для применения ассемблера. Собственно обсуждению того, насколько оправдана такая точка зрения, и посвящена данная статья. Она не ставит своей целью обучение программированию под Win32 или обучение ассемблеру, я подразумеваю, что читатели имеют определённые знания в этих областях.
В отличие от программирования под DOS, где программы написанные на языках высокого уровня (ЯВУ) были мало похожи на свои аналоги, написанные на ассемблере, приложения под Win32 имеют гораздо больше общего. В первую очередь, это связано с тем, что обращение к сервису операционной системы в Windows осуществляется посредством вызова функций, а не прерываний, что было характерно для DOS. Здесь нет передачи параметров в регистрах при обращении к сервисным функциям и, соответственно, нет и множества результирующих значений возвращаемых в регистрах общего назначения и регистре флагов. Следовательно проще запомнить и использовать протоколы вызова функций системного сервиса. С другой стороны, в Win32 нельзя непосредственно работать с аппаратным уровнем, чем "грешили" программы для DOS. Вообще написание программ под Win32 стало значительно проще и это обусловлено следующими факторами:
отсутствие startup кода, характерного для приложений и динамических библиотек написанных под Windows
3.x;
гибкая система адресации к памяти: возможность обращаться к памяти через любой регистр общего назначения; "отсутствие" сегментных регистров; доступность больших объёмов виртуальной памяти;
развитый сервис операционной системы, обилие функций, облегчающих разработку приложений; многообразие и доступность средств создания интерфейса с пользователем (диалоги, меню и т.п.).
58.СИСТЕМА КОМАНД СОПРОЦЕССОРА.
Система команд сопроцессора включает в себя около 80 машинных команд, включающих в себя
команды передачи данных; команды сравнения данных; арифметические команды; команды трансцендентных функций;
команды управления сопроцессором.
Мнемоническое обозначение команд сопроцессора характеризует особенности их работы и в связи с этим может представлять определенный интерес. Поэтому коротко рассмотрим основные моменты образования названий команд:
все мнемонические обозначения начинаются с символа f (float);
вторая буква мнемонического обозначения определяет тип операнда в памяти, с которым работает команда: - i
— целое двоичное число; - b — целое десятичное число; - отсутствие буквы — вещественное число; последняя буква мнемонического обозначения команды р означает, что последним действием команды обязательно является извлечение операнда из стека;
последняя или предпоследняя буква r (reversed) означает реверсивное следование операндов при выполнении команд вычитания и деления, так как для них важен порядок следования операндов.
Система команд сопроцессора отличается большой гибкостью в выборе вариантов задания команд, реализующих определенную операцию, и их операндов. Минимальная длина команды сопроцессора — 2 байта. Все команды сопроцессора оперируют регистрами стека сопроцессора. Если операнд в команде не указывается, то по умолчанию используется вершина стека сопроцессора (логический регистр st(0)). Если команда выполняет действие с двумя операндами по умолчанию, то эти операнды – регистры st(0) и st(1).
59.ИСКЛЮЧЕНИЯ СОПРОЦЕССОРА И ИХ ОБРАБОТКА
Однако выяснить причину исключения мало, да это и несложно. Важно, исправив ситуацию, вернуть управление прерванной программе. В защищенном режиме работы процессора прерывания (исключения) делятся на несколько групп: сбои, ловушки, исключения. Это деление осуществляется в зависимости от того, какая информация сохраняв тся о месте возникновения прерывания (исключения) и возможности возобновления прерванной программы. Для сопроцессора ситуация аналогична. Здесь инфор мация о месте возникновения исключения зависит от типа исключения. Так, для исключений недействительной операции, деления на ноль и денормализованног(э операнда запоминается адрес команды, вызвавшей исключение. То есть ситуация для этих типов исключений распознается, и исключение возбуждается до исполнения команды сопроцессора (по классификации для защищенного режима -• это сбой). При этом операнды в стеке и в памяти не модифицируются. Для остальных типов исключений ошибочная ситуация распознается после выполнения действий «виноватой» команды. Это означает, что в стеке в качестве адреса места возникновения исключения запоминается адрес следующей (после виновниц ы) команды программы. При этом операнды в памяти и в регистровом стеке, возможно, будут изменены. Ваши действия должны учитывать эти особенности возникновения различных типов исключений
60. ММХ – РАСШИРЕНИЕ АРХИТЕКТУРЫ МИКРОПРОЦЕССОРА
Основу модели ММХ-расширения составляют 2 компоненты: программная и аппаратная. Основа программной компоненты – система команд ММХ-расширения (57 команд) и 4 новых типа данных. ММХ-команды являются естественным дополнением основной системы команд микропроцессора. Основным принципом их работы является одновременная обработка нескольких единиц однотипных данных одной командой –
Single Instruction Multiple Data (SIMD)
Основа аппаратной компоненты – восемь регистров сопроцессора. Регистры сопроцессора стека имеют размерность 80 бит, когда регистры сопроцессора играют роль ММХ-регистров, то доступными являются их младшие 64 бита. При работе стека сопроцессора в режиме ММХ-расширения он рассматривается не как стек, а как обычный регистровый массив с произвольным доступом. Регистровый стек сопроцессора не может одновременно использоваться и по своему прямому назначению и как ММХ-расширение. Важное отличие ММХ-команд от обычных команд процессора в том, как они реагируют на ситуации переноса и заема. В случае выхода значения результата за пределы операнда, в нем фиксируется максимальное или минимальное значение. Такой принцип формирования результата называется арифметикой с насыщением.
Не все трансляторы ассемблера поддерживают ММХ-команды. В этом случае необходимо подключить файл iammx.inc. Включив этот файл директивой include в начало программы можно использовать все ММХ-команды в определенном формате.