Жанр: Учеба

Ассемблер и программирование для IBM PC

сторінка №9

од, если равно/нуль ZF
JNE/JNZ Переход, если не равно/не нуль ZF
JA/JNBE Переход, если выше/не ниже или равно ZF,CF
JAE/JNB Переход, если выше или равно/не ниже CF
JB/JNAE Переход, если ниже/не выше или равно CF
JBE/JNA Переход, если ниже или равно/не выше CF,AF

Любую проверку можно кодировать одним из двух мнемонических кодов.
Например, JB и JNAE генерирует один и тот же объектный код, хотя
положительную проверку JB легче понять, чем отрицательную JNAE.

Переходы для знаковых данных
------------------------------
Мнемоника Описание Проверяемые флаги

JE/JZ Переход, если равно/нуль ZF
JNE/JNZ Переход, если не равно/не нуль ZF
JG/JNLE Переход, если больше/не меньше или равно ZF,SF,OF
JGE/JNL Переход, если больше или равно/не меньше SF,OF
JL/JNGE Переход, если меньше/не больше или равно SF,OF
JLE/JNG Переход, если меньше или равно/не больше ZF,SF,OF

Команды перехода для условия равно или ноль (JE/JZ) и не равно или не
ноль (JNE/JNZ) присутствуют в обоих списках для беззнаковых и знаковых
данных. Состояние равно/нуль происходит вне зависимости от наличия знака.

Специальные арифметические проверки
-------------------------------------
Мнемоника Описание Проверяемые флаги

JS Переход, если есть знак (отрицательно) SF
JNS Переход, если нет знака(положительно) SF
JC Переход, если есть перенос (аналогично JB) CF
JNC Переход, если нет переноса CF
JO Переход, если есть переполнение OF
JNO Переход, если нет переполнения OF
JP/JPE Переход, если паритет четный PF
JNP/JP Переход, если паритет нечетный PF

Еще одна команда условного перехода проверяет равно ли содержимое
регистра CX нулю. Эта команда необязательно должна располагаться
непосредственно за командой арифметики или сравнения. Одним из мест для
команды JCXZ может быть начало цикла, где она проверяет содержит ли
регистр CX ненулевое значение.
Не спешите пока заучивать эти команды наизусть. Запомните только, что
для беззнаковых данных есть переходы по состояниям равно, выше или ниже, а
для беззнаковых - равно, больше или меньше. Переходы по проверкам флагов
переноса, переполнения и паритета имеют особое назначение. Ассемблер
транслирует мнемонические коды в объектный код независимо от того, какую
из двух команд вы применили. Однако, команды JAE и JGE являясь явно
одинаковыми, проверяют различные флаги.

ПРОЦЕДУРЫ И ОПЕРАТОР CALL
________________________________________________________________

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

BEGIN PROC FAR
BEGIN ENDP

Операнд FAR информирует систему о том, что данный адрес является
точкой входа для выполнения, а директива ENDP определяет конец процедуры.
Кодовый сегмент, однако, может содержать любое количество процедур,
которые разделяются директивами PROC и ENDP. Типичная организация
многопроцедурной программы приведена на рис.7.3.

__________________________________________________________________________

-------------------------¬
¦ CODESG SEGMENT PARA ¦
+------------------------+
¦ BEGIN PROC FAR ¦
¦ . ¦
¦ . ¦
¦ CALL B10 ¦
¦ CALL C10 ¦
¦ RET ¦
¦ BEGIN ENDP ¦
+------------------------+
¦ B10 PROC NEAR ¦
¦ . ¦
¦ . ¦
¦ RET ¦
¦ B10 ENDP ¦
+------------------------+
¦ C10 PROC NEAR ¦
¦ . ¦
¦ . ¦
¦ RET ¦
¦ C10 ENDP ¦
+------------------------+
¦ CODESG ENDS ¦
¦ END BEGIN ¦
L-------------------------
__________________________________________________________________________

Рис.7.3. Вызов процедур.

Обратите внимание на следующие особенности:

- Директивы PROC по меткам B10 и C10 имеют операнд NEAR для
указания того, что эти процедуры находятся в текущем кодовом
сегменте. Во многих последующих примерах этот операнд опущен, так как
по умолчанию ассемблер принимает тип NEAR.

- Каждая процедура имеет уникальное имя и содержит собственную
директиву ENDP для указания конца процедуры.

- Для передачи управления в процедуре BEGIN имеются две команды:
CALL B10 и CALL C10. В результате первой команды CALL управление
передается процедуре B10 и начинается ее выполнение. Достигнув
команды RET, управление возвращается на команду непосредственно
следующую за CALL B10. Вторая команда CALL действует аналогично -
передает управление в процедуру C10, выполняет ее команды и
возвращает управление по команде RET.

- Команда RET всегда выполняет возврат в вызывающую программу.
Программа BEGIN вызывает процедуры B10 и C10, которые возвращают
управление обратно в BEGIN. Для выполнения самой программы BEGIN
операционная система DOS вызывает ее и в конце выполнения команда RET
возвращает управление в DOS. Если процедура B10 не содержит
завершающей команды RET, то выполнение команд продолжится из B10
непосредственно в процедуре C10. Если процедура C10 не содержит
команды RET, то будут выполняться команды, оказавшиеся за процедурой
C10 с непредсказуемым результатом.

Использование процедур дает хорошую возможность организовать
логическую структуру программы. Кроме того, операнды для команды CALL
могут иметь значения, выходящие за границу от -128 до +127 байт.
Технически управление в процедуру типа NEAR может быть передано с
помощью команд перехода или даже обычным построчным кодированием. Но в
большинстве случаев рекомендуется использовать команду CALL для передачи
управления в процедуру и команду RET для возврата.

СЕГМЕНТ СТЕКА
________________________________________________________________

До этого раздела в приводимых примерах встретились только две
команды, использующих стек, - это команды PUSH в начале сегмента кодов,
которые обеспечивают возврат в DOS, когда EXE-программа завершается.
Естественно для этих программ требуется стек очень малого размера. Однако,
команда CALL автоматически записывает в стек относительный адрес команды,
следующей непосредственно за командой CALL, и увеличивает после этого
указатель вершины стека. В вызываемой процедуре команда RET использует
этот адрес для возврата в вызывающую процедуру и при этом автоматически
уменьшается указатель вершины стека.
Таким образом, команды PUSH записывают в стек двухбайтовые адреса или
другие значения. Команды POP обычно выбирают из стека записанные в него
слова. Эти операции изменяют относительный адрес в регистре SP (т.е. в
указатели стека) для доступа к следующему слову. Данное свойство стека
требует чтобы команды RET и CALL соответствовали друг другу. Кроме того,
вызванная процедура может вызвать с помощью команды CALL другую процедуру,
а та в свою очередь - следующую. Стек должен иметь достаточные размеры для
того, чтобы хранить все записываемые в него адреса. Для большинства
примеров в данной книге стек объемом в 32 слова является достаточным.
Команды PUSH, PUSHF, CALL, INT, и INTO заносят в стек адрес возврата
или содержимое флагового регистра. Команды POP, POPF, RET и IRET извлекают
эти адреса или флаги из стека.
При передаче управления в EXE-программу система устанавливает в
регистрах следующие значения:

DS и ES: Адрес префикса программного сегмента - область в 256
(шест.100) байт, которая предшествует выполняемому программному модулю в
памяти.

CS: Адрес точки входа в программу (адрес первой выполняемой команды).

IP: Нуль.

SS: Адрес сегмента стека.

SP: Относительный адрес, указывающий на вершину стека. Например, для
стека в 32 слова (64 байта), определенного как

DW 32 DUP(?)

SP содержит 64, или шест.40.

Выполним трассировку простой EXE-программы, приведенной на рис.7.4.
На практике вызываемые процедуры содержат любое число команд.

__________________________________________________________________________

TITLE CALLPROC (EXE) Вызов процедур
0000 STACKSG SEGMENT PARA STACK 'Stack'
0000 20 [ ???? ] DW 32 DUP(?)
0040 STACKG ENDS

0000 CODESG SEGMENT PARA 'Code'
0000 BEGIN PROC FAR
ASSUME CS:CODESG,SS:STACKSG
0000 1E PUSH DS
0001 2B C0 SUB AX,AX
0003 50 PUSH AX
0004 E8 0008 R CALL B10 ;Вызвать B10
; ...
0007 CB RET ;Завершить программу
0008 BEGIN ENDP
;-------------------------------------
0008 B10 PROC
0008 E8 000C R CALL C10 ;Вызвать C10
; ...
000B C3 RET ;Вернуться в
000C B10 ENDP ; вызывающую программу
;---------------------------------------------
000C C10 PROC
; ...
000C C3 RET ;Вернуться в
000D C10 ENDP ; вызывающую программу
;---------------------------------------------
000D CODESG ENDS
END BEGIN
__________________________________________________________________________

Рис.7.4. Воздействие выполнения программы на стек.

Текущая доступная ячейка стека для занесения или извлечения слова
является вершина стека. Первая команда PUSH уменьшает значение SP на 2 и
заносит содержимое регистра DS (в данном примере 049f) в вершину стека,
т.е. по адресу 4B00+3E. Вторая команда PUSH также уменьшает значение SP на
2 и записывает содержимое регистра AX (0000) по адресу 4B00+3C. Команда
CALL B10 уменьшает значение SP и записывает относительный адрес следующей
команды (0007) в стек по адресу 4B00+3A. Команда CALL C10 уменьшает
значение SP и записывает относительный адрес следующей команды (000B) в
стек по адресу 4B00+38.
При возврате из процедуры C10 команда RET извлекает 000B из стека
(4B00+38), помещает его в указатель команд IP и увеличивает значение SP на
2. При этом происходит автоматический возврат по относительному адресу
000B в кодовом сегменте, т.е. в процедуру B10.
Команда RET в конце процедуры B10 извлекает адрес 0007 из стека
(4B00+3A), помещают его в IP и увеличивает значение SP на 2. При этом
происходит автоматический возврат по относительному адресу 0007 в кодовом
сегменте. Команда RET по адресу 0007 завершает выполнение программы,
осуществляя возврат типа FAR.
Ниже показано воздействие на стек при выполнении каждой команды. Для
трассировки программы можно использовать отладчик DEBUG. Приведено только
содержимое памяти с адреса 0034 до 003F и содержимое регистра SP:

Команда Стек SP

Начальное значение: хххх хххх хххх хххх хххх хххх 0040
PUSH DS (запись 049F) хххх хххх хххх хххх хххх 049F 003E
PUSH AX (запись 0000) хххх хххх хххх хххх 0000 049F 003C
CALL B10 (запись 0007) хххх хххх хххх 0700 0000 049F 003A
CALL C10 (запись 000B) хххх хххх 0B00 0700 0000 049F 0038
RET (выборка 000B) хххх хххх хххх 0700 0000 049F 003A
RET (выборка 0007) хххх хххх хххх хххх 0000 049F 003C
| | | | | |
Смещение в стеке: 0034 0036 0038 003A 003C 003E

Обратите внимание на два момента. Во-первых, слова в памяти содержат
байты в обратной последовательности, так 0007 записывается в виде 0700.
Во-вторых, отладчик DEBUG при использовании его для просмотра стека
заносит в стек другие значения, включая содержимое IP, для собственных
нужд.

ПРОГРАММА: РАСШИРЕННЫЕ ОПЕРАЦИИ ПЕРЕСЫЛКИ
________________________________________________________________

В предыдущих программах были показаны команды пересылки
непосредственных данных в регистр, пересылки данных из памяти в регистр,
пересылки содержимого регистра в память и пересылки содержимого одного
регистра в другой. Во всех случаях длина данных была ограничена одним или
двумя байтами и не предусмотрена пересылка данных из одной области памяти
непосредственно другую область. В данном разделе объясняется процесс
пересылки данных, которые имеют длину более двух байт. В гл.11 будет
показано использование операций над строками для пересылки данных из одной
области памяти непосредственно в другую область.
В EXE-программе, приведенной на рис.7.5, сегмент данных содержит три
девятибайтовых поля, NAME1, NAME2, NAME3. Цель программы - переслать
данные из поля NAME1 в поле NAME2 и переслать данные из поля NAME2 в поле
NAME3. Так как эти поля имеют длину девять байт каждая, то для пересылки
данных кроме простой команды MOV потребуются еще другие команды. Программа
содержит несколько новых особенностей.

__________________________________________________________________________

page 65,132
TITLE EXMOVE (EXE) Операции расширенной пересылки
;------------------------------------------------------
STACKSG SEGMENT PARA STACK 'Stack'
DW 32 DUP(?)
STACKSG ENDS
;------------------------------------------------------
DATASG SEGMENT PARA 'Data'
NAME1 DB 'ABCDEFGHI'
NAME2 DB 'JKLMNOPQR'
NAME3 DB 'STUVWXYZ*'
DATASG ENDS
;-------------------------------------------------------
CODESG SEGMENT PARA 'Code'
BEGIN PROC FAR
ASSUME CS:CODESG,DS:DATASG,SS:STACKSG,ES:DATASG
PUSH DS
SUB AX,AX
PUSH AX
MOV AX,DATASG
MOV DS,AX
MOV ES,AX
CALL B10MOVE ;Вызвать JUMP подпрограмму
CALL C10MOVE ;Вызвать CALL подпрограмму
RET ;Завершить программу
BEGIN ENDP

; Расширенная пересылка (JUMP-подпрограмма),
; использующая переход по условию:
; -----------------------------------------
B10MOVE PROC
LEA SI,NAME1 ;Инициализация адресов
LEA DI,NAME2 ; NAME1 и NAME2
MOV CX,09 ;Переслать 9 символов
B20:
MOV AL,[SI] ;Переслать из NAME1
MOV [DI],AL ;Переслать в NAME2
INC SI ;Следующий символ в NAME1
INC DI ;Следующая позиция в NAME2
DEC CX ;Уменьшить счетчик цикла
JNZ B20 ;Счетчик " 0? Да - цикл
RET ;Если счетчик = 0, то
B10MOVE ENDP ; вернуться

; Расширенная пересылка (LOOP-подпрограмма),
; использующая команду LOOP:
; -----------------------------------------;
C10MOVE PROC
LEA SI,NAME2 ;Инициализация адресов
LEA DI,NAME3 ; NAME2 и NAME3
MOV CX,09 ;Переслать 9 символов
C20
MOV AL,[SI] ;Переслать из NAME2
MOV [DI],AL ;Переслать в NAME3
INC DI ;Следующий символ в NAME2
INC SI ;Следующая позиция в NAME3
LOOP C20 ;Уменьшить счетчик,
; если не ноль, то цикл
RET ;Если счетчик = 0, то
C10MOVE ENDP ; вернуться
CODESG ENDS
END BEGIN
__________________________________________________________________________

Рис.7.5. Расширенные операции пересылки.

Процедура BEGIN инициализирует сегментные регистры и затем вызывает
процедуры B10MOVE и C10MOVE. Процедура B10MOVE пересылает содержимое поля
NAME1 в поле NAME2. Так как каждый раз пересылается только один байт, то
процедура начинает с самого левого байта в поле NAME1 и в цикле пересылает
затем второй байт, третий и т.д.:

NAME1: A B C D E F G H I
| | | | | | | | |
NAME2: J K L M N O P Q R

Для продвижения в полях NAME1 и NAME2 в регистр CX заносится значение 9, а
регистры SI и DI используются в качестве индексных. Две команды LEA
загружают относительные адреса полей NAME1 и NAME2 в регистры SI и DI:

LEA SI,NAME1 ;Загрузка относительных адресов
LEA DI,NAME2 ; NAME1 и NAME2

Для пересылки содержимого первого байта из поля NAME1 в первый байт поля
NAME2 используются адреса в регистрах SI и DI. квадратные скобки в
командах MOV обозначают, что для доступа к памяти используется адрес в
регистре, указанном в квадратных скобках. Таким образом, команда

MOV AL,[SI]

означает: использовать адрес в регистре SI (т.е.NAME1) для пересылки
соответствующего байта в регистр AL. А команда

MOV [DI],AL

означает: пересылать содержимое регистра AL по адресу, лежащему в регистре
DI (т.е. NAME2).
Следующие команды увеличивают значения регистров SI и DI и уменьшают
значение в регистре SH. Если в регистре CX не нулевое значение, управление
передается на следующий цикл (на метку B20). Так как содержимое регистров
SI и DI было увеличено на 1, то следующие команды MOV будут иметь дело с
адресами NAME1+1 и NAME2+1. Цикл продолжается таким образом, пока не будет
передано содержимое NAME1+8 и NAME2+8.
Процедура C10MOVE аналогична процедуре B10MOVE с двумя исключениями:
она пересылает данные из поля NAME2 в поле NAME3 и использует команду LOOP
вместо DEC и JNZ.
Задание: Введите программу, приведенную на рис.7.5, выполните ее
ассемблирование, компоновку и трассировку с помощью отладчика DEBUG.
Обратите внимание на изменения в регистрах, командном указателе и в стеке.
Для просмотра изменений в полях NAME2 и NAME3 используйте команду D DS:0.

КОМАНДЫ ЛОГИЧЕСКИХ ОПЕРАЦИЙ: AND, OR, XOR, TEST, NOT
________________________________________________________________

Логические операции являются важным элементом в проектировании
микросхем и имеют много общего в логике программирования. Команды AND, OR,
XOR и TEST - являются командами логических операций. Эти команды
используются для сброса и установки бит и для арифметических операций в
коде ASCII (см.гл.13). Все эти команды обрабатывают один байт или одно
слово в регистре или в памяти, и устанавливают флаги CF, OF, PF, SF, ZF.

AND: Если оба из сравниваемых битов равны 1, то результат равен 1; во
всех остальных случаях результат - 0.

OR: Если хотя бы один из сравниваемых битов равен 1, то результат
равен 1; если сравниваемые биты равны 0, то результат - 0.

XOR: Если один из сравниваемых битов равен 0, а другой равен 1, то
результат равен 1; если сравниваемые биты одинаковы (оба - 0 или оба - 1)
то результат - 0.

TEST: действует как AND-устанавливает флаги, но не изменяет биты.

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

AND OR XOR
0101 0101 0101
0011 0011 0011
---- ---- ----
Результат: 0001 0111 0110

Для следующих несвязанных примеров, предположим, что AL содержит 1100
0101, а BH содержит 0101 1100:

1. AND AL,BH ;Устанавливает в AL 0100 0100
2. OR BH,AL ;Устанавливает в BH 1101 1101
3. XOR AL,AL ;Устанавливает в AL 0000 0000
4. AND AL,00 ;Устанавливает в AL 0000 0000
5. AND AL,0FH ;Устанавливает в AL 0000 0101
6. OR CL,CL ;Устанавливает флаги SF и ZF

Примеры 3 и 4 демонстрируют способ очистки регистра. В примере 5
обнуляются левые четыре бита регистра AL. Хотя команды сравнения CMP могут
быть понятнее, можно применить команду OR для следующих целей:

1. OR CX,CX ;Проверка CX на нуль
JZ ... ;Переход, если нуль
2. OR CX,CX ;Проверка знака в CX
JS ... ;Переход, если отрицательно

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

1. TEST BL,11110000B ;Любой из левых бит в BL
JNZ ... ; равен единице?
2. TEST AL,00000001B ;Регистр AL содержит
JNZ ... ; нечетное значение?
3. TEST DX,OFFH ;Регистр DX содержит
JZ ... ; нулевое значение?

Еще одна логическая команда NOT устанавливает обратное значение бит в
байте или в слове, в регистре или в памяти: нули становятся единицами, а
единицы - нулями. Если, например, регистр AL содержит 1100 0101, то
команда NOT AL изменяет это значение на 0011 1010. Флаги не меняются.
Команда NOT не эквивалентна команде NEG, которая меняет значение с
положительного на отрицательное и наоборот, посредством замены бит на
противоположное значение и прибавления единицы (см. "Отрицательные числа"
в гл.1.).

ПРОГРАММА: ИЗМЕНЕНИЕ СТРОЧНЫХ БУКВ НА ЗАГЛАВНЫЕ
________________________________________________________________

Существуют различные причины для преобразований между строчными и
заглавными буквами. Например, вы могли получить файл данных, созданный на
компьютере, который работает только с заглавными буквами. Или некая
программа должна позволить пользователям вводить команды как заглавными,
так и строчными буквами (например, YES или yes) и преобразовать их в
заглавные для проверки. Заглавные буквы от A до Z имеют шест. коды от 41
до 5A, а строчные буквы от a до z имеют шест. коды от 61 до 7A.
Единственная разница в том, что пятый бит равен 0 для заглавных букв и 1
для строчных:

Биты: 76543210 Биты: 76543210
Буква A: 01000001 Буква a: 01100001
Буква Z: 01011010 Буква z: 01111010

COM-программа, приведенная на рис.7.6, преобразует данные в поле
TITLEX из строчных букв в прописные, начиная с адреса TITLEX+1. Программа
инициализирует регистр BX адресом TITLEX+1 и использует его для пересылки
символов в регистр AH, начиная с TITLEX+1. Если полученное значение лежит
в пределах от шест.61 и до 7A, то команда AND устанавливает бит 5 в 0:

AND AH,11011111B

Все символы, отличные от строчных букв (от a до z), не изменяются.
Измененные символы засылаются обратно в область TITLEX, значение в
регистре BX увеличивается для очередного символа и осуществляется переход
на следующий цикл.

__________________________________________________________________________

TITLE CASE (COM) Перекод. в заглавные буквы
0000 CODESG SEGMENT PARA 'CODE'
ASSUME CS:CODESG,DS:CODESG,SS:CODESG
0001 ORG 100H
0001 EB 1C 90 BEGIN: JMP MAIN
; -------------------------------------------
0003 43 68 61 6E 67 65 TITLEX DB 'Change to uppercase letters'
20 74 6F 20 75 70
70 65 72 63 61 73
65 20 6C 65 74 74
65 72 73
; -------------------------------------------
011E MAIN PROC NEAR
011E 8D 1E 0104 R LEA BX,TITLEX+1 ;Адрес первого симв.

0122 B9 001F MOV CX,31 ;Число символов
0125 B20:
0125 8A 27 MOV AH,[BX] ;Символ из TITLEX
0127 80 FC 61 CMP AH,61H ;Это
012A 72 0A JB B30 ; прописная
012C 80 FC 7A CMP AH,7AH ; буква
012F 77 05 JA B30 ; ?
0131 80 E4 DF AND AH,11011111B ;Да - преобразовать
0134 88 27 MOV [BX],AH ;Записать в TITLEX
0136 B30:
0136 43 INC BX ;Следующий символ
0137 E2 EC LOOP B20 ;Повторить цикл 31 раз
0139 C3 RET
013A MAIN ENDP
013A CODESG ENDS
END BEGIN
__________________________________________________________________________

Рис.7.6. Изменение строчных букв на прописные.

Используемый таким образом регистр BX действует как индексный регистр
для адресации в памяти. Для этих целей можно использовать также регистры
SI и DI.

КОМАНДЫ СДВИГА И ЦИКЛИЧЕСКОГО СДВИГА
________________________________________________________________

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

- обрабатывают

Список сторінок

Поділитися у соцмережах

☏ Замовлення реклами: +3805044-68-872

© Асоціація електронних бібліотек України

☝ Усі матеріали сайту (зокрема статті, зображення, рекламні оголошення тощо) призначені лише для попереднього ознайомлення. Усі права на публікації, представлені на сайті, належать їхнім законним власникам. Просимо Вас не зберігати копії інформації.