стека в 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, для собственных
нужд.
ПРОГРАММА: РАСШИРЕННЫЕ ОПЕРАЦИИ ПЕРЕСЫЛКИ
________________________________________________________________
В предыдущих программах были показаны команды пересылки
непосредcтвенных данных в регистр, пересылки данных из памяти в регистр,
пересылки содержимого регистра в память и пересылки содержимого oдного
регистра в другой. Во всех случаях длина данных была огpаничена одним или
двумя байтами и не предусмотрена пересылка данных из одной области памяти
непосредственно другую область. В данном разделе объясняется процесс
пересылки данных, которые имеют длину более двух байт. В гл.11 будет
показано использование операций над строками для пересылки данных из одной
области памяти непосредственно в другую область.
В EXE-программе, приведенной на рис.7.5, сегмент данных cодержит три
девятибайтовых поля, 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
загружают относительные aдреса полей NAME1 и NAME2 в регистры SI и DI:
LEA SI,NAME1 ;Загрузка относительных адресов
LEA DI,NAME2 ; NAME1 и NAME2
Для пересылки содержимого первого байта из поля NAME1 в первый байт поля
NAME2 используются адреса в регистрах SI и DI. kвадратные скобки в
командах MOV обозначают, что для доступа к памяти используется адрес в
регистре, указанном в квадратных cкобках. Таким образом, команда
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