|
В гл.3 обсуждалось, как реализован стек в
микропроцессоре 8088.
Микропроцессор 8088 адресует стек с
помощью регистровой пары SS:SP.
Помещение объектов в стек приводит к тому,
что он растет в сторону
меньших адресов памяти.Стек, кроме всего прочего, служит и для
запоминания адресов возврата из
подпрограмм.В этом разделе
рассматриваются некоторые команды, которые
непосредственно работают
со стеком.
Фиг.4.7 иллюстрирует ассемблированные
стековые команды.
Мнемоника команд очевидна; за кодами
операций PUSH и POP следует
имя регистра для указания операнда.
Единственным исключением
является помещение и извлечение из стека
регистра флагов, которые
используют мнемонику PUSHF и POPF
соответственно. Содержимое любой
ячейки памяти, которую программа может
адресовать, используя
возможные способы адресации, также может
быть помещено или
извлечено из стека.
При любых действиях со стеком в
микропроцессоре 8088 базовой
единицей информации является 16=битовое
слово. Длина любого
объекта, помещаемого в стек либо
извлекаемого из стека, составляет
одно или несколько слов. Байтовых команд,
связанных с засылкой
данных или извлечением их из стека, не
существует. Если, например,
программе необходимо сохранить содержимое
регистра AL а стеке, она
должна поместить содержимое регистра AX,
так как не существует
способа сохранения только содержимого
регистра AL.
Основное назначение стека - временное
хранение информации. Как
мы уже видели, стек используется для
сохранения адреса возврата;
программа также может сохранять данные.
Если программа хочет
использовать регистр, пусть даже сохранить
текущие данные, она
может послать значение этого регистра в
стек. Эти данные
сохраняются в стеке и позже могут быть
восстановлены. Например,
Microsoft (R) Macro Assembler Version 5.001/1/80 04:00:43
Фиг. 4.7 Операции со стеком
Page1-1
PAGE,132
TITLEФиг. 4.7 Операции со стеком
0000CODESEGMENT
ASSUMECS:CODE,DS:CODE
0000EXWORDLABELWORD
000050PUSHAX ;
Поместить регистр в стек
000156PUSHSI
00020EPUSHCS ;
Можно поместить в стек сегментный регистр
0003FF 36 0000 RPUSHEXWORD; Можно также поместить в стек ячейку памяти
00078F 06 0000 RPOPEXWORD; Можно извлечь то, что в помещено в стек
000B07POPES ;
Можно извлечь в другое место
000C5FPOPDI
000D5BPOPBX
000E9CPUSHF; Другая мнемоника для флагов
000F9DPOPF
;-----Пример, демонстрирующий передачу параметров
001050PUSHAX
001153PUSHBX
001251PUSHCX
001352PUSHDX
0014E8 0017 RCALLSUBROUTINE; Передача управления
;...; Продолжение программы
0017SUBROUTINEPROCNEAR
00178B ECMOVBP, SP; Занесение в BP адреса стека
00198B 46 02MOVAX, [BP+2]; Выборка последнего параметра (DX)
001C8B 5E 04MOVBX, [BP+4]; Выборка третьего параметра (CX)
001F8B 4E 06MOVCX, [BP+6]; Выборка второго параметра (BX)
00228B 56 08MOVDX, [BP+8]; Выборка первого параметра (AX)
;...
0025C2 0008RET8; Возврат с уничтожением поля параметров
0028SUBROUTINEENDP
0028CODEENDS
END
Фиг. 4.7 Операции со стеком
программе нужно ввести код из порта
ввода=вывода 3DAH, а в регистре
DX находятся важные данные. Следующая
последовательность команд
PUSHDX
MOV DX,3DAH
INAL,DX
POP DX
сохраняет регистр DX в стеке на то время,
пока он нужен в
программе для выполнения команды IN.
Операции сохранения регистров в стеке
обычно используется в
начале программы. В большинстве случаев
подпрограмма старается
избегать изменения содержимого любого
регистра. Поэтому
подпрограмма, которой нужны регистры для
вычислений и для хранения
адресов, помещает все необходимые ей
регистры в стек до выполнения
команд обработки. Затем, после выполнения,
подпрограмма
восстанавливает регистры из стека с
помощью команд POP.
Помните о том, что стек - это структура
типа LIFO. Если в вашей
программе выполняется последовательность
команд
PUSHBX
PUSH CX
POP BX
POP CX
то результирующим эффектом будет обмен
значений в регистрах BX
и CX. Только тот факт, что в команде PUSH
был указан регистр BX, не
означает, что команда POP, указывающая на
тот же регистр,
восстанавливает первоначальное содержимое
регистра BX. Еще одним
важным моментом является то, что команды
PUSH и POP должны быть
сбалансированы, т.е. каждой команде PUSH
должна соответствовать
команда POP. Точно так же, как и в случае
скобок в арифметическом
выражении, если посылки и извлечения из
стека не сбалансированы,
результаты будут неверны. Более того,
несбалансированные команды
PUSH/POP обычно приводят к возврату из
подпрограмм по адресу
значения данных, а не значения указателя
команд из=за того, что
микропроцессор 8088 записывает в стек
адрес возврата. Обычно это
вынуждает микропроцессор выполнять
программу, которую программист
никогда не писал. Поэтому баланс стековых
команд обязателен. Будьте
особенно внимательны в тех случаях, когда
в программе есть условный
переход вокруг стековых операций; можно
легко выпустить из виду
один из вариантов выполнения, что оставит
стек несбалансированным.
Наряду с сохранением данных, программа
может использовать стек
в качестве буфера при некоторых
пересылках; в частности, не
существует команды пересылки, которая бы
переносила данные из
одного сегментного регистра в другой. В
обычном случае загрузка
одного сегментного регистра из другого
требует сначала загрузки его
значения а промежуточный регистр. Это
достигается следующей
последовательностью из двух команд:
MOVAX,CS;переслать значение регистра
;CS в регистр AX
MOVDS,AX;загрузить это значение в
; регистр DS
Каждая из этих команд имеет длину
несколько байт, и эта
последовательность разрушает содержимое
регистра AX. Альтернативным
подходом может быть
PUSHCS;
регистр CS поместить в стек
POPDS;
поместить это значение в регистр DS
Результирующий эффект этой
последовательности команд тот же,
регистр DS загружается из регистра CS.
Здесь длина программы -
всего два байта, и к тому же не требуется
промежуточный регистр.
Однако эти две команды занимают больше
времени, так как нужны
дополнительные циклы чтения и записи в
стек. Это - метод потери в
скорости выполнения ради уменьшения
размера объектного кода.
|