Главная страница » Как формируется машинный код команды безусловного перехода ассемблера

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

  • автор:

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

Безусловный переход в программе на Ассемблере производится по команде JMP. Полный формат команды следующий:

JMP[модификатор]адрес_перехода.

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

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

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

Прямой короткий внутрисегментный переход применяется, когда расстояние от команды JMPдо адреса перехода не более чем –128: +127 байтов. В этом случае транслятор языка формирует машинную команду безусловного перехода длиной 2 байта 1 байт – код операции, 2-ой байт – смещение. В коде операции заложена информация о том, что 2-ой байт интерпретируется как смещение. Здесь нужно отметить одну особенность транслятора Ассемблера – он является однопроходным, иными словами, машинный код программы получается за один просмотр мнемокоманд от начала до конца. В связи с этим обстоятельством, если безусловный переход должен происходить на адрес до командыJMP, то транслятор может легко вычислить смещение. Если же переход короткий, но на метку после командыJMP, то транслятору нужно подсказать, что он должен сформировать команду безусловного короткого перехода. С этой целью в командеJMPиспользуется модификаторSHORTPTR(полностью -SHORTPOINTERили короткий указатель):

JMP SHORT PTR M1

. . . . . . не более 35-40 команд

Прямой внутрисегментный переход отличается от короткого тем, что длина машинной команды составляет 3 байта, в которой 2 последних байта интерпретируются как смещение. Нетрудно определить, что в этом варианте можно осуществлять переход в пределах 64 Кбайт памяти относительно следующей за JMPкоманды.

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

JMP SHORT PTR K.

Приведу этот фрагмент программы полностью с комментариями.

MOV AL,A ;сторону треугольника а записать в AL

MOV BL,B ;сторону треугольника в записать в ВL

MOV СL,С ;сторону треугольника с записать в СL

CMP AL,BL ;сравнить стороны а и b

JNE NOT_EQABC ;если стороны не равны, перейти к NOT_EQABC

CMP BL,CL ;если а=b, сравнить b и c

JNE NOT_EQABC ;если стороны не равны, перейти к NOT_EQABC

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

JMP SHORT PTR K ; переход на метку K

NOT_EQABC: CMP BL,CL ;а не равно b, сравнить b и c

JE EQUAL ; если стороны равны, перейти к EQUAL

CMP AL,CL ; если b не равно c,сравнить а и с

JE EQUAL ; если стороны равны, перейти к EQUAL

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

JMP SHORT PTR K ; переход на метку K

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

Если приведенный фрагмент сравнить с предыдущим, то можно видеть, что после метки NOT_EQABCпропущена проверка сторонаив, поскольку на эту команду мы попадем в том случае, если а не равно в.

Косвенный внутрисегментный переход означает, что в команде JMPуказывается не сам адрес перехода, а место, где этот адрес записан. Например:

DSEG SEGMENT PARA PUBLIC ‘DATA’

CSEG SEGMENT PARA PUBLIC ‘CODE’

ASSUME CS:CSEG, DS:DSEG, SS:STACK

В командах косвенного внутрисегментного перехода рекомендуется применять модификатор NEAR, т.к. при косвенном переходе не всегда транслятору удается определить, находится адрес перехода в текущем сегменте кода или нет.

Команда прямого межсегментного перехода имеет длину 5 байт, из которых 2 байта составляет смещение адреса перехода, а другие 2 байта – значение сегментной составляющей (CS) того кодового сегмента, где находится адрес перехода. Например:

SEG1 SEGMENT PARA PUBLIC ‘CODE’

ASSUME CS:SEG1, DS:DSEG1, SS:STACK

SEG2 SEGMENT PARA PUBLIC ‘CODE’

ASSUME CS:SEG2, DS:DSEG2, SS:STACK

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

Команда косвенного межсегментного перехода в качестве операнда имеет адрес области памяти, в которой содержится смещение и сегментная часть целевого адреса перехода.

DSEG SEGMENT PARA PUBLIC ‘DATA’

CSEG SEGMENT PARA PUBLIC ‘CODE’

ASSUME CS:CSEG, DS:DSEG, SS:STACK

CS1 SEGMENT PARA PUBLIC ‘CODE’

ASSUME CS:CS1, DS:DS1, SS:ST1

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

DSEG SEGMENT PARA PUBLIC ‘DATA’

CSEG SEGMENT PARA PUBLIC ‘CODE’

ASSUME CS:CSEG, DS:DSEG, SS:STACK

JMP DWORD PTR [BX]

CS1 SEGMENT PARA PUBLIC ‘CODE’

ASSUME CS:CS1, DS:DS1, SS:ST1

В двойное слово ADDRпомещается смещение адреса и начало сегмента кода, включающего меткуM1, в нашем случае, начало сегментаCS1.

Т.о. модификаторы SHORTPTR,NEARPTRиWORDPTRприменяют при организации внутрисегментных переходов, аFARPTRиDWORDPTR– при межсегментных переходах.

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

Безусловный переход в программе на Ассемблере производится по команде JMP. Полный формат команды следующий:

JMP [модификатор] адрес_перехода.

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

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

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

Прямой короткий внутрисегментный переход применяется, когда расстояние от команды JMP до адреса перехода не более чем –128: +127 байтов. В этом случае транслятор языка формирует машинную команду безусловного перехода длиной 2 байта 1 байт – код операции, 2-ой байт – смещение. В коде операции заложена информация о том, что 2-ой байт интерпретируется как смещение. Здесь нужно отметить одну особенность транслятора Ассемблера – он является однопроходным, иными словами, машинный код программы получается за один просмотр мнемокоманд от начала до конца. В связи с этим обстоятельством, если безусловный переход должен происходить на адрес до команды JMP, то транслятор может легко вычислить смещение. Если же переход короткий, но на метку после команды JMP, то транслятору нужно подсказать, что он должен сформировать команду безусловного короткого перехода. С этой целью в команде JMP используется модификатор SHORT PTR (полностью — SHORT POINTER или короткий указатель):

JMP SHORT PTR M1

. . . . . . не более 35-40 команд

Прямой внутрисегментный переход отличается от короткого тем, что длина машинной команды составляет 3 байта, в которой 2 последних байта интерпретируются как смещение. Нетрудно определить, что в этом варианте можно осуществлять переход в пределах 64 Кбайт памяти относительно следующей за JMP команды.

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

JMP SHORT PTR K.

Приведу этот фрагмент программы полностью с комментариями.

MOV AL,A ;сторону треугольника а записать в AL

MOV BL,B ;сторону треугольника в записать в ВL

MOV СL,С ;сторону треугольника с записать в СL

CMP AL,BL ;сравнить стороны а и b

JNE NOT_EQABC ;если стороны не равны, перейти к NOT_EQABC

CMP BL,CL ;если а=b, сравнить b и c

JNE NOT_EQABC ;если стороны не равны, перейти к NOT_EQABC

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

JMP SHORT PTR K ; переход на метку K

NOT_EQABC: CMP BL,CL ;а не равно b, сравнить b и c

JE EQUAL ; если стороны равны, перейти к EQUAL

CMP AL,CL ; если b не равно c,сравнить а и с

JE EQUAL ; если стороны равны, перейти к EQUAL

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

JMP SHORT PTR K ; переход на метку K

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

Если приведенный фрагмент сравнить с предыдущим, то можно видеть, что после метки NOT_EQABC пропущена проверка сторон а и в, поскольку на эту команду мы попадем в том случае, если а не равно в.

Косвенный внутрисегментный переход означает, что в команде JMP указывается не сам адрес перехода, а место, где этот адрес записан. Например:

DSEG SEGMENT PARA PUBLIC ‘DATA’

CSEG SEGMENT PARA PUBLIC ‘CODE’

ASSUME CS:CSEG, DS:DSEG, SS:STACK

В командах косвенного внутрисегментного перехода рекомендуется применять модификатор NEAR, т.к. при косвенном переходе не всегда транслятору удается определить, находится адрес перехода в текущем сегменте кода или нет.

Команда прямого межсегментного перехода имеет длину 5 байт, из которых 2 байта составляет смещение адреса перехода, а другие 2 байта – значение сегментной составляющей (CS) того кодового сегмента, где находится адрес перехода. Например:

SEG1 SEGMENT PARA PUBLIC ‘CODE’

ASSUME CS:SEG1, DS:DSEG1, SS:STACK

SEG2 SEGMENT PARA PUBLIC ‘CODE’

ASSUME CS:SEG2, DS:DSEG2, SS:STACK

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

Команда косвенного межсегментного перехода в качестве операнда имеет адрес области памяти, в которой содержится смещение и сегментная часть целевого адреса перехода.

DSEG SEGMENT PARA PUBLIC ‘DATA’

CSEG SEGMENT PARA PUBLIC ‘CODE’

ASSUME CS:CSEG, DS:DSEG, SS:STACK

CS1 SEGMENT PARA PUBLIC ‘CODE’

ASSUME CS:CS1, DS:DS1, SS:ST1

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

DSEG SEGMENT PARA PUBLIC ‘DATA’

CSEG SEGMENT PARA PUBLIC ‘CODE’

ASSUME CS:CSEG, DS:DSEG, SS:STACK

JMP DWORD PTR [BX]

CS1 SEGMENT PARA PUBLIC ‘CODE’

ASSUME CS:CS1, DS:DS1, SS:ST1

В двойное слово ADDR помещается смещение адреса и начало сегмента кода, включающего метку M1, в нашем случае, начало сегмента CS1.

Т.о. модификаторы SHORT PTR, NEAR PTR и WORD PTR применяют при организации внутрисегментных переходов, а FAR PTR и DWORD PTR – при межсегментных переходах.

Процедуры

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

Имя_процедуры PROC [[модификатор_языка]язык] [расстояние]

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

— атрибут расстояние. Он может принимать значения NEAR и FAR. 1-ый вариант – для обращения к процедуре, описанной в текущем сегменте кода, 2-ой вариант – для обращения к процедуре из другого сегмента кода (внешней по отношению к текущему сегменту кода). По умолчанию предполагается NEAR. В этой связи следует обратить внимание, что основная процедура программы на ассемблере должна всегда иметь атрибут расстояния FAR, т.к. для программы-загрузчика она является внешней;

— процедуру можно помещать в любом месте программы, но таким образом, чтобы управление передавалось процедуре только в нужное время. Учитывая это, процедуру можно размещать в начале программы (до первой исполняемой команды) или в конце программы (после возвращения управления операционной системе) или в другом модуле. Если Вы все же решите поместить процедуру внутри другой процедуры или основной программы, то не забудьте предусмотреть обход процедуры, поставив перед началом процедуры команду JMP;

— Обращение к процедуре происходит по команде

— CALL [модификатор] имя_процедуры

— Модификатор принимает такие же значения, как и в команде JMP, за исключением SHORT PTR.

Организация циклов

При организации циклов широко используются команды INC (инкремент) и DEC (декремент), что означает добавление или вычитание единицы из целого числа, помещенного в ячейку памяти, РОН или индексный регистр. Команды имеют формат:

INC операнд или

В листинге 10.2 на стр.223 (учебник Юрова “Ассемблер”) приведен пример программы, в которой цикл организован за счет использования команд декремента и условного и безусловного перехода.

Перевод чисел из одной системы счисления в другую 4

Практическая работа N11
Тема: Программирование переходов

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

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

  • любая команда, изменяющая состояние арифметических флагов (ниже эти флаги будут перечислены);
  • команда сравнения CMP.

CMP приемник, источник или CMP операнд1, операнд2.

Эта команда осуществляет вычитание (операнд1 — операнд2) или (приемник – источник), однако результат никуда не записывается, а только устанавливает флаги в соответствие с таблицей 2 [5].

— “H” означает, что ‘не имеет значения” или иначе, на этот флаг операция не влияет;

— 0/1 означает, что флаг устанавливается или в 1 или в 0 в зависимости от значений операндов (отрицательные или положительные или разнознаковые операнды сравниваются).

Приведем еще одну таблицу 3 [1], в которой отражается действие команд условного перехода по значениям анализируемых этими командами флагов. В этой таблице через слеш ‘/’ перечисляются идентичные команды, действие которых совершенно одинаково, и применение конкретной из них зависит от пристрастий программиста. Наличие идентичных команд объясняется тем фактом, что если число_1 >число_2, то можно с уверенностью утверждать, что число_1 не (меньше или равно) число_2.

Логика команд условного перехода

Тип операндов Мнемокод команды Критерий перехода Значения флагов для перехода
любые JE Операнд_1=операнд_2 ZF=1
Любые JNE Операнд_1<>операнд_2 ZF=0
Со знаком JL/JNGE Операнд_1 OF
Со знаком JLE/JNG Операнд_1 OF или ZF=1
Со знаком JG/JNLE Операнд_1>операнд_2 SF=OF и ZF=0
Со знаком JGE/JNL Операнд_1>=операнд_2 SF=OF
Без знака JB/JNAE Операнд_1 операнд_2 CF=0 и ZF=0
Без знака JAE/JNB Операнд_1=>операнд_2 CF=0

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

Безусловный переход в программе на ассемблере производится по команде JMP. Полный формат команды следующий:

JMP [модификатор] адрес_перехода.

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

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

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

Прямой короткий внутрисегментный переход применяется, когда расстояние от команды JMP до адреса перехода не более чем 127 байтов выше или ниже. В этом случае транслятор языка формирует машинную команду безусловного перехода длиной 2 байта: первый байт – код операции, второй байт – смещение. В коде операции заложена информация о том, что второй байт интерпретируется как смещение. Здесь нужно отметить одну особенность транслятора ассемблера – он является однопроходным, иными словами, машинный код программы получается за один просмотр команд от начала программы до ее окончания. В связи с этим обстоятельством, если безусловный переход должен происходить на адрес до команды JMP, то транслятор может легко вычислить смещение. Если же переход короткий, но на метку после команды JMP, то транслятору нужно подсказать, что он должен сформировать команду безусловного короткого перехода. С этой целью в команде JMP используется модификатор SHORT PTR (полностью — SHORT POINTER или короткий указатель):

JMP SHORT PTR M1

. . . . . . не более 35-40 команд

Прямой внутрисегментный переход отличается от короткого тем, что длина машинной команды составляет 3 байта, в которой два последних байта интерпретируются как смещение. Нетрудно определить, что в этом варианте можно осуществлять переход в пределах 64 Кбайт памяти относительно следующей за JMP команды.

Косвенный внутрисегментный переход означает, что в команде JMP указывается не сам адрес перехода, а место, где этот адрес записан. Например:

DSEG SEGMENT PARA PUBLIC ‘DATA’

CSEG SEGMENT PARA PUBLIC ‘CODE’

ASSUME CS:CSEG, DS:DSEG, SS:STACK

В командах косвенного перехода рекомендуется применять модификатор NEAR, т.к. при косвенном переходе не всегда транслятору удается определить, находится адрес перехода в текущем сегменте кода или нет.

Команда прямого межсегментного перехода имеет длину 5 байт, из которых 2 байта составляет смещение адреса перехода, а другие 2 байта – значение сегментной составляющей (CS) того кодового сегмента, где находится адрес перехода. Например:

SEG1 SEGMENT PARA PUBLIC ‘CODE’

ASSUME CS:SEG1, DS:DSEG1, SS:STACK

SEG2 SEGMENT PARA PUBLIC ‘CODE’

ASSUME CS:SEG2, DS:DSEG2, SS:STACK

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

Команда косвенного межсегментного перехода в качестве операнда имеет адрес области памяти, в которой содержится смещение и сегментная часть целевого адреса перехода. Например:

DSEG SEGMENT PARA PUBLIC ‘DATA’

CSEG SEGMENT PARA PUBLIC ‘CODE’

ASSUME CS:CSEG, DS:DSEG, SS:STACK

CS1 SEGMENT PARA PUBLIC ‘CODE’

ASSUME CS:CS1, DS:DS1, SS:ST1

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

DSEG SEGMENT PARA PUBLIC ‘DATA’

CSEG SEGMENT PARA PUBLIC ‘CODE’

ASSUME CS:CSEG, DS:DSEG, SS:STACK

JMP DWORD PTR [BX]

CS1 SEGMENT PARA PUBLIC ‘CODE’

ASSUME CS:CS1, DS:DS1, SS:ST1

В двойное слово ADDR помещается смещение адреса и начала сегмента кода, включающего метку M1, в нашем случае, начало сегмента CS1.

Т.о. модификаторы SHORT PTR, NEAR PTR и WORD PTR применяют при организации внутрисегментных переходов, а FAR PTR и DWORD PTR – при межсегментных переходах.

3. Организация циклов

При организации циклов широко используются команды INC (инкремент) и DEC (декремент), что означает добавление или вычитание единицы из целого числа, помещенного в ячейку памяти, РОН или индексный регистр. Команды имеют формат:

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

  • вычитании 1 из регистра СХ;
  • сравнении регистра СХ с нулем;
  • если СХ=0, то управление передается на следующую после LOOP команду, иначе осуществляется передача управления на метку_перехода.
  • если СХ>0 и ZF=1, управление передается на метку_перехода, иначе если СХ=0 или ZF=0, то выполняется следующая после команды LOOPE/LOOPZ команда.
  • если СХ>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

kon_cycl: inc si ;переходим к следующему элементу вектора

loop cycl ;завершаем цикл.

Практическая часть
1. Изучить приведенный теоретический материал к лабораторной работе.

2. Написать программы в соответствии с заданным преподавателем вариантом.

3. Оттранслировать программы в объектный код.

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

Варианты заданий

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

2. Определить, сколько цифровых и нецифровых символов присутствует в заданной символьной строке.

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

4. Определить, сколько знаков отношения ( ,=) присутствует в заданной символьной строке.

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

Примечание к кодированию заданий 1-5: при написании алгоритмов преобразований необходимо использовать таблицу кодов ASCII, которая приводится в приложении 3.

6. Подсчитать количество положительных и отрицательных элементов в заданном векторе и определить, каких элементов в векторе больше

а) элементы вектора однобайтовые;

б) элементы вектора двухбайтовые.

7. Подсчитать количество нулевых и ненулевых элементов в заданном векторе и определить, каких элементов в векторе больше

а) элементы вектора однобайтовые;

б) элементы вектора двухбайтовые.

8. Подсчитать количество неотрицательных элементов в заданном двумерном массиве

а) элементы массива однобайтовые;

б) элементы массива двухбайтовые.

9. Подсчитать количество неположительных элементов в заданном двумерном массиве

а) элементы массива однобайтовые;

б) элементы массива двухбайтовые.

10. Подсчитать количество положительных и отрицательных элементов в заданном двумерном массиве и определить, каких элементов в нем больше

а) элементы массива однобайтовые;

б) элементы массива двухбайтовые.

Примечание к кодированию пунктов 8-10: в программе необходимо реализовать такую конструкцию, как “вложенные циклы”. Кроме того, понятие массива и индексации массива весьма условны, ибо в памяти ЭВМ элементы массива располагаются последовательно, строка за строкой, в результате чего физическая структура двумерного массива и вектора (одномерного массива) оказываются одинаковыми. Отличие двумерного массива и вектора заключается в интерпретации области памяти, отведенной этим структурам. Наращивание индекса элемента структуры определяется алгоритмом обработки.
Контрольные вопросы
1. Каков синтаксис команд условного перехода?

FasmWorld Программирование на ассемблере FASM для начинающих и не только

Учебный курс. Часть 16. Условные и безусловные переходы

Автор: xrnd | Рубрика: Учебный курс | 27-04-2010 | Распечатать запись

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

Безусловные переходы

Безусловный переход — это переход, который выполняется всегда. Безусловный переход осуществляется с помощью команды JMP. У этой команды один операнд, который может быть непосредственным адресом (меткой), регистром или ячейкой памяти, содержащей адрес. Существуют также «дальние» переходы — между сегментами, однако здесь мы их рассматривать не будем. Примеры безусловных переходов:

jmp metka ;Переход на метку jmp bx ;Переход по адресу в BX jmp word[bx] ;Переход по адресу, содержащемуся в памяти по адресу в BX

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

Условный переход осуществляется, если выполняется определённое условие, заданное флагами процессора (кроме одной команды, которая проверяет CX на равенство нулю). Как вы помните, состояние флагов изменяется после выполнения арифметических, логических и некоторых других команд. Если условие не выполняется, то управление переходит к следующей команде.

Существует много команд для различных условных переходов. Также для некоторых команд есть синонимы (например, JZ и JE — это одно и то же). Для наглядности все команды условных переходов приведены в таблице:

Команда Переход, если Условие перехода
JZ/JE нуль или равно ZF=1
JNZ/JNE не нуль или не равно ZF=0
JC/JNAE/JB есть переполнение/не выше и не равно/ниже CF=1
JNC/JAE/JNB нет переполнения/выше или равно/не ниже CF=0
JP число единичных бит чётное PF=1
JNP число единичных бит нечётное PF=0
JS знак равен 1 SF=1
JNS знак равен 0 SF=0
JO есть переполнение OF=1
JNO нет переполнения OF=0
JA/JNBE выше/не ниже и не равно CF=0 и ZF=0
JNA/JBE не выше/ниже или равно CF=1 или ZF=1
JG/JNLE больше/не меньше и не равно ZF=0 и SF=OF
JGE/JNL больше или равно/не меньше SF=OF
JL/JNGE меньше/не больше и не равно SF≠OF
JLE/JNG меньше или равно/не больше ZF=1 или SF≠OF
JCXZ содержимое CX равно нулю CX=0

У всех этих команд один операнд — имя метки для перехода. Обратите внимание, что некоторые команды применяются для беззнаковых чисел, а другие — для чисел со знаком. Сравнения «выше» и «ниже» относятся к беззнаковым числам, а «больше» и «меньше» — к числам со знаком. Для беззнаковых чисел признаком переполнения будет флаг CF, а соответствующими командами перехода JC и JNC. Для чисел со знаком о переполнении можно судить по состоянию флага OF, поэтому им соответствуют команды перехода JO и JNO. Команды переходов не изменяют значения флагов.

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

use16 ;Генерировать 16-битный код org 100h ;Программа начинается с адреса 100h mov al,[x] ;AL = x add al,[y] ;AL = x + y jo error ;Переход, если переполнение mov ah,09h ;\ mov dx,ok_msg ; > Вывод строки ‘OK’ int 21h ;/ exit: mov ah,09h ;\ mov dx,pak ; > Вывод строки ‘Press any key. ‘ int 21h ;/ mov ah,08h ;\ int 21h ;/ Ввод символа mov ax,4C00h ;\ int 21h ;/ Завершение программы error: mov ah,09h ;\ mov dx,err_msg ; > Вывод сообщения об ошибке int 21h ;/ jmp exit ;Переход на метку exit ;———————————————————- x db -89 y db -55 err_msg db ‘Error: overflow detected.’,13,10,’$’ ok_msg db ‘OK’,13,10,’$’ pak db ‘Press any key. $’

Команды CMP и TEST

Часто для формирования условий переходов используются команды CMP и TEST. Команда CMP предназначена для сравнения чисел. Она выполняется аналогично команде SUB: из первого операнда вычитается второй, но результат не записывается на место первого операнда, изменяются только значения флагов. Например:

cmp al,5 ;Сравнение AL и 5 jl c1 ;Переход, если AL < 5 (числа со знаком)

cmp al,5 ;Сравнение AL и 5 jb c1 ;Переход, если AL < 5 (числа без знака)

Команда TEST работает аналогично команде AND, но также результат не сохраняется, изменяются только флаги. С помощью этой команды можно проверить состояние различных битов операнда. Например:

test bl,00000100b ;Проверить состояние 2-го бита BL jz c2 ;Переход, если 2-й бит равен 0

Пример программы

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

use16 ;Генерировать 16-битный код org 100h ;Программа начинается с адреса 100h jmp start ;Безусловный переход на метку start ;———————————————————- menu db ‘1 — Print hello’,13,10 db ‘2 — Print go away’,13,10 db ‘0 — Exit’,13,10,’$’ select db 13,10,’Select>$’ hello db 13,10,’Hello!’,13,10,13,10,’$’ go_away db 13,10,’Go away!’,13,10,13,10,’$’ ;———————————————————- start: mov ah,09h ;\ mov dx,menu ; > Вывод меню int 21h ;/ select_loop: mov ah,09h ;\ mov dx,select ; > Вывод строки ‘Select>’ int 21h ;/ mov ah,01h ;Функция DOS 01h — ввод символа int 21h ;Введённый символ помещается в AL cmp al,’1′ ;Сравнение введённого символа с ‘1’ je c1 ;Переход, если равно cmp al,’2′ ;Сравнение введённого символа с ‘2’ je c2 ;Переход, если равно cmp al,’0′ ;Сравнение введённого символа с ‘0’ je exit ;Переход, если равно jmp select_loop ;Безусловный переход c1: mov ah,09h ;\ mov dx,hello ; > Вывод строки ‘Hello’ int 21h ;/ jmp start ;Безусловный переход c2: mov ah,09h ;\ mov dx,go_away ; > Вывод строки ‘Go away’ int 21h ;/ jmp start ;Безусловный переход exit: mov ax,4C00h ;\ int 21h ;/ Завершение программы

Скриншот работы программы:

Упражнение

Упражнение простое. Напишите программу для сравнения двух переменных со знаком a и b. В зависимости от результатов сравнения выведите «a < b», «a > b» или «a = b». Проверьте работу программы в отладчике. Результаты можете выкладывать в комментариях.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *