Попов И.И., Матвеев А.А., Максимов Н.В. Архитектура электронно-вычислительных машин и систем (2004) (1186255), страница 97
Текст из файла (страница 97)
Переход (возврат) по адресу из стека:RET opИз стека считывается адрес и по нему производится переход. Еслиуказан операнд (а это должно быть неотрицательное число), то послечтения адреса стек еще очищается на это число байтов (к SP добавляетсяэто число). Команда используется для возврата из подпрограммы поадресу, записанному в стек по команде CALLпри вызове494подпрограммы, и одновременной очистки стека от параметров, которыеосновная программа занесла в стек перед обращением к подпрограмме.Команда RET имеет две разновидности (хотя в MASM онизаписываются и одинаково):— в одном случае из стека считывается только одно слово - смещениеадреса возврата,— во втором - из стека считывается пара seg:ofs, указывающаяабсолютный адрес возврата.
Как ассемблер определяет, какой из этихдвух случаев имеет место, объяснено ниже.В I80Х86 стек в основном используется для организацииподпрограмм и прерываний. Однако даже если программе не нуженстек, она все равно должна отвести под него место. Дело в том, чтостеком будет неявно пользоваться операционная система при обработкепрерываний, которые возникают (например, при нажатии клавиш наклавиатуре) в то время, когда выполняется программа. Для нужд ОСрекомендуется выделять в стеке 64 байта.ПрерыванияИногда необходимо выполнить одну из набора специальныхпроцедур, если в системе или в программе возникают определенныеусловия, например, нажата клавиша на клавиатуре.
Действие, стимулирующее выполнение одной из таких процедур, называется прерыванием, поскольку основной процесс при этом приостанавливается навремя выполнения этой процедуры. Существует два общих классапрерываний: внутренние и внешние. Первые инициируютсясостояниемЦП или командой, а вторые - сигналом, подаваемым от другихкомпонентов системы. Типичные внутренние прирывания: деление нануль, переполнение и т.п., а типичные внешние - это запрос наобслуживание со стороны какого-либо устройства ввода/ вывода.Переход к процедуре прерывания осуществляется из любойпрограммы, а после выполнения процедуры прерывания обязательнопроисходит возврат в прерванную программу.
Перед обращением кпроцедуре прерывания должно быть сохранено состояние всех регистров и флагов, используемых процедурой прерывания, а послеокончания прерывания эти регистры должны быть восстановлены.495Прерывание вынуждает процессор прекратить выполнение однойпоследовательности команд и начать выполнение другой, при этом адресочередной команды, которая должна была бы выполняться (содержимоерегистра IP), если бы не было прерывания, запоминается. Адрескоманды, которая должна выполняться после возникновенияпрерывания, выбирается из таблицы, хранящейся в начальной областипамяти. Эта таблица называется таблицей векторов прерываний.
Втаблице записано 256 адресов. Когда устройство вызывает прерываниепроцессора, оно сообщает ему, какой адрес из таблицы следуетиспользовать для перехода к новой последовательности команд.Аппаратное прерываниеНа рисунке изображены процессор, запоминающее устройство стаблицей адресов, система прерываний, внешнее устройство, требующеепрерывания, и восьмиразрядная шина адреса прерывания, по которой изсистемы прерываний процессору передается указание о том, какой адресиз таблицы векторов прерываний должен быть использован приполучении процессором сигнала аппаратного прерывания. Связьсистемы прерываний с процессором осуществляется с помощью шиныпрерываний INTR; появление на этой шине, обычно находящееся всостоянии 1, сигнала 0 приводит к прерыванию работы процессора.496Справа от системы прерываний изображены четыре шины,соединяющие ее с устройствами, которые могут потребоватьпрерывания работы процессора, и, в частности, устройство, требующеевнимания со стороны процессора и использующее для прерывания шинуINT3.Прерывание возникает тогда, когда устройство, требующеепрерывания (например, печатающее устройство), посылает сигнална шину INT3.
Система прерываний выявляет наличие сигнала на шинеи реагирует на него; т. е. помещает восьмибитовое число на шину адресапрерывания и устанавливает 0 на шине прерываний INTR. Процессор,определив, что на шине INTR появился сигнал 0, запоминает адрескоманды, которая должна была бы выполняться следующей. Затем садресной шины прерываний считывается число, указывающее, какойадрес необходимо извлечь из таблицы векторов прерываний, ипроцессор переходит к выполнению команды, начинающейся с этогоадреса.Типичным примером устройства, требующего прерывания,является клавиатура. После нажатия клавиши на клавиатуре. В системупрерываний передается сигнал, приводящий к прерыванию работыпроцессора. Очевидно, что процессор прекращает текущую работу и,используя адрес, переданный из системы прерываний, начинаетвыполнение специальной программы взаимодействия с клавиатурой.Программа вводит с клавиатуры код, соответствующий нажатойклавише, и заносит его в область сохранения, расположенную в памяти.497Затем программа взаимодействия с клавиатурой возвращает управлениепрограмме, которая выполнялась до прерывания.Программные прерыванияПрерывания могут также иметь место при выполнении специальной команды: прервать, используя адрес X.
(Число X указывает одиниз адресов в таблице векторов прерываний.) При выполнении команды«прервать» процессор определяет и запоминает адрес команды, котораядолжна была бы выполняться следующей, а затем переходит квыполнению программы, начинающейся с адреса X, извлеченного изтаблицы векторов прерываний.
Такая последовательность действий называется программным прерыванием.ПодпрограммыТипичная схема организации подпрограмм, обычно используемаятрансляторами с языков высокого уровня для реализации процедур ифункций (в частности, рекурсивных), следующая.При обращении к подпрограмме в стек заносятся параметры длянее и адрес возврата, после чего делается переход на ее начало:PUSH param1 ;запись 1-го параметра в стек...PUSH paramk ;запись последнего (k-го) параметра в стекCALL subr ;переход в возратом на подпрограмму(если необходимо вычислить параметр или если его размер отличен отслова, тогда для записи параметра в стек нужно, конечно, несколькокоманд, а не одна.)Первыми командами подпрограммы обычно являются следующие:PUSH BP;сохранить в стеке старое значение BPMOV SP,BP ;установить BP на вершину стекаSUB SP,m;отвести в стеке место (m байтов) под локальныевеличины подпрограммы.Пояснимэти "входные" команды.В подпрограммедляобращения к ячейкам стека, занятых параметрами, используется (какбазовый) регистр BP: если в BP занести адрес вершины стека, то длядоступа к этим ячейкам следует использовать адресные выражения видаi[BP] или, что то же самое, [BP+i].
(Отметим, что применять здесьрегистры-модификаторы BX, SI и DI нельзя, т.к. формируемые по нимисполнительные адреса будут сегментироваться по умолчанию порегистру DS, а в данном случае нужно сегментирование по SS.) Однакоданная подпрограмма может быть вызвана из другой, такжеиспользующей регистр BP, поэтому прежде, чем установить BP навершину стека, надо спасти в стеке старое значение этого регистра,что и делает первая из "входных" команд.498Вторая же команда устанавливает BP на вершину стека.
Еслипредположить, что каждый параметр и адрес возврата занимают послову памяти, тогда доступ к первому параметру обеспечиваетсяадресным выражением [BP+4], ко второму - выражением [BP+6] и т.д.Подпрограмме может потребоваться место для ее локальныхвеличин. Такое место обычно отводится в стеке (а для рекурсивныхподпрограмм только в стеке) "над" ячейкой, занимаемой старымзначением BP. Если под эти величины нужно m байтов, то такой"захват" места можно реализовать простым уменьшением значениярегистра SP на m, что и делает 3-я "входная" команда.
Доступ клокальным величинам обеспечивается адресными выражениями вида[BP-i]. Если подпрограмме не нужно место под локальные величины,тогда третью из "входных" команд следует опустить.Выход из подпрограммы реализуется следующими командами:MOV SP,BP ;очистить стек от локальных величинPOP BP;восстановить старое значение BPRET 2*k;возврат из подпрограммы и очистка стека отпараметров (считаем, что они занимают 2*k байтов).Первая из этих "выходных" команд заносит в регистр SP адрес тойячейки стека, где хранится старое значение регистра BP, т.е.
происходиточистка стека от локальных величин (если их не было, то даннуюкоманду надо опустить). Вторая команда восстанавливает в BP этостарое значение, одновременно удаляя его из стека. В этот моментсостояние стека будет таким же, как и перед входом в подпрограмму.Третья команда считывает из стека адрес возврата (в результате чего SP"опускается" на 2 байта), затем добавляет к SP число, которое должноравняться числу байтов, занимаемых всеми параметрами подпрограммы,и затем осуществляет переход по адресу возврата. В этот моментсостояние стека будет таким же, каким оно было перед обращением кподпрограмме.Здесь описана универсальная схемаорганизации работыподпрограмм. В конкретных случаях могут использоваться болеепростые схемы.
Например, параметры можно передавать не через стек,а через регистры, место под локальные величины можно отводить не встеке, а в сегменте данных и т.п.Процедуры в ассемблереПри составлении и вызове подпрограмм необходимо следить затем, чтобы команды CALL и RET действовали согласовано - былиодновременно близкими или дальними. В MASM эта проблемаснимается, если подпрограмму описать как процедуру. Процедурыимеют следующий вид:499имя_процедуры PROC [NEAR или FAR]...имя_процедуры ENDPХотя в директиве PROC после имени процедуры не ставитсядвоеточие, это имя относится к меткам и его можно указывать вкомандах перехода, в частности в команде CALL, когда надо вызватьпроцедуру.