Автор: Пользователь скрыл имя, 10 Марта 2013 в 15:44, курс лекций
Один из основных принципов машины фон Неймана — то, что и программы, и данные хранятся в одной и той же памяти. Сохраняемая в памяти программа представляет собой некоторые коды, которые могут рассматриваться как данные. Возможно, с точки зрения программиста программа — активный компонент, она выполняет некоторые действия. Но с точки зрения процессора команды программы — это данные, которые процессор читает и интерпретирует. С другой стороны программа — это данные с точки зрения обслуживающих программ, например, с точки зрения компилятора, который на входе получает одни данные — программу на языке высокого уровня (ЯВУ), а на выходе выдает другие данные — программу в машинных кодах.
При появлении
имени в поле метки команды
или директивы Ассемблер
После окончания прохода Ассемблер проверяет таблицу символов: если в ней остались неопределенные имена, выдается сообщение об ошибке.
Если объектный модуль выводится в файл по мере его формирования, алгоритм работы Ассемблера очень похож на предыдущий случай. Ассемблер не может при определении имени исправить уже сформированные и выведенные в файл операнды, но вместо этого он формирует новую запись объектного модуля, исправляющую старую. При загрузке будет сначала загружена в память запись с пустым полем операнда, но затем на ее место — запись с правильным полем операнда.
Для чего может понадобиться многопроходный Ассемблер? Единственная необходимость во многих проходах может возникнуть, если в директиве EQU разрешены ссылки вперед. Мы упоминали выше, что имя в директиве EQU может определяться через другое имя. В одно- или двухпроходном Ассемблере это другое имя должно быть обязательно определено в программе выше. В многопроходном Ассемблере оно может быть определено и ниже. На первом проходе происходит определение имен и составление таблицы символов, но некоторые имена остаются неопределенными. На втором проходе определяются имена, не определившиеся во время предыдущего прохода. Второй проход повторяется до тех пор, пока не будут определены все имена (или не выяснится, что какие-то имена определить невозможно). На последнем проходе генерируется объектный код.
Лекция 11.
Логика и организация программы
4
Команда JMP
Большинство программ содержат ряд циклов, в которых несколько команд повторяются до достижения определенного требования, и различные проверки, определяющие, какие из нескольких действий следует выполнять. Обычным требованием является проверка — должна ли программа завершить выполнение.
Эти требования включают передачу управления по адресу команды, которая не находится непосредственно за выполняемой в текущий момент командой. Передача управления может осуществляться вперед для выполнения новой группы команд или назад для повторения уже выполненных команд.
Некоторые команды могут передавать управление, изменяя нормальную последовательность шагов непосредственной модификацией значения смещения в командном указателе. Ниже приведены четыре способа передачи управления:
Безусловный переход
JMP
Цикл:
LOOP
Условный переход:
J nnn (больше,меньше,равно)
Вызов процедуры:
CALL
Заметим, что имеется три типа адресов: SHORT, NEAR и FAR. Адресация SHORT используется при циклах, условных пеpеходах и некоторых безусловных переходах. Адресация NEAR и FAR используется для вызовов процедур (CALL) и безусловных переходов, которые не квалифицируются , как SHORT. Все три типа передачи управления воздействуют на содержимое регистра IP; тип FAR также изменяет регистр CS.
Одной из команд обычно используемых для передачи управления является команда JMP. Эта команда выполняет безусловный переход, то есть, обеспечивает передачу управления при любых обстоятельствах.
4
Команда LOOP
Команда JMP реализует бесконечный цикл. Но более вероятно подпрограмма должна выполнять определенное число циклов. Команда LOOP, которая служит для этой цели, использует начальное значение в регистре CX. В каждом цикле команда LOOP автоматически уменьшает содержимое регистра CX на 1. Пока значение в CX не равно нулю, управление передается по адресу, указанному в операнде, и если в CX будет 0, управление переходит на следующую после LOOP команду.
Аналогично команде JMP, операнд команды LOOP определяет расстояние от конца команды LOOP до адреса метки, которое прибавляется к содержимому командного указателя. Для команды LOOP это расстояние должно быть в пределах от -128 до +127 байт. В случае, если операнд превышает эти границы, то Ассемблер выдаст сообщение:
«Relative jump out of range» (превышены границы перехода)
Для проверки команды LOOP рекомендуется изменить соответствующим образом программу, выполнить ее ассемблирование, компоновку и преобразование в COM-файл. Для трассировки всех циклов используйте отладчик DEBUG. Когда в значение регистре CX уменьшится до нуля, содержимое регистpов AX, BX и DX будет соответственно шест. 000B, 0042 и 0400. Для выхода из отладчика введите команду Q.
Дополнительно существует две разновидности команды LOOP — это LOOPE (или LOOPZ) и LOOPNE (или LOOPNZ). Обе команды также уменьшают значение регистра CX на 1. Команда LOOPE передает управление по адресу операнда, если регистр CX имеет ненулевое значение и флаг нуля установлен (ZF=1). Команда LOOPNE передает управление по адресу операнда, если регистр CX имеет ненулевое значение и флаг нуля сброшен (ZF=0).
4
Флаговый регистр
Флаговый регистр содержит 16 бит флагов, которые управляются различными командами для индикации состояния операции. Во всех случаях флаги сохраняют свое значение до тех пор, пока другая команда не изменит его. Флаговый регистр содержит следующие девять используемых бит (звездочками отмечены неиспользуемые биты):
Номер бита: 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
Флаг: * * * * O D I T S Z * A * P * C
Рассмотрим эти флаги в последовательности справа налево.
CF (Carry Flag) — флаг переноса
Содержит значение «переносов» (0 или 1) из старшего разряда при арифметических операциях и некоторых операциях сдвига и циклического сдвига.
PF (Parity Flag) — флаг четности
Проверяет младшие восемь бит pезультатов операций над данными. Нечетное число бит приводит к установке этого флага в 0, а четное — в 1. Не следует путать флаг четности с битом контроля на четность.
AF (Auxiliary Carry Flag) — дополнительный флаг переноса
Устанавливается в 1, если арифметическая операция приводит к переносу четвертого справа бита (бит номер 3) в регистровой однобайтовой команде.Данный флаг имеет отношение к арифметическим операциям над символами кода ASCII и к десятичным упакованным полям.
ZF (Zero Flag) — флаг нуля
Устанавливается в качестве результата aрифметических команд и команд сравнения. Как это ни странно, ненулевой результат приводит к установке нулевого значения этого флага, а нулевой — к установке единичного значения. Кажущееся несоответствие является, однако, логически правильным, так как 0 обозначает «нет» (то есть, результат не равен нулю), а единица обозначаeт «да» (то есть, результат равен нулю).
Команды условного перехода JE и JZ проверяют этот флаг.
SF (SIgn Flag) — знаковый флаг
Устанавливается в соответствии со знаком результата (старшего бита) после арифметических опеpаций: положительный результат устанавливает 0, а отрицательный — 1. Команды условного перехода JG и JL проверяют этот флаг.
TF (Trap Flag) — флаг пошагового выполнения
Этот флаг вам уже приходилось устанавливать, когда использовалась команда Т в отладчике DEBUG. В случае, если этот флаг установлен в единичное cостояние, то процессор переходит в режим пошагового выполнения команд, то есть, в каждый момент выполняется одна команда под пользовательским управлением.
IF (Interrupt Flag) — флаг прерывания
При нулевом
состоянии этого флага
DF (DIrection Flag) — флаг направления
Используется
в строковых операциях для
определения направления
OF (Overflow Flag) — флаг переполнения
Фиксирует арифметическое переполнение, то есть, перенос вниз старшего (знакового) бита при знаковых арифметических операциях.
В качестве примера: команда CMP сравнивает два операнда и воздействует на флаги AF, CF, OF, PF, SF, ZF. Однако, нет необходимости проверять все эти флаги по отдельности. В следующем примере проверяется содержит ли регистр BX нулевое значение:
CMP BX,00 ;Сравнение BX с нулем
JZ B50 ;Переход на B50 если нуль
...
действия не при нуле
...
B50: ... ;Точка перехода при BX=0
В случае, если BX содержит нулевое значение, команда CMP устанавливает флаг нуля ZF в единичное состояние, и возможно изменяет (или нет) другие флаги.
Команда JZ (переход, если нуль) проверяет только флаг ZF. При единичном значении ZF, обозначающее нулевой признак, команда передает управление на адрес, указанный в ее операнде, то есть, на метку B50.
4
Команды условного перехода
Команда LOOP уменьшает на единицу содержимое регистра CX и проверяет его: если не ноль, то управление передается по адресу, указанному в операнде. Таким образом, передача управления зависит от конкретного состояния. Ассемблер поддерживает большое количество команд условного перехода, которые осуществляют передачу управления в зависимости от состояний флагового регистра. Например, при сравнении содержимого двух полей последующий переход зависит от значения флага.
Команду LOOP в программе можно заменить на две команды: одна уменьшает содержимое регистра CX, а другая выполняет условный переход:
LOOP A20
DEC CX
JNZ A20
Команды DEC и JNZ действуют аналогично команде LOOP: уменьшают содержимое регистра CX на 1 и выполняет переход на метку A20, если в CX не ноль. Команда DEC кроме того устанавливает флаг нуля во флаговом регистре в состояние 0 или 1. Команда JNZ затем проверяет эту установку. В рассмотренном примере команда LOOP хотя и имеет ограниченное использование, но более эффективна, чем две команды: DEC и JNZ.
Аналогично командам JMP и LOOP операнд в команде JNZ cодержит значение расстояния между концом команды JNZ и адресом A20, которое прибавляется к командному указателю. Это расстояние должно быть в пределах от -128 до +127 байт.
В случае перехода за эти границы Ассемблер выдаст сообщение:
«Relative jump out of range» (превышены относительные границы перехода)
Знаковые и беззнаковые данные
Рассматривая назначение команд условного перехода следует пояснить характер их использования. Типы данных, над которыми выполняются арифметические операции и операции сравнения определяют какими командами пользоваться: беззнаковыми или знаковыми. Беззнаковые данные используют все биты как биты данных; характерным примером являются символьные строки: имена, адреса и натуральные числа. В знаковых данных самый левый бит представляет собой знак, причем если его значение равно нулю, то число положительное, и если единице, то отрицательное. Многие числовые значения могут быть как положительными так и отрицательными.
В качестве примера предположим, что регистр AX содержит 11000110, а BX — 00010110. Команда:
CMP AX,BX
сравнивает содержимое регистров AX и BX. В случае, если данные беззнаковые, то значение в AX больше, а если знаковые — то меньше.
Запомните, что для беззнаковых данных есть переходы по состояниям равно, выше или ниже, а для беззнаковых — равно, больше или меньше. Переходы по проверкам флагов переноса, переполнения и паритета имеют особое назначение. Ассемблер транслирует мнемонические коды в объектный код независимо от того, какую из двух команд вы применили.
4
Процедуры и оператор CALL
Ранее примеры содержали в кодовом сегменте только oдну процедуру, оформленную следующим образом:
BEGIN PROC FAR
.
.
BEGIN ENDP
Операнд FAR информирует систему о том, что данный адрес является точкой входа для выполнения, а директива ENDP определяет конец процедуры.
Кодовый сегмент, однако, может содержать любое количество процедур, которые разделяются директивами PROC и ENDP.
Обратите внимание на следующие особенности:
u Директивы PROC по меткам имеют операнд NEAR для указания того, что эти процедуры находятся в текущем кодовом сегменте.
u Каждая процедура имеет уникальное имя и содержит собственную директиву ENDP для указания конца процедуры.
u Для передачи управления в процедуре BEGIN имеются две команды: CALL. В результате первой команды CALL управление передается указанной процедуре и начинается ее выполнение. Достигнув команды RET, управление возвращается на команду непосредственно следующую за первой командой CALL. Вторая команда CALL действует аналогично — передает управление в указанную процедуру, выполняет ее команды и возвращает управление по команде RET.
u Команда RET всегда выполняет возврат в вызывающую программу.
Программа BEGIN вызывает процедуры, которые возвращают управление обратно в BEGIN. Для выполнения самой программы BEGIN операционная система DOS вызывает ее и в конце выполнения команда RET возвращает управление в DOS. В случае, если процедура не содержит завершающей команды RET, то выполнение команд продолжится непосредственно в этой процедуре. В случае, если процедура не содержит команды RET, то будут выполняться команды, оказавшиеся за процедурой с непредсказуемым результатом.
Использование процедур дает хорошую возможность организовать логическую структуру программы. Кроме того, операнды для команды CALL могут иметь значения, выходящие за границу от -128 до +127 байт.
Технически управление в процедуру типа NEAR может быть передано с помощью команд перехода или даже обычным построчным кодированием. Но в большинстве случаев рекомендуется использовать команду CALL для передачи управления в процедуру и команду RET для возврата.