Будь умным!


У вас вопросы?
У нас ответы:) SamZan.net

Лабораторная работа 11.

Работа добавлена на сайт samzan.net:

Поможем написать учебную работу

Если у вас возникли сложности с курсовой, контрольной, дипломной, рефератом, отчетом по практике, научно-исследовательской и любой другой работой - мы готовы помочь.

Предоплата всего

от 25%

Подписываем

договор

Выберите тип работы:

Скидка 25% при заказе до 23.11.2024

Московский государственный технический университет им. Н. Э. Баумана

Калужский филиал

Кафедра ЭИУ2-КФ

Методическое пособие

к лабораторным работам

по курсу «Системное программирование»

Калуга, 2007.

Лабораторная работа №1.

FAR Manager. Turbo Debugger.

Цель работы: изучить основы работы со средой программирования FAR Manager, используемой при написании исходных текстов программ. Научиться пользоваться отладчиком программ Turbo Debugger.

Теоретическая часть.

Процесс разработки программы на ассемблере.

Условно процесс разработки программы можно разделить на 4 этапа.

Рис. 1. Процесс разработки программы на ассемблере.

На первом этапе, когда вводится код программы, можно использовать любой текстовый редактор (например, FAR Manager). Созданный с помощью редактора файл должен иметь расширение .asm.

Следующий шаг на пути создания исполняемого модуля – трансляция программы. Для трансляции нужен созданный файл с расширением .asm. На этапе трансляции решается несколько задач:

  •  перевод команд ассемблера в соответствующие им машинные команды;
  •  построение таблицы символов;
  •  расширение макросов;
  •  формирование файла листинга и объектного модуля.

Программа, которая реализует эти задачи, называется ассемблером. Итог работы ассемблера – два файла: файл объектного модуля и файл листинга. Объектный модуль включает в себя представление исходной программы в машинных кодах и некоторую другую информацию, необходимую для его компоновки и отладки. Формат командной строки для запуска tasm.exe следующий:

tasm.exe [ключи] имя_исходного_файла [,имя_объектного_файла] [,имя_файла_перекрестных_ссылок]

Вместо атрибута [ключи] строка может содержать:

/c - указание на включение в файл информацией о перекрестных ссылках; 

/khn - задает максимальное количество идентификаторов, которое может содержать исходная программа. По умолчанию программа может содержать до 16384 идентификаторов. Это значение можно увеличить (но не более чем до 32 768) или уменьшить до n;

/l - указывает на необходимость создания файла листинга, даже если он не “заказывается” в командной строке; 

/ml - различать во всех идентификаторах прописные и строчные буквы; 

/mu - воспринимать все символы идентификаторов как прописные;

/t - подавление вывода всех сообщений при условном ассемблировании, кроме сообщений об ошибках (то есть тестирование программы на предмет выявления синтаксических ошибок);

/zi - включить в объектный файл информацию для отладки. Эта информация используется отладчиком Turbo Debugger;

/zn - запретить помещение в объектный файл отладочной информации. 

Следующий этап – компоновка. Главная цель этого этапа – преобразовать код и данные в объектных файлах в их перемещаемое исполняемое отображение (файл с расширением .exe). Формат командной строки для запуска компоновщика следующий:

tlink.exe[ключи]список_объектных_файлов, имя_загрузочного_модуля] [,имя_файла_карты] [,имя_файла_библиотеки] [,имя_файла_определений] [,имя_ресурсного_файла]

Параметр [ключи] может принимать следующие значения:

/x - не создавать файл карты (map); 

m - создать файл карты;

/c - различать строчные и прописные буквы в идентификаторах;

/v - включить отладочную информацию в выполняемый файл, для ее использования при отладке программы;

/t - создать файл типа .com (по умолчанию .exe).

На этапе отладки в соответствии с алгоритмом программист проверяет правильность функционирования как отдельных фрагментов кода, так и программы в целом.

Запуск отладчика производится с помощью строки:

td.exe имя_исполняемого_модуля

FAR Manager.

FAR обеспечивает:

отображение деревьев каталогов и содержимого каталогов (характеристик входящих в них файлов) в форме, наиболее удобной для восприятия человеком;

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

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

подготовку текстовых файлов;

выполнение из ее среды всех команд DOS.

Для удобства и быстроты работы в FAR Manager, в нем предусмотрены, так называемые HotKeys “горячие клавиши”. HotKeys можно разделить по функциональному назначению:

Команды управления панелями

Общие команды

Tab - Изменить активную панель

Ctrl-U - Поменять панели местами

Ctrl-R - Обновить содержимое панели

Ctrl-O - Убрать/показать обе панели

Ctrl-P - Убрать/показать неактивную панель

Команды файловой панели

Alt-Left,Alt-Right Прокрутка длинных имен и описаний

ЛевыйCtrl-1 - Установить краткий режим просмотра

ЛевыйCtrl-2 - Установить средний режим просмотра

ЛевыйCtrl-3 - Установить полный режим просмотра

ЛевыйCtrl-4 - Установить широкий режим просмотра

ЛевыйCtrl-5 - Установить детальный режим просмотра

ЛевыйCtrl-6 - Установить режим просмотра описаний

ЛевыйCtrl-7 - Установить режим просмотра длинных описаний

ЛевыйCtrl-8 - Установить режим просмотра владельцев файлов

ЛевыйCtrl-9 - Установить режим просмотра связей файлов

ЛевыйCtrl-0 - Установить альтернативный полный режим просмотра

Ctrl-F1Убрать/показать левую панель

Ctrl-F2Убрать/показать правую панель

Ctrl-F3Сортировать файлы активной панели по имени

Ctrl-F4Сортировать файлы активной панели по расширению

Ctrl-F5Сортировать файлы активной панели по времени модификации

Ctrl-F6Сортировать файлы активной панели по размеру

Ctrl-F7Не сортировать файлы активной панели

Ctrl-F8Сортировать файлы активной панели по времени создания

Ctrl-F9Сортировать файлы активной панели по времени доступа

Ctrl-F10Сортировать файлы активной панели по описаниям

Ctrl-F11Сортировать файлы активной панели по владельцу

Ctrl-F12Вывести меню режимов сортировки

Командная строка

Общие команды

Ctrl-Home - В начало строки

Ctrl-End - В конец строки

Ctrl-K - Удалить до конца строки

Ctrl-BS - Удалить слово слева

Ctrl-Del - Удалить слово справа

Ctrl-E - Предыдущая команда

Ctrl-X - Следующая команда

Ctrl-Y - Очистить командную строку

Команды вставки

Ctrl-Enter - Вставить имя файла из активной панели

Ctrl-F Вставить - полное имя файла из активной панели

Ctrl-[ - Вставить путь из левой панели

Ctrl-] - Вставить путь из правой панели

Управление файлами и сервисные команды

F1 - Помощь

F3 - Просмотр

F4 - Редактирование

F5 - Копирование

F6 - Переименование или перенос

F7 - Создание новой папки

F8 - Удаление

F9 - Показать горизонтальное меню

F10 - Завершить работу с FAR

Alt-F1 - Изменить текущий диск в левой панели

Alt-F2 - Изменить текущий диск в правой панели

Alt-F3 - Встроенная/внешняя программа просмотра

Alt-F4 - Встроенный/внешний редактор

Alt-F5 - Печать файлов

Alt-F7 - Выполнить команду поиска файла

Alt-F8 - Показать историю команд

Turbo Debugger.

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

  •  определить место логической ошибки;
  •  определить причину логической ошибки.

TD предоставляет следующие возможности по отладке:

  •  трассировка программы в прямом направлении;
  •  трассировка программы в обратном направлении;

просмотр и изменение состояния аппаратных ресурсов процессора во время трассировки.

Для удобства использования отладчика в нем присутствуют следующие основные “горячие клавиши”:

F1 - Получение контекстно-зависимой интерактивной подсказки

F2 - Устанавливает точку останова в позиции курсора

F4 - Выполнение до позиции курсора

F7 - Выполнение одной исходной строки или команды

F8 - Выполнение одной исходной строки или команды с пропуском вызовов

F9 - Запуск программы

Alt-F2 - Устанавливает точку останова по адресу

Alt-F3 - Закрывает текущее окно

Alt-F4 - Реверсирует выполнение программы

Alt-F5 - Показывает экран вывода программы

Alt-F7 - Выполняет одну команду программы

Alt-F8 - Выполняет программу до возврата из функции

Alt-F9 - Выполняет программу до заданного адреса

Alt-F10 - Вызывает локальное меню окна

Alt-1-9 - Делает активным окно с заданным номером

Alt-X - Осуществляет выход из отладчика и возврат в DOS               

Ctrl-F2 - Завершает сеанс отладки и устанавливает программу в исходное состояние

Ctrl-F4 - Вычисляет значение выражения

Ctrl-F7 - Заносит переменную в окно слежения

Ctrl-F9 - Запускает программу

Ins - Начинает выбор (выделение) блока текста; для выделения используются клавиши "Стрелка влево" и "Стрелка вправо"

Задание:

В памяти задана строка символов. Необходимо преобразовать строку таким образом, чтобы ее можно было прочитать в обратном направлении (справа – налево). При написании программы разрешается использовать только команду пересылки данных mov.

Лабораторная работа №2.

Регистр флагов.

Цель работы: изучить структуру регистра флагов (FLAGS/EFLAGS) и основные принципы работы с ним. Научиться определять состояния отдельных флагов по результату выполненной операции.

Теоретическая часть.

Архитектура процессоров семейства ix86. Регистры.

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

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

Таблица 1.

Общая регистровая архитектура процессора семейства ix86.

                  31           16 15                        0

20h/0Eh

EIP

IP

указатель команд

24h/10h

EFLAGS

FLAGS

регистр флагов

28h/12h

EAX

AX

AH       |       AL

аккумулятор

2Ch/14h

ECX

CX

CH       |       CL

счетчик

30h/16h

EDX

DX

DH       |       DL

регистр данных

34h/18h

EBX

BX

BH       |       BL

указатель базы

38h/1Ah

ESP

SP

указатель стека

3Ch/1Ch

EBP

BP

базовый регистр в стеке

40h/1Eh

ESI

SI

индекс источника

44h/20h

EDI

DI

индекс приемника

4Ch/24h

CS

регистр сегмента кода

50h/26h

SS

регистр сегмента стека

54h/28h

DS

регистр сегмента данных

22h

ES

дополнительные регистры

сегмента данных

58h

FS

5Ch

GS

Регистры можно разбить на 4 категории:

  1.  регистр флагов (FLAGS);
  2.  регистры общего назначения (AX(AH, AL), CX(CH, CL), DX(DH, DL), BX(BH, BL), SP, BP, SI, DI);
  3.  сегментные регистры (CS, DS, ES, FS, GS, SS);
  4.  указатель команд (IP).

Регистр флагов.

Регистр флагов – 16-ти разрядный регистр, содержащий всю необходимую информацию о состоянии процессора ix86 и результатах последних команд.

Основные флаги и их положение в регистре флагов показаны на рис. 1.

15

14

13

12

11

10

9

8

7

6

5

4

3

2

1

0

OF

DF

IF

TF

SF

ZF

AF

PF

CF

Рис.1. Структура 16-ти разрядного регистра флагов.

OFфлаг переполнения – предназначен для индикации переполнения результата при выполнении арифметических операций:

1 – в результате выполнения операции происходит перенос в старший знаковый бит результата или заем из старшего знакового бита результата;

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

DFфлаг направления – применяется преимущественно в командах обработки строковых данных:

1 – обработка осуществляется от наибольшего адреса к наименьшему.

0 – обработка осуществляется от наименьшего адреса к наибольшему.

В единичное положение флаг DF устанавливается командой STD, а сбрасывается в ноль – CLD.

IFфлаг разрешения прерывания – используется для разрешения или запрета внешнего прерывания:

1 – внешние прерывания разрешены;

0 – внешние прерывания запрещены.

В единичное положение флаг IF устанавливается командой STI, а в нулевое – CLI.

TFфлаг трассировки – используется для осуществления покомандного выполнения программы:

1 – процессор генерирует прерывание после выполнения каждой машинной команды (может использоваться при отладке программ, в частности отладчиками);

0 – обычная работа.

SFфлаг знака – используется для индикации знака результата последней выполненной команды:

1 – результат отрицательный;

0 – результат положительный.

ZFфлаг нуля – используется для проверки на ноль результата последней выполненной команды:

1 – результат нулевой;

0 – результат ненулевой.

AFфлаг дополнительного переноса – предназначен для обработки чисел в BCD формате. Используется в арифметических операциях над числами длиной в один байт:

1 – в результате операции сложения был произведен перенос из третьего разряда в старший разряд или при вычитании был заем в третий разряд младшей тетрады из значения в старшей тетраде;

0 – переносов и заемов в третий разряд (из третьего разряда) младшей тетрады результата не было.

PFфлаг четности:

1 – 8 младших разрядов результата содержат четное число единиц;

0 – 8 младших разрядов результата содержат нечетное число единиц.

CFфлаг переноса – предназначен для индикации переноса из старшего разряда:

1 – арифметическая операция произвела перенос из старшего бита результата;

0 – переноса не было.

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

Задание.

Самостоятельно на практике изучить регистр флагов (FLAGS), его назначение. А также, рассмотреть ситуации изменения основных флагов при выполнении арифметических операций.

Написать программу, демонстрирующую изменение следующих битов регистра флагов: CF, PF, ZF, SF, DF, OF. Прокомментировать изменение каждого флага.

Пример:

.model small

.stack 100h

.code

.startup

   std  ;Установка флага DF

   cld  ;Сброс флага DF

   mov al,+100

   add al,+100    ;=200(-56), CF=0, ZF=0, SF=1, OF=1, PF=0

   mov al,128     

   add al,128       ;=256(0), CF=1, ZF=1, SF=0, OF=1, PF=1

   mov al,-128    

   add al,+127    ;=-1(255), CF=0, ZF=0, SF=1, OF=0, PF=1

   mov al,-10      

   add al,-10       ;=-20(492), CF=1, ZF=0, SF=1, OF=0, PF=0

   mov al,+10     

   add al,+10      ;=20, CF=0, ZF=0, SF=0, OF=0, PF=1

   mov al,-5        

   add al,+5        ;=0(256), CF=1, ZF=1, SF=0, OF=0, PF=1

   mov bx,63      

   add bx,-2        ;=61, CF=1, ZF=0, SF=0, OF=0, PF=0

   add bh,16       ;=16, CF=0, ZF=0, SF=0, OF=0, PF=0

   add bl,16        ;=77, CF=0, ZF=0, SF=0, OF=0, PF=1

.exit 0

end

Лабораторная работа №3.

Директивы языка Assembler.

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

Теоретическая часть.

Директивой называется указание транслятору ассемблера на выполнение некоторых действий. У директив нет аналогов в машинном представлении.

К основным директивам ассемблера относятся: директивы стандартной сегментации, используемые при работе в режиме Ideal; директивы упрощенной сегментации, используемые при работе в режиме MASM; директивы резервирования памяти и инициализации данных; другие директивы.

  1.  Директивы стандартной сегментации (режим Ideal).

Директива SEGMENT указывает на необходимость размещения всех последующих данных в одном сегменте памяти, который может содержать данные, код или стек программы. Синтаксически описание сегмента на ассемблере выглядит следующим образом:

<имя_сегмента> SEGMENT [выравнивание] [комбинирование] [класс] [размер] [доступ]

{директивы}

{команды}

{макрокоманды}

{комментарии}

<имя_сегмента> ENDS

Директива SEGMENT имеет 5 необязательных атрибутов:

  •  Атрибут выравнивания сегмента (выравнивание) сообщает компоновщику о том, что нужно обеспечить размещение начала сегмента на заданной границе. По умолчанию тип выравнивания имеет значение PARA. Допустимые значения этого атрибута следующие:

Byte — выравнивание не выполняется. Сегмент может начинаться с любого адреса памяти;

Word — сегмент начинается по адресу, кратному двум, то есть последний (младший) значащий бит физического адреса равен 0 (выравнивание по границе слова);

DWord — сегмент начинается по адресу, кратному четырем, то есть два последних (младших) значащих бита равны 0 (выравнивание по границе двойного слова);

Para — сегмент начинается по адресу, кратному 16, то есть последняя шестнадцатеричная цифра адреса должна быть 0h (выравнивание по границе параграфа);

Page — сегмент начинается по адресу, кратному 256, то есть две последние шестнадцатеричные цифры должны быть 00h (выравнивание по границе страницы размером 256 байт);

MemPage — сегмент начинается по адресу, кратному 4 Кбайт, то есть три последние шестнадцатеричные цифры должны быть 000h (адрес следующей страницы памяти размером 4 Кбайт).

  •  Атрибут комбинирования сегментов (комбинирование) сообщает компоновщику, как нужно комбинировать сегменты различных модулей, имеющие одно и то же имя. По умолчанию атрибут комбинирования принимает значение Private. Атрибут может принимать следующие значения:

Private —все сегменты с одинаковыми именами рассматриваются как различные сегменты;

Public (Memory) — все сегменты с одинаковым именем будут объединены в порядке, установленном в программе. Новый объединенный сегмент будет целым и непрерывным. Все адреса (смещения) объектов, будут вычисляться относительно начала этого нового сегмента;

Common — располагает все сегменты с одним и тем же именем по одному адресу, то есть все сегменты с данным именем перекрываются. Размер полученного в результате сегмента будет равен размеру самого большого сегмента;

At xxxx — располагает сегмент по абсолютному адресу (xxxx), кратному 16;

Stack — определение сегмента стека. Заставляет компоновщика объединять все одноименные сегменты и вычислять адреса в этих сегментах относительно регистра SS;

UnInit – определяет сегмент неинициализированных данных;

Virtual – определяет общее пространство, которое должно находиться внутри другого сегмента.

  •  Атрибут класса сегмента (класс) — выполняет роль спецификатора категории. Все сегменты с одинаковым именем класса, даже с различными собственными именами, во время работы программы физически располагаются совместно в памяти.
  •  Атрибут размера сегмента (размер) – применяется только для процессоров i80386 и выше сегменты могут быть 16- или 32-разрядными. Это влияет, прежде всего, на размер сегмента и порядок формирования физического адреса внутри него. Далее перечислены возможные значения атрибута:

Use16 — сегмент допускает 16-разрядную адресацию. При формировании физического адреса может использоваться только 16-разрядное смещение. Соответственно, такой сегмент может содержать до 64 Кбайт кода или данных;

Use32 — сегмент должен быть 32-разрядным. При формировании физического адреса может использоваться 32-разрядное смещение. Поэтому такой сегмент может содержать до 4 Гбайт кода или данных.

  •  Атрибут доступа к сегменту (доступ) – используется только в программах защищенного режима. Возможные значения атрибута следующие:

ExecOnly – сегмент может содержать только код (без данных);

ExecRead – сегмент может содержать исполняемый код и данные только для чтения;

ReadOnly – сегмент может содержать только данные для чтения (без кода);

ReadWrite – сегмент может содержать изменяемые данные.

Директива ENDS – определяет конец описания сегмента.

Директива CODESEG – определяет начало нового сегмента кода.

Директива DATASEG – определяет начало нового сегмента данных.

Директива CONST – определяет начало нового сегмента постоянных данных.

Директива STACK – определяет начало нового сегмента стека.

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

ASSUME [NOTHING || (<сегментный_регистр> : <имя_сегмента || NOTHING>)]

Эта директива сообщает транслятору, какой сегмент, к какому сегментному регистру привязан. В свою очередь, это позволяет транслятору корректно связывать символические имена, определенные в сегментах. Привязка сегментов к сегментным регистрам осуществляется с помощью операндов этой директивы, в которых <имя_сегмента> должно быть именем сегмента, определенным в исходном тексте программы директивой SEGMENT или ключевым словом NOTHING. Если в качестве операнда используется только ключевое слово NOTHING, то предшествующие назначения сегментных регистров аннулируются, причем сразу для всех шести сегментных регистров. Ключевое слово NOTHING можно также использовать вместо аргумента <имя_сегмента> в этом случае будет выборочно разрываться связь между сегментом с именем <имя_сегмента> и соответствующим сегментным регистром.

  1.  Директивы упрощенной сегментации (режим MASM).

Директива .model – задает модель памяти, определяющей набор сегментов программы, размеры сегментов данных и кода, способы связывания сегментов и сегментных регистров. У этой директивы имеется один атрибут, который указывает на определенный тип памяти:

Tiny – сверхмалая; код и данные имеют ближний тип и размещаются внутри одного сегмента;

Small – малая; код и данные имеют ближний тип и размещаются в разных сегментах;

Medium – средняя; код имеет дальний тип, а данные – ближний. Код и данные располагаются в разных сегментах;

Compact – компактная; код имеет ближний тип, а данные – дальний. Код и данные находятся в разных сегментах;

Large – большая; код и данные имеют дальний тип, размещаются в разных сегментах, имеются ограничения на размер массивов;

Huge – сверхбольшая; код и данные имеют дальний тип и размещаются в разных сегментах;

Flat – плоская; код и данные имеют ближний тип и располагаются в одном 32-битном сегменте (сплошная модель памяти).

Директива .code – определяет начало или продолжение сегмента кода.

Директива .data – определяет начало или продолжение сегмента инициализированных данных.

Директива .const – определяет начало или продолжение сегмента постоянных данных.

Директива .data? – определяет начало или продолжение сегмента неинициализированных данных. Также используется для определения данных типа near.

Директива .stack [размер] – определяет начало или продолжение сегмента стека. Параметр [размер] задает размер стека.

  1.  Директивы резервирования памяти и инициализации данных.

Эти директивы являются указаниями транслятору на выделение определенного объема памяти.

db – резервирование памяти для данных размером 1 байт.

dw – резервирование памяти для данных размером 2 байта.

dd – резервирование памяти для данных размером 4 байта.

df и dp – резервирование памяти для данных размером 6 байтов.

dq – резервирование памяти для данных размером 8 байтов.

dt – резервирование памяти для данных размером 10 байтов.

dup – директива повторения. Используется для объявления цепочки данных в памяти. Применяется эта директива следующим образом:

<имя_переменной> k dup(n1, … ni)

где: k – константное выражение;

      n1,…,ni – любой операнд;

Пример:

.data

  a db 255

  b dw 65535

  d 2 db dup(1,3 dup(2,’A’));эта область памяти будет инициализирована

                                             ;следующим образом:

1

2

A

2

A

2

A

1

2

A

2

A

2

A

  1.  Прочие директивы.

Директива IDEAL – определяет режим Ideal (режим стандартной сегментации).

Директива MASM – определяет режим MASM (режим упрощенной сегментации).

Директива .startup – директива начальной инициализации (в частности, инициализирует сегментные регистры).

Директива .exit 0 – генерирует код возврата (в данном случае 0 – код стандартного завершения программы). Если код возврата не указан, то возвращается значение из регистра al.

Директива end [точка_входа] – определяет конец исходного текста программы. Параметр [точка_входа] должен ссылаться на метку или имя процедуры, с которой программа начинает выполнение.

Директива EQU – определяет значение, которое может быть использовано для подстановки в других командах. Синтаксически директива EQU применяется следующим образом:

<Имя_константы> EQU 10

<Имя_константы> может быть представлено любым допустимым в ассемблере  именем.  Теперь, если в какой-нибудь команде или директиве будет использоваться слово <Имя_константы>, ассемблер подставит  значение 10.

Например:

num EQU 10

str1 db num dup(?); эквивалентно str1 db 10 dup (?)

mov CX,num

Директива = –  по применению подобна директиве EQU, но в отличие от нее допускает переопределение в процессе выполнения программы. Например:

len = 1

len = len + 5

a EQU 4

len = len – a

a = a+1; Ошибка!

Пример использования стандартных директив сегментации:

IDEAL

data SEGMENT para public ‘data’     ;начало сегмент данных

  a db 5

  b db 7

data ENDS

stk SEGMENT stack                           ;начало сегмент стека

  db 256 dup(?)

stk ENDS

code SEGMENT para public ‘code’   ;начало сегмента кода

start:                                                     ;точка входа в программу

  ASSUME CS:code, DS:data, SS:stk;привязывание сегментных

                                                            ;регистров к сегментам

  mov AX,data                                    ;адрес сегмента данных необходимо

  mov DS,AX                                      ;явно записывать в регистр DS

  mov DL,[a]

  mov DH,[b]

  add DL,DH                                       ;сложение содержимого AL и AH

  .exit 0

code ENDS                                          ;конец сегмента кода

END start                                             ;конец программы

Использование упрощенных директив сегментации:

MASM

.model small

.data                                                      ;начало сегмент данных

  a db 5

  b db 7

.stack 256                                             ;начало сегмент стека

.code                                                    ;начало сегмента кода

  .startup

  mov DL,[a]

  mov DH,[b]

  add DL,DH                                       ;сложение содержимого AL и AH

  .exit 0

END                                                    ;конец программы

Задание:

1. Используя директивы эквивалентности EQU и =, скопировать строку, заданную в памяти, в другую, предварительно выделив под нее неинициализированную область памяти. При написании программы использовать стандартные директивы сегментации.

2. Преобразовать строку символов в памяти используя, директивы эквивалентности EQU и =, таким образом, чтобы ее можно была прочитать в обратном направлении (справа – налево). При написании программы использовать упрощенные директивы сегментации.

Лабораторная работа №4.

Команды пересылки. Арифметические операции с данными.

Цель работы: изучить команды пересылки. Научиться выполнять арифметические операции и отслеживать операции над беззнаковыми числами и числами со знаком.

Теоретическая часть.

Команда MOV.

Команда MOV - предназначена для пересылки байта или слова. Пересылаемая величина берётся из регистра области памяти или команды, а записывается в регистр или область памяти.

mov op1, op2.

На место первого операнда пересылается значение второго. Флаги не меняются.

Таблица 1.

Допустимые типы операндов команды MOV.

op1

op2

r8

r8, m8, i8

m8

r8, i8

r16

r16, m16, i16, sr

m16

r16, i16, sr

r32

r32, m32, i32

m32

r32, i32

sr

r16, m16

Размер пересылаемой величины определяется по типу операндов. Размеры операндов должны совпадать.

Определение смещения данных в сегменте.

  OFFSET <op> .

  Выдает число байт между выражением и началом сегмента, в котором оно определено.

  <op> - может быть меткой,  именем сегмента или переменной. Для получения правильного смещения при доступе к переменным в сегментах или в группах,  используйте префикс переопределения сегмента ':' для того, чтобы команда OFFSET вычисляла смещение относительно начала группы или сегмента.

Команда XCHG.

Команда XCHG op1, op2 меняет местами значения своих операндов (они должны быть либо байтами, либо словами). Флаги не меняются.

Таблица 2.

Допустимые типы операндов команды XCHG.

op1

op2

r8

r8, m8

m8

r8

r16

r16, m16

m16

r16

r32

r32, m32

m32

r32

Арифметические команды.

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

Если складываются беззнаковые числа, смотрят CF, знаковыеOF. При операциях сложения и вычитания меняются ZF и SF.

Команды сложения и вычитания ADD и SUB.

ADD op1, op 2   ; сложение

SUB op 1, op 2    ; вычитание

Таблица 3.

Допустимые типы операндов для команд ADD и SUB.

op1

op2

r8

r8, m8, i8

m8

r8, i8

r16

r16, i16, m16

m16

r16, i16

r32

r32, i32, m32

m32

r32, i32

Команда ADD op 1, op 2 складывает операнды и записывает их сумму на место первого: ор1:=ор1+ор2. Команда SUB op 1, op 2 из первого вычитает второй и полученную разность записывает на место первого: ор1:=ор1-ор2. Если первый операнд байт (слово), то и второй - байт (слово).

Команды INC и DEC.

INC <op>   ( = ADD <op>, 1 или ор:=ор+1), увеличение операнда на 1

DEC <op>  ( = SUB <op>, 1  или ор:=ор-1), уменьшение операнда на 1.

Эти команды экономят память и выполняются быстрее. Допустимые типы операндов: r8, m8, r16, m16, r32, m32.

Команды сложения с учетом переноса (ADC) и вычитания с учетом займа (SBB).

ADC op1, op2 – сложение с учетом переноса

SBB op1, op2 – вычитание с учетом займа

Эти команды аналогичны командам обычного сложения, вычитания (add и sub) за одним исключением. В команде ADC к сумме операндов добавляется еще значение флага переноса, а в команде SBB из разности операндов вычитается значение флагов CF.

Команды ADD, SUB, ADC, SBB одинаково работают как со знаковыми, так и с беззнаковыми числами.

Команда изменения знака операнда NEG.

NEG <ор1>    ; допустимые типы операндов - r8, m8, r16, m16, r32, m32.

Если число положительное, то будет отрицательным и наоборот. Если операнд занимает 1 байт и число равно –128, то нет знакового числа +128, аналогично с 32768. В данном случае команда не меняет операнд. В этом особом случае OF=1. При других операндах OF=0. При нулевом операнде CF=0, при других CF=1. Флаги SF и ZF меняются как обычно.

Команды умножения MUL, IMUL.

Команды умножения для знаковых и беззнаковых чисел выполняются по разному алгоритму.

mul <ор> – для беззнаковых чисел.

imul <ор> – для знаковых чисел.

Операнд, указываемый в команде – это лишь один из сомножителей. Он может находиться либо в регистре, либо в памяти, но не может быть непосредственным операндом. При умножении байтов, он берется из AL, при использовании слов из AX. Место нахождения результата умножения, заранее известно и поэтому в команде явно не указывается. Под результат отводится в два раза больше места, чем под сомножители.

Все команды умножения дают результат в удвоенном формате, что не всегда удобно обрабатывать, поэтому желательно знать, нужен ли двойной формат результата или нет. Это можно сделать с помощью флага переноса CF и флага переполнения OF, которые в обеих командах умножения, меняются синхронно и по следующему принципу: CF=OF=1 - произведение занимает двойной формат, CF=OF=0 – произведение занимает одинарный формат.

Команды деления DIV, IDIV.

DIV <op> - для беззнаковых чисел

IDIV <op> - для знаковых чисел

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

При делении слова на байт делимое обязательно находится в АХ, а делитель должен быть байтом. При делении двойного слова на слово делимое обязательно находится в паре регистров: DX – старшая часть, АХ – младшая часть, а делитель должен иметь размер слова.

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

Задание.

Написать программу, в которой необходимо сложить (вычесть, умножить, поделить) попарно элементы из двух массивов, а результат поместить в третий массив. Размерность элементов третьего массива должна обеспечивать корректность арифметической операции (если результат не умещается в выбранный тип операндов).

Лабораторная работа №5.

Команды безусловного и условного переходов.

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

Теоретическая часть.

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

JMP <op>

<op> – тем или иным способом указывает адрес перехода, указывая адрес той команды, которую должен выполнить следующей.

Прямой переход.

Прямой переход: JMP <метка>

В ПК имеется регистр IP, в котором хранится адрес следующей команды. Команда прямого перехода устроена, так что в ней указывается не адрес следующей команды, а разность между адресом команды и адресом команды перехода. Действие самой команды перехода заключается в прибавлении этой разности к текущему значению IP. Говоря точнее, относительный адрес перехода отсчитывается не от самой команды перехода, а от следующей за ним команды.

В зависимости от «расстояния» переходы бывают трех типов: короткие (SHORT), ближние (NEAR) и дальние (FAR). Тип перехода задается необязательным параметром инструкции JMP. Если тип не задан, по умолчанию используется тип NEAR.

Максимальная «длина» короткого перехода (то есть максимальное расстояние между текущим и целевым адресом) ограничена. Второй байт инструкции (операнд) содержит только одно 8-разрядное значение, поэтому целевой адрес может быть в пределах от -128 до 127 байтов. При переходе выполняется знаковое расширение 8-разрядного значения и его добавление к текущему значению Е(IР).

«Длина» ближнего перехода (NEAR) зависит только от режима процессора. В реальном режиме меняется только значение IP, поэтому мы можем «путешествовать» только в пределах одного сегмента (то есть в пределах 64 Кб); в защищенном режиме используется EIP, поэтому целевой адрес может быть где угодно в пределах 4 Гб адресного пространства.

Переход типа FAR модифицирует кроме IP еще и сегментный регистр CS, который используется при вычислении фактического адреса памяти. Поэтому команда перехода должна содержать новое значение CS.

Команды сравнения и условного перехода.

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

- сначала сравнивают две величины, в результате чего соответствующим образом формируются  флаги ZF, OF;

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

CMP op1,op2

Таблица 1.

Допустимые типы операндов команды CMP.

op1

op2

r8

r8, m8, i8

m8

r8, i8

r16

r16, i16, m16

m16

r16, i16

r32

r32, i32, m32

m32

r32, i32

Jxx <метка>,

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

Команды условного перехода можно разбить на  3 группы: в первую входят команды, которые ставятся после команд сравнения. В их мнемокодах с помощью определенных букв  описывается тот исход сравнения, при котором надо делать переход.

Je (равно)

Jn (не равно)

Jg (больше для чисел со знаком)

Jl (меньше для чисел со знаком)

Ja (больше для чисел без знака)

Jb (меньше для чисел без знака)

После сравнения чисел со знаком и сравнения чисел без знака надо реагировать на разные флаги.

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

Приведем название всех команд перехода используемых после команд сравнения / указаны синонимы.

Таблица 2.

Команды условного перехода, применяемые после команды сравнения.

Мнемокод

Условие для перехода после cmp op1,op2

Состояние флагов для перехода

Je

Op1=op2

ZF=1

Jne

Op1<>op2

ZF=0

Для чисел со знаком

Jl/ Jnge

Op1<op2

SF<>OF

Jle/ Jng

Op1<=op2

SF<>OF ZF=1

Jg/ Jnle

Op1>op2

SF=OF ZF=1

Jge/ Jnl

Op1>=op2

SF=OF

Для чисел без знака

Jb/ Jnae

Op1<op2

CF=1

Jbe/ Jna

Op1<=op2

CF=1  ZF=1

Ja/ Jnbe

Op1>op2

CF=0 ZF=1

Jae/ Jnb

Op1>=op2

CF=0

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

Таблица 3.

Команды условного переходы, реагирующие на состояние регистра флагов.

Мнемокод

Условный переход

Jz

ZF=1

Js (знак)

SF=1

Jc (перенос)

CF=1

Jo (переполн)

OF=1

Jp (четность)

PF=1

Jnz

ZF=0

Jns (знак)

SF=0

Jnc (перенос)

CF=0

Jno (переполн)

OF=0

Jnp (четность)

PF=0

Следующие пары эквивалентны je - jz; jb - jc; jnb - jnc.

В третью группу входит команда  JCXZ <метка> переход на <метка>, если CX=0.

Все команды условного перехода осуществляют только короткий переход это примерно 30-40 команд (-128…127).

Задание.

Написать программу, реализующую поиск подстроки в строке.

Пример кода задания строки и подстроки:

.model small

.data

  st1 db 'пример'                ; задаем строку

  len1 equ $-stud1              ; длина строки

  st2 db 'им'                        ; задаем подстроку

  len2 equ $-stud2              ; длина подстроки

  rez db 0                            ; результат «1» если подстрока найдена, «0»

                                           ;если нет (изначально «0»)

.code

.startup

…                                    ; код программы

.exit 0

end

Лабораторная работа №6.

Циклы.

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

Теоретическая часть.

Команды сравнения и условного перехода.

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

- сначала сравнивают две величины, в результате чего соответствующим образом формируются  флаги ZF, OF;

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

CMP op1,op2

Таблица 1.

Допустимые типы операндов команды CMP.

op1

op2

r8

r8, m8, i8

m8

r8, i8

r16

r16, i16, m16

m16

r16, i16

r32

r32, i32, m32

m32

r32, i32

Эквивалентна команде sub за одним исключением вычисленная разность op1-op2 никуда не записывается поэтому единственный главный эффект это установка флагов характеризующих полученную разность или характеризующих сравниваемые величины.

Jxx <метка>,

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

Команды условного перехода можно разбить на  3 группы: в первую входят команды, которые ставятся после команд сравнения. В их мнемокодах с помощью определенных букв  описывается тот исход сравнения, при котором надо делать переход.

Je (равно)

Jn (не равно)

Jg (больше для чисел со знаком)

Jl (меньше для чисел со знаком)

Ja (больше для чисел без знака)

Jb (меньше для чисел без знака)

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

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

Приведем название всех команд перехода используемых после команд сравнения / указаны синонимы.

Таблица 2.

Команды условного перехода, применяемые после команды сравнения.

Мнемокод

Условие для перехода после cmp op1,op2

Состояние флагов для перехода

Je

Op1=op2

ZF=1

Jne

Op1<>op2

ZF=0

Для чисел со знаком

Jl/ Jnge

Op1<op2

SF<>OF

Jle/ Jng

Op1<=op2

SF<>OF ZF=1

Jg/ Jnle

Op1>op2

SF=OF ZF=1

Jge/ Jnl

Op1>=op2

SF=OF

Для чисел без знака

Jb/ Jnae

Op1<op2

CF=1

Jbe/ Jna

Op1<=op2

CF=1  ZF=1

Ja/ Jnbe

Op1>op2

CF=0 ZF=1

Jae/ Jnb

Op1>=op2

CF=0

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

Таблица 3.

Команды условного переходы, реагирующие на состояние регистра флагов.

Мнемокод

Условный переход

Jz

ZF=1

Js (знак)

SF=1

Jc (перенос)

CF=1

Jo (переполн)

OF=1

Jp (четность)

PF=1

Jnz

ZF=0

Jns (знак)

SF=0

Jnc (перенос)

CF=0

Jno (переполн)

OF=0

Jnp (четность)

PF=0

Легко заметить, что следующие пары эквивалентны je - jz; jb - jc; jnb - jnc.

Команды цикла.

Пусть некоторую группу команд требуется повторить n число раз (n>0)

Тогда на Ассемблере этот цикл можно реализовать

    mov CX,n

  M:

    dec CX

    cmp CX,n

    jne M

Как видно в конце циклов применяется одна и та же тройка команд.

Была введена специальная команда, которая объединяет действие этих команд.

LOOP <метка>

С командой LOOP программа выглядит компактной и работает быстрее. Однако необходимо учитывать особенности команды LOOP, чтобы в качестве счетчика обязательно использовался СХ при другом регистре применять нельзя. Начальное значение СХ должно быть присвоено до цикла, причем тому регистру надо присвоить столько, сколько должен повторяться этот цикл.

Поскольку команда LOOP ставится в конце цикла, то тело цикла хотя бы раз выполняется, поэтому для случая СХ=0 применяется команда условного перехода JCXZ  M1.

Именно для осуществления такого перехода и была введена JCXZ, в других  случаях она используется редко. Команда LOOP реализует только короткий переход, поэтому расстояние от нее до метки не должно превышать 128 байт (30-40 команд). Если цикл содержит больше команд тогда команду LOOP использовать нельзя и надо реализовать цикл по иному.

Задание:

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

Лабораторная работа №7.

Записи и структуры.

Цель работы: научится организовывать записи и структуры и работать с ними.

Теоретическая часть.

Структуры.

Структура – составной объект, занимающий несколько соседних областей памяти. Компоненты структуры называются полями. Они могут быть разного типа, (т.е. разного размера). Оно может быть byte, word и т.д. Поля именуются. Доступ к полям осуществляется по именам. Прежде чем использовать структуру, надо описать ее тип.

Описание типа структуры выглядит:

<имя типа> STRUC

<опис. поля>

……

<опис. поля>

<имя типа> ENDS

Описание типа открывает STRUC, где указывается имя, которое дали имени структуры. Это же имя обязательно должно быть повторено в директиве ENDS, оканчивающей структуру.  Между этими двумя директивами может быть указано любое число директив описывающих поля структуры. Каждое поле описывается одной директивой. Имя, указанное в такой директиве считается именем соответствующего поля структуры.

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

Описание переменных структур.

После того как описан тип структуры, можно определять в программе переменную этого типа. Такие переменные называются переменными структурами или просто структурами и описываются они с помощью следующих директив:

<имя структуры> <имя типа> <нач. значение…>

Каждое начальное значение – это или знак ‘?’, выражение или пусто:

Указанное начальное значение должно умещаться в размер поля, иначе будет зафиксирована ошибка.

Правило задания полей.

  1.  Если в качестве начального значения указан ‘?’, то соответствующее поле не получит ни какого начального значения.
  2.  Если в качестве начального значения указано выражения или строка, то оно становится начального значением поля.
  3.  Если не указано, то возможно 2 случая:
    1.  Если при описании структуры указано какое-то значение по умолчанию, то оно становится начальным значением этого поля данной переменной.
    2.  Если же в описании типа не указано имя по умолчанию, то это поле данной переменной не получит ни какого начального значения.
  4.   При задании начального знач. полей возможны сокращения: если в уголках не указываются начальные значения для нескольких последних полей, т.е. в конце стоит несколько запятых подряд, то эти запятые можно опустить. Однако в начале или в середине запятые пропускать нельзя.

Записи. Работа с записями.

В Ассемблер есть средства для работы с упакованными данными (записями). Запись - упакованная структура, когда поля занимают не отдельные байты, а части бита, где каждое поле – группа соседних битов.

Между полями не должно быть промежутков, не относящихся к полям.

Сумма размеров всех полей записи называется размером записи.

Если размер записи меньше либо равен восьми, то под запись Ассемблер отводит 1 байт, если от 9 до 16 слово и т.д. Если поле занимает не всю область (байт, слово и т.д.), то они приписываются к младшим адресам, а левые биты области считаются не относящимися к записи. Поля получают имена.

<имя записи> record <поле, …>

поле = <имя поля> : <размер>  [<нач. значение>]

При описании типа записи поля перечисляются слева направо. Для каждого поля обязательно указывается имя и через двоеточие размер в битах. Имена полей должны отличаться от других имен используемых в программе. При описании поля может быть указан знак равно. Значение этого поля по умолчанию (это значение должно указываться в размер поля). Если такое значение не указано, то оно по умолчанию считается равным 0. Левые биты области памяти, не относящиеся к записи равны 0.

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

Переменные записи.

Для описания такой переменной в программу необходимо поместить структуру следующего вида:

начальное значение константное выражение, знак вопроса или пусто.

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

Работа с полями записей.

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

Width ор (<имя поля или записи>, <имя типа записи>)

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

Оператор MASK ор (<имя поля или записи>, <имя типа записи>)

Значением маска в байт или слово в зависимости от размера записи, содержащая единицы в тех разрядах, которые принадлежат указанному полю или всем полям записи в остальных разрядах. Оператор Mask используется при выделении полей записи.

Задание.

Написать программу, вычисляющую средний балл студентов, по курсу Системное Программирование, группы.

Структура класса Student: 1) FIO - char, 2) Otsenka – dw.

Лабораторная работа №8.

Работа со стеком.

Цель работы: изучить назначение стека и работу с ним. Научиться использовать команды PUSH и POP.

Теоретическая часть.

Стек.

Стек – область памяти работа, с которым ведётся по следующему принципу: последний пришёл, первый ушёл. LIFO (т.е. элемент записанный последним считывается из него первым).

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

В PC-совместимых компьютерах нет аппаратного стека, поэтому данные стека хранятся в памяти. Для знания текущего положения вершины стека используется регистр SP, в нём хранится адрес той области памяти, в которой находится элемент, записанный в стек последним. Более точно в SP находится смещение этой области, т.е. её адрес, отсчитанный от начала сегмента стека. Поэтому абсолютный адрес вершины стека задаётся парой регистров SS:SP (SS:ESP). Элементы стека могут иметь любой размер (байт, слово, … ), однако имеющиеся в языке ассемблера команды записи в стек и считывания из него работают со СЛОВАМИ. Обработка байтов, и т.д. подгоняется под обработку слов.

Следует различать сегмент стека и стек (содержание стека) если первый термин означает область памяти, которую потенциально могут занять данные стека, то второй термин означает совокупность тех данных, что в текущий момент хранятся в стеке. Причём те данные, которые расположены выше SP, считаются не относящимися к стеку.

Чаще всего не задаются начальные значения для области памяти. Поэтому при описании сегмента стека указывается лишь то, сколько байтов отводится под стек, т.е. используют директиву db конструкцию dup с указанием количества байт:

        .stack  k

Стековые команды.

Все стековые команды будут работать правильно, если регистр SS  указывает на начало сегмента стека, а регистр SP на вершину стека. Если в этих регистрах записано что-то иное, то действие стековых команд непредсказуемо.

PUSH op – запись слова в стек.

Флаги не меняет. opr16, m16, r32, m32, sr.

Сначала значения регистра  SP уменьшаются на два, т.е. SP сдвигается вверх и после этого в эту область памяти записывается операнд.

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

POP op - чтение слова из стека

Нельзя использовать CS (остальное, как и у PUSH).  Команда считывания слова из стека и присвоения его указанному операнду.

Более точно: слово из памяти, на которое указывает пара регистров SS:SP пересылается в операнд, а затем SP увеличивается на два, т.е. сдвигается вниз.

Запись и чтение регистра флагов.

PUSHАзапись.

POPАчтение.

В стек записывается содержимое регистров флагов FLAGS при этом регистр флагов не меняется, а по команде POPА из стека считывается слово и оно заносится в регистр FLAGS.

Эти команды используются для сохранения текущих состояний флагов и последующего его восстановления.

Регистры помещаются в стек в следующем порядке (сверху вниз):

(Е)АХ, (Е)СХ, (E)DX, (E)BX, (E)SP, (E)BP, (E)SI, (E)DI

Рассмотрим небольшой пример:

    pusha          ;поместить в стек все регистры общего назначения

      …              ;некоторые действия, модифицирующие

      …              ;значения регистров

    рора            ;восстанавливаем все регистры

Некоторые приемы работы со стеком.

  1.  Сохранение регистров.

Два вложенных цикла.

mov CX,60000

m:

  push CX

  mov CX,60000

  m1:

     

  loop m1

  pop CX

loop m

  1.  Пересылка данных через стек.

;ES = DS

push DS

pop ES

  1.  Проверка на выход за пределы стека.

Следует понимать, что PUSH и POP не осуществляют проверку на выход за пределы стека, если стек пуст и применяется команда чтения из стека, то ошибка не будет фиксирована, а будет считано слово, следующее за сегментом стека, аналогично не будет зафиксирована ошибка, если будет записано слово, когда стек уже полон.

Эти проверки можно осуществить следующим образом:

Если SP=0 стек полон

Если SP=N, где N-размер стека в байтах - стек пуст

  1.  Очистка, восстановление стека.
    1.  Выполнить столько же раз как pop.
    2.  add SP,10
    3.  Запомнить старое значение SP, а потом его восстановить.

mov BX, SP

mov SP,BX

  1.  Доступ к элементам стека.

Иногда приходится очищать стек, т. е. удалять из него несколько последних элементов, никуда их не переписывая, это можно сделать, выполнив нужное число раз команду POP. Но это можно сделать гораздо проще.

Если мы записали в стек N слов, то значение SP уменьшилось на 2*N то для того чтобы восстановить значение регистра SP к нему нужно прибавить 2*N.

Регистр SP регистр общего назначения, поэтому может использоваться в арифметических операциях.

add SP,2*N; очистка стека от N слов

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

Задание.

Написать программу, преобразующую число в строку, используя стек (блок-схема алгоритма преобразования числа в строку приведена на Рис. 1.).

Рис. 1. Блок-схема алгоритма преобразования числа в строку.

Лабораторная работа №9.

Прерывания.

Цель работы: научиться работать с прерываниями DOS, осуществлять посимвольный ввод строки, а также вывод ее на экран.

Теоретическая часть.

INT 21h – вызов функции DOS.

Для вызова функции DOS должно быть выполнено:

  1.  занести номер функции в регистр АН, а если требуется – номер подфункции в регистр AL.
  2.  загрузить остальные регистры необходимой информацией.
  3.  если необходимо, сформировать необходимые буфера и области данных.

Ввод символа со стандартного устройства ввода STDIN.

По умолчанию – клавиатура.

Вход: АН = 1.

Выход: AL = символу, прочитанному  с устройства STDIN.

Описание: читает символ с STDIN и отображает его на STDOUT.

При вводе ожидает готовности STDIN, обычно – нажатие клавиши на клавиатуре.

Пример:

mov AH, 1

int 33

Клавиши не входящие в набор ASCII: 1-ое обращение вернет AL = 0, а 2-ое – расширенный ASCII-код клавиши.

Вывод символа на стандартное устройство вывода STDOUT.

Вход: AH = 1.

Выход: AL = символ для вывода.

Описание: выводит символ на STDOUT (экран).

Ввод символа со стандартного устройства ввода без «эха».

Вход: АН = 8.

Выход: AL = символ присланный с STDIN.

Описание: читает символ с STDIN и не отображает его на STDOUT.

  1.  При вводе ожидает готовности STDIN.
  2.  Клавиши не входящие в набор ASCII: 1-ое обращение вернет AL = 0, а 2-ое – расширенный ASCII-код клавиши.

Вывод строки на стандартное устройство вывода.

Вход: АН = 9.

Выход: (DS:DX) – адрес выводимой строки.

Описание: строка, адрес которой записан в (DS:DX) и оканчивающаяся символом $ выводится на STDOUT.

  1.  Символ «забоя» выводится как возврат курсора на шаг.
  2.  Для перевода курсора на новую строку, вводимая строка должна содержать символы 13 и 10.
  3.  Строку содержащую $ надо выводить другими способами.

Буферизированный ввод со стандартного устройства ввода.

Вход: АН = 10,

         (DS:DX) – адрес буфера ввода.

Выход: буфер содержит вводимую строку.

Описание: перед вызовом функции 1-ый байт буфера должен содержать его размер (1-254). Символы вводятся с STDIN и помещаются в буфер до тех пор, пока не встретится символ Enter или не будет введено n-1 символов, во 2-ой байт буфера помещается фактическая длинна строки не считая завершающего кода 13, который заносится последним кодом строки.

Задание:

Используя директивы прерывания, осуществить ввод строки с клавиатуры. Затем выполнить разбиение введенной строки на массивы по следующим категориям: а) буквы нижнего регистра; б) буквы верхнего регистра; в) цифры; г) другие символы.

 

Лабораторная работа №10.

Строковые команды.

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

Теоретическая часть.

Строковые команды могут обращаться к памяти увеличивать или уменьшать регистр указатель. Их можно использовать как при работе с массивами буферами данных и любыми типами строк байт или слов.

Рассмотрим две различные по функциональному назначению группы строковых команд

Строковые команды для перемещения данных LODS, STOS, MOVS.

Две команды для поиска и сравнения данных: SCAS,CMPS.

Использование флага направления DF.

При выполнении строковой команды в зависимости от флага направления соответствующие регистры указатели SI и DI уменьшаются или увеличиваются. Если флаг направления=0 то указатели будут увеличиваться.

CLD  

Если флаг направления = 1, то указатели будут уменьшаться.

STD

Данные команды не имеют аргументов.

Строковые команды перемещения данных LODS, STOS, MOVS.

Во многом аналогичны команде MOV но выполняют большее число функций чем MOV и работают быстрее.

LODS – загружает байт или слово в регистр AX изменяет регистр SI.

Разделяют LODSB - байт

                  LODSW - слово

LODSB - загружает байт адресуемый DI:SI в регистр AL и увеличивает или уменьшает SI в зависимости от флага направления.

Пример:

.data

  mas db ‘ABCDEF’

  len EQU $-mas

.code

  .startup

  lea SI,mas

  cld

  lodsb    ;AL=’A

Команда LODSW аналогична LODSB, но она сохраняет в AX слово, адресуемое парой регистров DS:SI, а значение регистра SI увеличивается или уменьшается в зависимости от флага направления DF.

Команда STOS - дополнение команды LODS, она записывает значение из аккумулятора в область памяти, на которую указывает  ES:DI, а затем увеличивает или уменьшает регистр DI.

STOSB - записывает байт из AL в область памяти ES:DI, а затем увеличивает или уменьшает регистр DI на 1 в зависимости от флага DF.

STOSW - записывает байт из AХ в область памяти ES:DI, а затем увеличивает или уменьшает регистр DI на 2 в зависимости от флага DF.

MOVS - аналогична LODS и STOS, если их объединить в одну. Эта команда считывает байт или слово по адресу DS:SI, а затем записывает по адресу ES:DI. Слово или байт при этом не передается через регистры, поэтому значение АХ не изменяется. Команда MOVS занимает 1 байт.

Пример:

.data

  mas dbABCDEF

  len EQU $-mas

  masb db len dup(?)

.code

  .startup

  lea SI, mas

  lea DI, masb

  mov CX, len

  mov BX, DS

  mov ES, BX

  cld

  M:

     movsb

  loop M

Префиксы  повторения.

Переместить весь массив с помощью одной строковой команды можно с помощью строковых команд с префиксом REP.

REP - это префикс команды, который изменяет работу последней команды. REP указывает что последнюю команду надо повторять до тех пор пока содержимое СХ=0. Если СХ=0 в начале выполнения, то команда не выполняется.

Пример:

.data

  mas db ‘ABCDEF’

  len EQU $-mas

  masb db len dup(?)

.code

  .startup

  lea SI, mas

  lea DI, masb

  mov CX, len

  mov BX, DS

  mov ES, BX

  cld

  REP movsb

Эта команда будет перемещать len байт из строки с адресом DS:SI в память начинающуюся с адреса ES:DI

Каждое повторение с помощью префикса строковой команды выполняется быстрее чем выполнение одной строковой команды. Это позволяет получить быстрый способ чтения из памяти записи и копирования.  Префикс REP можно использовать в командах  LODS STOS.

Поиск данных с помощью строковых команд.

Команда SCAS используется для просмотра памяти и поиска совпадения или не совпадения с конкретным значением размером байт или слово, как и строковые команды имеет SCASB-байт, SCASW-слово.

SCASB-сравнивает содержимое AL с байтовым значением по адресу ES:DI устанавливая при этом флаги отражающие результат сравнения как CMP.

Как и при выполнении команды STOSB при выполнении SCASB увеличивается или уменьшается значение DI в зависимости от DF.

Команды сравнения.

Команда CMPS позволяет выполнить сравнение байтов или слов. При одном выполнении CMPS сравниваются две области памяти, а затем увеличиваются или уменьшаются SI,DI в зависимости от значения флага DF.

CMPS - можно рассматривать как аналог MOVS только вместо копирования происходит сравнение областей памяти.

CMPSB - сравнивает байт по адресу DS:SI с байтом по адресу ES:DI и увеличивает или уменьшает DI в зависимости от DF.

Задание.

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

Пример:

Дана строка: Lin1ux is32 th4e oper5at6ing 3sys2tem

Результат: Linux. is. the. operating. system.

Лабораторная работа № 11.

Подпрограммы.

Цель работы: изучить особенности организации подпрограмм в программе, научиться осуществлять вызов подпрограмм.

Теоретическая часть.

Подпрограмма является блоком команд, которые могут быть вызваны из другого места памяти. Вызов (CALL) подпрограммы подразумевает, что обязательно будет совершен возврат (RET) из подпрограммы. Это не переход, возврат из которого не требуется. В языке ассемблера термины процедура и подпрограмма взаимозаменяемы.

В языке ассемблера директивы PROC и ENDP отмечают начало и конец процедуры.

Вызов ближних процедур. 

Когда командой CALL вызывается процедура, находящаяся в том же самом сегменте кода, то используется способ, называемый ближним вызовом. Перед переходом к процедуре, команда CALL сохраняет текущее значение указателя команд IP в стеке. Затем в IP помещается смещение подпрограммы, заставляя процессор немедленно перейти к выполнению первой команды подпрограммы:

Вызывающая программа             подпрограмма

main PROC       sub1 PROC

  call sub1                   mov AX, 1

  inc AX                   …

  …           ret

main ENDP                sub1 ENDP

Вызов удаленной процедуры.

Когда вызывающая программа и подпрограмма находятся в разных сегментах кода, то используется дальний вызов. Перед переходом на подпрограмму команда call сохраняет текущее значение регистров CS и IP в стеке и затем загрузит смещение подпрограммы в регистр CS и смещение в IP. Исполнение начинается с нового адреса.

Вызывающая процедура   Подпрограмма

main PROC      sub1 PROC far

  call far PTR sub1       mov AX, 1

  inc AX          …

  …                    ret

main ENDP               sub1 ENDP

Сохранение регистров.

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

Локальные данные. 

Выделение места в сегменте данных неэффективно, так как они не

освободятся при завершении процедуры. Поэтому целесообразно использовать стек для хранения данных. Доступ к ним будет производиться с помощью конструкции [Bp+k].

Задание:

Написать подпрограмму, реализующую решение квадратного уравнения  ( ,). В качестве параметров должны передаваться множители a,b и c. Предусмотреть случаи, в которых дискриминант меньше нуля.

Лабораторная работа № 12.

Макросредства языка Assembler.

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

Теоретическая часть.

С помощью блоков повторения один раз описывается некоторый фрагмент программы, который затем многократно копируется макрогенератором. Но блок повторения можно использовать, только если эти копии должны быть расположены рядом друг с другом. Если фрагмент должен повторяться в разных местах программы, то в этом случае используются макросы: специальным образом описывается этот фрагмент программы (это и есть макрос) и ему дается имя, а затем в нужных местах программы выписывается ссылка на этот макрос (указывается его имя); когда макрогенератор просматривает текст программы и встречает такую ссылку, то он вместо нее подставляет в окончательный текст программы сам макрос – соответствующий фрагмент программы; и так делается для каждой ссылки на макрос, в каком бы месте программы она не встретилась.

Описание макроса называется макроопределением, ссылка на макрос – макрокомандой, процесс замены макрокоманды на макрос – макроподстановкой, а результат такой подстановки – макрорасширением.

Макрокоманда.

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

<имя макроса> <фактические параметры через ‘,’ и/или пробел>

Например:

.data

  z dw ?

  x dw 45

  y dw 600

sum MACRO A,B,C

  mov AX,B

  add AX,C

  MOV A,AX

ENDM

.code

  …

  sum z,x,y

  lea BX,z

  sum <word PTR [BX]>,x,y

Макрокоманды очень похожи на обычные команды и директивы. Но есть и отличия. Во-первых, вместо названия команды или директивы, являющегося служебным словом, в макрокоманде указывается имя макроса, которое придумал сам автор программы. Во-вторых, в макрокоманде параметры могут отделяться друг от друга, как запятыми, так и пробелами.

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

При записи параметров макрокоманд можно использовать те же макрооператоры ‘< >, !, %’, что и при записи фактических параметров БП.

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

Задание:

Написать макрос, реализующий вычисление a, при .


Начало

исло равно 0 ?

Делим на 10

Запись остатка

Конец

Да

Нет




1. Партии и партийные системы
2. Урал в период Великой Отечественной войны
3. Реферат з дисципліни- Реферат з дисципліни- Технологія зведення реконструкція та ремонт будів
4. Организация выездного мероприятия сотрудников фирмы на примере отеля Чайка
5. Крест на скале и А
6. Лекция2. Классификация религий
7. ОПРЕДЕЛЕНИЕ ПЛОТНОСТИ ТВЕРДОГО ТЕЛА ПРАВИЛЬНОЙ ФОРМЫ Принадлежности- тело цилин
8. Образование в XIX веке
9. Консервативная школьная политика
10. якої народності й тим більше нації
11. РАО Норильский никель
12. Алгоритмы интерпретации показателей кислотно-основного состояния
13. Мама купила 1 кг 200 г клубники
14. Курсовая работа Психологические аспекты нарушения пищевого поведения
15. Строительные машины Классификация строительных машин
16. Иностранные заимствования в лексике английского языка
17. технический прогресс в развитии производительных сил и возрастающее использование обществом географическо
18.  ПРОМЫШЛЕННОСТЬ РФ И ЕЕ ВЕДУЩАЯ РОЛЬ В РАЗВИТИИ ЭКОНОМИКИ СТРАНЫ
19. Філософська антропологія та її методичні принципи М
20. Разработка структуры локальной вычислительной сети многопрофильного предприяти