Лабораторная работа № 3
Программирование ветвлений и циклов
1 ЦЕЛЬ РАБОТЫ
Целью работы является закрепление знаний по командам условного и безусловного переходов и циклов на примере программ на языке ассемблера, а также приобретение навыков написания программ с циклами.
2 ОСНОВНЫЕ ТЕОРЕТИЧЕСКИЕ СВЕДЕНИЯ
2.1. Команды условного перехода
Команды передачи управления реализуют изменение естественного порядка выполнения команд программы. Их можно разделить на 3 подгруппы, описание которых приведено в приложении 1 [5]. В мнемонические обозначения команд условного перехода входят буквы, которые определяют условия в соответствии с таблицей 1 [1]. В этой таблице операнд “метка перехода” или “близкая метка” отражает тот факт, что метка помеченной команды должна находиться в пределах текущего сегмента кода и на относительном расстоянии от команды перехода >-128 и < 127 байтов. Ограничение (–128..127) байтов снято у процессоров, начиная с модели 80386, однако ограничение передачи управления в пределах текущего сегментного кода действует и в моделях PENTIUM.
Таблица 1
Мнемокоды команд условного перехода
Буква мнемокода
|
Условие
|
Тип операндов
|
Е
|
равно
|
любые
|
N
|
Не равно
|
любые
|
G
|
больше
|
Числа со знаком
|
L
|
меньше
|
Числа со знаком
|
А
|
Выше, в смысле “больше”
|
Числа без знака
|
В
|
ниже, в смысле “меньше”
|
Числа без знака
|
Решение о том, куда будет передано управление командой условного перехода, принимается на основании условия. Источниками таких условий могут быть:
-
любая команда, изменяющая состояние арифметических флагов (ниже эти флаги будут перечислены);
-
команда сравнения CMP.
Формат команды CMP:
CMP приемник, источник или CMP операнд1, операнд2.
Эта команда осуществляет вычитание (операнд1 - операнд2) или (приемник – источник), однако результат никуда не записывается, а только устанавливает флаги в соответствие с таблицей 2 [5].
Таблица 2
Значения флагов, устанавливаемые командой CMP
Сравниваемые операнды
|
Флаги
|
|
OF
|
SF
|
ZF
|
CF
|
Операнды без знака
Источник < приемник
|
Н
|
Н
|
0
|
0
|
Источник = приемник
|
Н
|
Н
|
1
|
0
|
Источник > приемник
|
Н
|
Н
|
0
|
1
|
Операнды со знаком
|
|
|
|
|
Источник < приемник
|
0/1
|
0
|
0
|
H
|
Источник = приемник
|
0
|
0
|
1
|
H
|
Источник > приемник
|
0/1
|
1
|
0
|
H
|
В этой таблице приняты следующие обозначения:
- “H” означает, что ‘не имеет значения” или иначе, на этот флаг операция не влияет;
- 0/1 означает, что флаг устанавливается или в 1 или в 0 в зависимости от значений операндов (отрицательные или положительные или разнознаковые операнды сравниваются).
Приведем еще одну таблицу 3 [1], в которой отражается действие команд условного перехода по значениям анализируемых этими командами флагов. В этой таблице через слеш ‘/’ перечисляются идентичные команды, действие которых совершенно одинаково, и применение конкретной из них зависит от пристрастий программиста. Наличие идентичных команд объясняется тем фактом, что если число_1 >число_2, то можно с уверенностью утверждать, что число_1 не (меньше или равно) число_2.
Таблица 3
Логика команд условного перехода
Тип операндов
|
Мнемокод команды
|
Критерий перехода
|
Значения флагов для перехода
|
любые
|
JE
|
Операнд_1=операнд_2
|
ZF=1
|
Любые
|
JNE
|
Операнд_1<>операнд_2
|
ZF=0
|
Со знаком
|
JL/JNGE
|
Операнд_1<операнд_2
|
SF<>OF
|
Со знаком
|
JLE/JNG
|
Операнд_1<=операнд_2
|
SF<>OF или ZF=1
|
Со знаком
|
JG/JNLE
|
Операнд_1>операнд_2
|
SF=OF и ZF=0
|
Со знаком
|
JGE/JNL
|
Операнд_1>=операнд_2
|
SF=OF
|
Без знака
|
JB/JNAE
|
Операнд_1<операнд_2
|
CF=1
|
Без знака
|
JBE/JNA
|
Операнд_1<=операнд_2
|
CF=1 или ZF=1
|
Без знака
|
JA/JNBE
|
Операнд_1>операнд_2
|
CF=0 и ZF=0
|
Без знака
|
JAE/JNB
|
Операнд_1=>операнд_2
|
CF=0
|
2.2. Команда безусловного перехода
Безусловный переход в программе на ассемблере производится по команде JMP. Полный формат команды следующий:
JMP [модификатор] адрес_перехода.
Адрес перехода может быть либо меткой, либо адресом области памяти, в которую предварительно помещен указатель перехода.
В системе команд микропроцессора существуют несколько кодов машинных команд безусловного перехода. Их различия определяются дальностью перехода и способом задания целевого адреса. Дальность перехода определяется местоположением операнда адрес_перехода. Этот адрес может находиться в текущем сегменте кода или в некотором другом сегменте. В первом случае переход называется внутрисегментным или близким, а во втором случае – межсегментным или дальним.
Внутрисегментный переход предполагает, что изменяется только содержимое регистра IP. Можно выделить три варианта внутрисегментного перехода: прямой короткий, прямой, косвенный.
Прямой короткий внутрисегментный переход применяется, когда расстояние от команды JMP до адреса перехода не более чем 127 байтов выше или ниже. В этом случае транслятор языка формирует машинную команду безусловного перехода длиной 2 байта: первый байт – код операции, второй байт – смещение. В коде операции заложена информация о том, что второй байт интерпретируется как смещение. Здесь нужно отметить одну особенность транслятора ассемблера – он является однопроходным, иными словами, машинный код программы получается за один просмотр команд от начала программы до ее окончания. В связи с этим обстоятельством, если безусловный переход должен происходить на адрес до команды JMP, то транслятор может легко вычислить смещение. Если же переход короткий, но на метку после команды JMP, то транслятору нужно подсказать, что он должен сформировать команду безусловного короткого перехода. С этой целью в команде JMP используется модификатор SHORT PTR (полностью - SHORT POINTER или короткий указатель):
JMP SHORT PTR M1
. . . . . . не более 35-40 команд
M1:
MOV AL, 34H.
Прямой внутрисегментный переход отличается от короткого тем, что длина машинной команды составляет 3 байта, в которой два последних байта интерпретируются как смещение. Нетрудно определить, что в этом варианте можно осуществлять переход в пределах 64 Кбайт памяти относительно следующей за JMP команды.
Косвенный внутрисегментный переход означает, что в команде JMP указывается не сам адрес перехода, а место, где этот адрес записан. Например:
LEA BX, M1
JMP BX
. . . . . .
M1: MOV AL, 34H
Или
DSEG SEGMENT PARA PUBLIC ‘DATA’
ADDR DW M1
. . . . . . . .
CSEG SEGMENT PARA PUBLIC ‘CODE’
ASSUME CS:CSEG, DS:DSEG, SS:STACK
. . . . . .
JMP ADDR.
В командах косвенного перехода рекомендуется применять модификатор NEAR, т.к. при косвенном переходе не всегда транслятору удается определить, находится адрес перехода в текущем сегменте кода или нет.
Команда прямого межсегментного перехода имеет длину 5 байт, из которых 2 байта составляет смещение адреса перехода, а другие 2 байта – значение сегментной составляющей (CS) того кодового сегмента, где находится адрес перехода. Например:
SEG1 SEGMENT PARA PUBLIC ‘CODE’
ASSUME CS:SEG1, DS:DSEG1, SS:STACK
. . . . . .. .
JMP FAR PTR M2
. . . . . ..
M1 LABEL FAR
. . . . . . ..
SEG1 ENDS
SEG2 SEGMENT PARA PUBLIC ‘CODE’
ASSUME CS:SEG2, DS:DSEG2, SS:STACK
. . . . . . .. .
M2 LABEL FAR
JMP M1.
Во втором случае FAR необязательно, но если модификатор примените, то ошибки не будет. Необязательность объясняется тем, что метка находится раньше команды перехода и транслятор может самостоятельно определить, что переход является межсегментным.
Команда косвенного межсегментного перехода в качестве операнда имеет адрес области памяти, в которой содержится смещение и сегментная часть целевого адреса перехода. Например:
DSEG SEGMENT PARA PUBLIC ‘DATA’
ADDR DD M1
. . . . . . . .
CSEG SEGMENT PARA PUBLIC ‘CODE’
ASSUME CS:CSEG, DS:DSEG, SS:STACK
. . . . . .
JMP ADDR
CSEG ENDS
CS1 SEGMENT PARA PUBLIC ‘CODE’
ASSUME CS:CS1, DS:DS1, SS:ST1
M1 LABEL FAR
MOV AX, BX
. . . .. ..
CS1 ENDS.
Одним из вариантов рассматриваемого перехода является косвенный регистровый межсегментный переход. Адрес перехода в этом варианте указывается в регистре, что удобно при программировании динамических переходов, когда конкретный адрес перехода определяется в процессе выполнения программы и помещается в регистр:
DSEG SEGMENT PARA PUBLIC ‘DATA’
ADDR DD M1
. . . . . . . .
CSEG SEGMENT PARA PUBLIC ‘CODE’
ASSUME CS:CSEG, DS:DSEG, SS:STACK
. . . . . .
LEA BX, ADDR
JMP DWORD PTR [BX]
. . . . . .
CSEG ENDS
CS1 SEGMENT PARA PUBLIC ‘CODE’
ASSUME CS:CS1, DS:DS1, SS:ST1
M1 LABEL FAR
MOV AX, BX
. . . . . . . .
CS1 ENDS.
В двойное слово ADDR помещается смещение адреса и начала сегмента кода, включающего метку M1, в нашем случае, начало сегмента CS1.
Т.о. модификаторы SHORT PTR, NEAR PTR и WORD PTR применяют при организации внутрисегментных переходов, а FAR PTR и DWORD PTR – при межсегментных переходах.
2.3. Организация циклов
При организации циклов широко используются команды INC (инкремент) и DEC (декремент), что означает добавление или вычитание единицы из целого числа, помещенного в ячейку памяти, РОН или индексный регистр. Команды имеют формат:
INC операнд ,
DEC операнд.
Такую программную конструкцию как цикл можно реализовать, используя в программе операции инкремента, декремента, условного и безусловного переходов. Но, учитывая важность такого алгоритмического элемента, как цикл, разработчики ассемблера предусмотрели специальные команды цикла, например:
LOOP метка_перехода.
Команда означает ’повторить цикл’. Выполнение команды заключается в следующем:
-
вычитании 1 из регистра СХ;
-
сравнении регистра СХ с нулем;
-
если СХ=0, то управление передается на следующую после LOOP команду, иначе осуществляется передача управления на метку_перехода.
Другими командами цикла являются команды:
LOOPE/LOOPZ метка_перехода,
которые означают “повторить цикл, пока СХ<>0 или ZF=0”. Обе команды совершенно идентичны, поэтому использовать можно любую из них. Отличаются эти команды от предыдущей команды анализом окончания цикла:
-
если СХ>0 и ZF=1, управление передается на метку_перехода, иначе если СХ=0 или ZF=0, то выполняется следующая после команды LOOPE/LOOPZ команда.
Еще одной модификацией являются команды цикла
LOOPNE/LOOPNZ метка_перехода,
которые означают, “повторить цикл, пока СХ<>0 или ZF=1”. Как и в предыдущем случае обе команды совершенно идентичны. В них анализ окончания цикла выполняется по следующему правилу:
-
если СХ>0 и ZF=0, управление передается на метку перехода, иначе если СХ=0 или ZF=1, то выполняется следующая после команды LOOPNE/LOOPNZ операция.
Общая особенность команд цикла в том, что они используют регистр общего назначения СХ как счетчик числа повторений цикла, поэтому при их использовании не забудьте до метки_перехода послать в этот регистр нужное число – количество повторений цикла!
Недостаток всех команд цикла в том, что они реализуют только короткие переходы. Для работы с длинными циклами используются комбинации команд условного перехода и безусловного перехода.
Приведем пример использования вышеописанных команд в контексте подсчета количества нулевых, положительных и отрицательных элементов вектора (одномерного массива), состоящего из однобайтовых чисел.
Описания переменных в сегменте данных могут быть следующими:
Mas db -1, 0, 3,-8,0,9,-6,1,2,-5 ; заданный вектор
Len_mas =$-mas ;количество элементов в векторе
Sch_0 db 0 ;счетчик нулевых элементов вектора
Sch_pol db 0 ;счетчик положительных элементов вектора
Sch_otr db 0 ;счетчик отрицательных элементов вектора.
Фрагмент сегмента кода для подсчета элементов может быть следующим:
Mov cx, len_mas ;инициализация счетчика цикла
Xor si,si ;инициализация индексного регистра
Cycl: cmp mas[si],0 ;сравниваем элемент вектора с 0
Jz zero ;нуль-элементы считаем в блоке zero
Jg pol ;элементы>0 считаем в блоке pol
Inc Sch_otr ;увеличиваем счетчик элементов <0
Jmp kon_cycl
Zero: Inc Sch_0 ;увеличиваем счетчик нулевых элементов
Jmp kon_cycl
pol: Inc Sch_pol ;увеличиваем счетчик элементов >0
kon_cycl: inc si ;переходим к следующему элементу вектора
loop cycl ;завершаем цикл.
3. ПОРЯДОК ВЫПОЛНЕНИЯ РАБОТЫ
1. Изучить приведенный теоретический материал к лабораторной работе.
2. Написать программы в соответствии с заданным преподавателем вариантом.
3. Оттранслировать программы в объектный код.
4. Провести отладку программ и проверить получаемые результаты.
4. СОДЕРЖАНИЕ ОТЧЕТА
Отчет должен включать:
-
титульный лист;
-
описание цели работы;
-
описание задания на лабораторную работу;
-
словесные пояснения к алгоритму решения задачи и схему программы;
-
листинги программ;
-
результаты выполнения программ;
-
выводы.
5. ВАРИАНТЫ ЗАДАНИЙ
1. Преобразовать символьную строку заданной длины, изменив все строчные буквы латинского алфавита на прописные.
2. Определить, сколько цифровых и нецифровых символов присутствует в заданной символьной строке.
3. Определить, сколько символов кириллицы и латиницы присутствует в заданной символьной строке.
4. Определить, сколько знаков отношения (<,>,=) присутствует в заданной символьной строке.
5. Преобразовать заданную символьную строку, изменив прописные буквы латиницы на их порядковые номера в алфавите.
Примечание к кодированию заданий 1-5: при написании алгоритмов преобразований необходимо использовать таблицу кодов ASCII, которая приводится в приложении 3.
6. Подсчитать количество положительных и отрицательных элементов в заданном векторе и определить, каких элементов в векторе больше
а) элементы вектора однобайтовые;
б) элементы вектора двухбайтовые.
7. Подсчитать количество нулевых и ненулевых элементов в заданном векторе и определить, каких элементов в векторе больше
а) элементы вектора однобайтовые;
б) элементы вектора двухбайтовые.
8. Подсчитать количество неотрицательных элементов в заданном двумерном массиве
а) элементы массива однобайтовые;
б) элементы массива двухбайтовые.
9. Подсчитать количество неположительных элементов в заданном двумерном массиве
а) элементы массива однобайтовые;
б) элементы массива двухбайтовые.
10. Подсчитать количество положительных и отрицательных элементов в заданном двумерном массиве и определить, каких элементов в нем больше
а) элементы массива однобайтовые;
б) элементы массива двухбайтовые.
Примечание к кодированию пунктов 8-10: в программе необходимо реализовать такую конструкцию, как “вложенные циклы”. Кроме того, понятие массива и индексации массива весьма условны, ибо в памяти ЭВМ элементы массива располагаются последовательно, строка за строкой, в результате чего физическая структура двумерного массива и вектора (одномерного массива) оказываются одинаковыми. Отличие двумерного массива и вектора заключается в интерпретации области памяти, отведенной этим структурам. Наращивание индекса элемента структуры определяется алгоритмом обработки.
6. Контрольные вопросы
1. Каков синтаксис команд условного перехода?
2. Какие флаги анализируют команды безусловного перехода?
-
Как формируется машинный код команды безусловного перехода ассемблера?
4. Что такое близкий и дальний переходы в ассемблере?
5. Как различить в командах прямой и косвенный переходы?
6. Какие действия выполняют команды цикла в ассемблере?
7. Какую команду необходимо предусмотреть перед меткой перехода для цикла?
Если ты не можешь перевести алгоритм из C++ в Assembler, то сделай проше:
например у тебя есть программа на C++, ты берешь компилятор С++ ставишь там флаг {генерировать ассемблерный код}, потом этот код подправляешь и сдаешь.
P.S В MS Visual Studio это делается так
Project->Properties->Configuration Properties->C/C++->Otput Files->Assembler Output = Assembly-Only Listing (/FA) (только выключи оптимизацию, а то ничего не разберешь в асме)
Достарыңызбен бөлісу: |