Команды сдвигов и циклических сдвигов 


Мы поможем в написании ваших работ!



ЗНАЕТЕ ЛИ ВЫ?

Команды сдвигов и циклических сдвигов



Эти команды также обеспечивают манипуляции над отдельными битами, перемещая биты операнда влево или вправо на определенное число битов в зависимости от кода операции. Количество битов, на которое выполняется сдвиг, определяется счетчиком сдвигов CNT. Значение счетчика может задаваться статически (непосредственно во втором операнде) или динамически (в регистре CL перед выполнением команды сдвига). Исходя из размерности регистра CL, очевидно, что значение счётчика сдвигов CNT может находиться в диапазоне от 0 до 255. Однако в целях оптимизации процессор воспринимает только значения пяти младших битов счётчика, что сокращает границы его значений до диапазона от 0 до 31.

Все команды сдвига воздействуют на флаг переноса CF. По мере сдвига битов за пределы операнда сначала попадают во флаг переноса CF. В командах сдвига влево с правой стороны операнда «вдвигаются» нули, а старшие биты «выдвигаются» с левой стороны и теряются, но последний из них сохраняется во флаге CF. Команды сдвига вправо аналогичным образом сдвигают биты вправо.

Описание команд линейных и циклических сдвигов представлено в табл. 1.9.

Команды арифметического линейного сдвига отличаются от команд логического сдвига тем, что они воспринимают сдвигаемые значения как числа со знаком и особым образом работают со знаковым битом (седьмым) числа. Но арифметический сдвиг вправо не помещает слева нули, а дублирует в старшие биты знак операнда.

Команды арифметического сдвига позволяют выполнить «быстрое» умножение и деление операнда на степени двойки. Например, сдвиг числа влево на один разряд аналогичен его умножению на 2, а сдвиг числа вправо на один разряд аналогичен делению его на 2. Преимущество этих команд по сравнению с традиционными командами умножения и деления заключается в скорости исполнения: команды сдвига выполняются быстрее.

Команды циклического сдвига отличаются от команд сдвига тем, что операнд считается «кольцом», в котором выдвигаемые с одной стороны биты вдвигаются с другой стороны.

В командах простого циклического сдвига сдвигаемый бит одновременно вдвигается в операнд с другого конца и становится значением флага переноса CF.

 

Таблица 1.9

Формат команд сдвигов и циклических сдвигов

Название команды Мнемоника и формат команды Описание действия
Сдвинуть логически влево SHL OPR,CNT  
7
6
5
4
3
2
1
0
0
флаг CF

Сдвинуть арифметически влево SAL OPR,CNT Не сохраняет знака, но устанавливает флаг OF в случае смены знака очередным выдвигаемым битом. В остальном полностью аналогична команде SHL
Сдвинуть логически вправо SHR OPR,CNT  
7
6
5
4
3
2
1
0
флаг CF
0

Сдвинуть арифметически вправо SAR OPR,CNT   Сохраняет знак, восстанавливая его после сдвига каждого очередного бита. В остальном  аналогична команде SHR
Сдвинуть циклически влево ROL OPR,CNT
7
6
5
4
3
2
1
0
флаг CF

Сдвинуть циклически вправо ROR OPR,CNT
7
6
5
4
3
2
1
0
флаг CF

Сдвинуть циклически влево через перенос RCL OPR,CNT

флаг CF
7
6
5
4
3
2
1
0

Сдвинуть циклически вправо через перенос RCR OPR,CNT
7
6
5
4
3
2
1
0
флаг CF

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

Флажки SF, Z F, PF модифицируются командами линейного сдвига, но команды циклических сдвигов на них не воздействуют. Флажок OF имеет смысл, если только счетчик сдвига равен 1.

Команды сдвигов влияют на состояние флажка АF, но оно определенного смысла не имеет.

Что касается режимов адресации, то OPR может иметь любой режим адресации, кроме непосредственного режима.

Примеры:

mov al,01001101b; Переслать в регистр al двоичное

;значение 01001101 b

shl al; 2; Сдвинуть содержимое регистра al влево на 2 бита

     ; В регистре al появится значение 001101 00 b

     ; Во флаге cf появится значение шестого бита, т.е. 1

mov al,10001101b; Переслать в регистр al двоичное

;значение 1 0001101 b (выделенный бит – знак числа)

sar al, 3; Сдвинуть содержимое регистра al арифметически влево

; на 3 бита

; В регистре al появится значение 1 111 0001 b

; Во флаге cf появится значение 1

mov al,01001101b; Переслать в регистр al двоичное

;значение 01001101 b

rol al; 2; Сдвинуть содержимое регистра al циклически влево

 ; на 2 бита

       ; В регистре al появится значение 001101 01 b

       ; Во флаге cf появится значение шестого бита, т.е. 1

mov al,00000011b; Переслать в регистр al двоичное

;значение 01001101 b

rcr al; 1; Сдвинуть содержимое регистра al циклически влево

 ; с переносом на 1 бит

       ; В регистре al появится значение 0000000 1 b

       ; Во флаге cf появится значение нулевого бита, т.е. 1

rcr al; 1; Циклический сдвиг с переносом вправо на 1 бит

 ; В регистре al появится значение 1 0000000 b

       ; Во флаге cf появится значение нулевого бита, т.е. 1

 

Команды передачи управления

Данные команды нарушают естественный порядок выполнения команд программы.

Изменение потока управления происходит при наличии команд переходов (условного и безусловного), а также вызова процедур.

1. Команды перехода. При выполнении команд перехода в счётчик команд IP принудительно записывается новое значение – новый адрес в памяти, начиная с которого будут выполняться команды.

1.1. Команда безусловного перехода обеспечивает переход по заданному адресу без проверки каких-либо условий.

Формат команды:

JMP Модификатор адрес_перехода

Этой командой задаются внутрисегментные и межсегментные переходы.

Модификатор указывает вид перехода (внутрисегментный прямой, внутрисегментный косвенный, межсегментный прямой, межсегментный косвенный) и принцип изменения содержимого регистров CS и IP. Модификатор не всегда указывается в команде JMP.

Описание команды безусловного перехода для внутрисегментных переходов представлено в табл. 1.10.

Таблица 1.10

Формат команды для внутрисегментных переходов

Вариант внутрисегментного перехода Мнемоника и формат команды Описание действия
Прямой короткий переход (расстояние от команды JMP до адреса перехода не превышает -128 или 127 байт) JMP OPR JMP SHORT PTR OPR (IP) (IP) + 8- битное смещение, определяемое OPR
Прямой переход (на расстояние от 128 байт до 64 Кбайт) JMP OPR JMP NEAR PTR OPR (IP) (IP) + 16- битное смещение, определяемое OPR
Косвенный переход (в команде указывается не сам адрес перехода, а место, где он находится) JMP OPR JMP WORD PTR OPR (IP) (EA), где EA- эффективный адрес перехода, определяемый OPR

 

 

Прямой короткий внутрисегментный переход применятся, когда расстояние от команды JMP до адреса перехода находится в диапазоне от -128 байт (адрес перехода расположен до команды JMP в программе) до +127 байт (адрес перехода расположен после команды JMP в программе). В последнем случае для указания короткого перехода в команде JMP используется модификатор SHORT PTR. При выполнении короткого перехода длина команды безусловного перехода составляет два байта.

Прямой внутрисегментный переход отличается от предыдущего варианта перехода тем, что расстояние между адресом перехода и командой JMP находится в диапазоне от 128 байт до 64 Кбайт, т.е. переходы между командами могут осуществляться в пределах всего сегмента кода. Для уточнения вида перехода может использоваться модификатор NEAR PTR. При выполнении внутрисегментного прямого перехода длина команды безусловного перехода составляет три байта.

В команде косвенного внутрисегментного перехода указывается не сам адрес перехода, а его местоположение, т.е. смещение (эффективный адрес) в сегменте данных. Если адрес ячейки памяти, где хранится адрес перехода, задаётся транслятору через регистр (с помощью команды LEA), то в команде перехода необходимо использовать модификатор WORD PTR для дополнительного сообщения о том, что переход является внутрисегментным.

Примеры:

jmp short ptr met; Выполняется переход на команду с адресом met

…        ; (расстояние до 127 байт)

met: inc ah; Увеличение содержимого регистра ah на 1

met: inc ah; Увеличение содержимого регистра ah на 1

jmp met; Выполняется переход на команду с адресом met

… ; (расстояние до -128 байт)

jmp met; Выполняется переход на команду с адресом met

…    ; (расстояние от 128 байт до 64 Кбайт)

met: inc ah; Увеличение содержимого регистра ah на 1

d_s segment

 a dw met; По адресу a указан адрес команды,

               ; на которую должен быть выполнен переход

d_s ends

c_s segment

assume ds:d_s, cs:c_s

begin:

mov ax, d_s

mov ds, ax

jmp a; Выполняется ближний переход на команду, адрес которой

  ; указан по смещению a в сегменте данных

met: inc ah; Увеличение содержимого регистра ah на 1

c_s ens

end begin

d_s segment

 a dw met; По адресу a указан адрес команды,

               ; на которую должен быть выполнен переход

d_s ends

c_s segment

assume cs:c_s

begin:

mov ax, d_s

mov ds, ax

lea bp,a; Загружается адрес ячейки a в регистр bp

jmp word ptr [bp]; Выполняется ближний косвенный переход

               ; на команду, адрес которой указан в регистре bp

met: inc ah; Увеличение содержимого регистра ah на 1

c_s ens

end begin

Формат команды безусловного перехода для межсегментных переходов описан в табл. 1.11.

При выполнении прямого межсегментного перехода в команде указывается адрес перехода длиной четыре байта, из которых два старшие байта – начальный адрес нового сегмента кода, а младшие два байта – адрес команды (смещение) в этом сегмента кода. Команда прямого межсегментного перехода имеет длину пять байтов. Использование модификатора FAR PTR обязательно.

Таблица 1.11

Формат команды для межсегментных переходов

Вариант межсегментного перехода Мнемоника и  формат команды Описание действия
Прямой переход JMP FAR PTR OPR (CS) начальный адрес сегмента, определяемого OPR (IP) смещение в сегменте из OPR
Косвенный переход JMP FAR PTR OPR JMP DWORD PTR OPR (IP) (EA), где EA – эффективный адрес, определяемый OPR (CS) (EA + 2), где EA – эффективный адрес из OPR

В команде косвенного межсегментного перехода в качестве операнда указывается адрес области памяти, в которой содержатся смещение в новом сегменте и начальный адрес нового всего (всего четыре байта). Если адрес области памяти в команде перехода указан прямо, то используется модификатор FAR PTR, если адрес области памяти указан косвенно, через регистр, то используется модификатор DWORD PTR.

Пример:

d_s segment

a dd c_s1:m1; По адресу a указан адрес перехода в сегмент c _ s 1

               ; по смещению m 1

d_s ends

c_s1 segment

assume cs:c_s1

m1: mov ah,4

add ah,7

jmp c_s:m2

c_s1 ends

c_s segment

assume ds:d_s, cs:c_s

begin:

lea bp, a; В регистр bp загружается адрес ячейки a

jmp dword ptr [bp]; Выполняется безусловный межсегментный

 ; переход по адресу, указанному в регистре bp

m2: mov ah,4ch

int 21h

c_s ends

end begin

Межсегментные передачи управления реализуются только командами безусловных переходов.

Не модифицируются все флажки условий.

Что касается режимов адресации, то во внутрисегментных прямых переходах и межсегментных прямых переходах используется прямой режим. Во внутрисегментных косвенных переходах не допускается непосредственный режим, а в межсегментных косвенных переходах должна адресоваться область памяти.

1.2. Ветвление (условный переход) происходит только при соблюдении определённого условия, в противном случае выполняется следующая по порядку команда программы. Условием, на основании которого осуществляется переход, чаще всего выступают признаки результата выполнения предшествующей арифметической или логической команды (без флага AF). Каждый из признаков фиксируется в своём разряде регистра флагов PSW. Возможен и такой подход, когда решение о переходе принимается в зависимости от состояния одного из регистров общего назначения, куда предварительно помещается результат операции сравнения CMP.

Формат команды CMP представлен в табл. 1.12.

Таблица 1.12

Формат команды сравнения

Название команды Мнемоника и формат команды Описание действия
Сравнить CMP OPR1,OPR2 (OPR1) - (OPR2) Выполняется сравнение путём вычитания операндов, при этом сами операнды не изменяются

Команда CMP устанавливает статусные флаги в зависимости от результата сравнения операндов, не меняя самих операндов.

Команды условного перехода позволяют выполнять только короткие переходы (внутрисегментные прямые переходы в диапазоне от -128 байт до +127 байт).

Команды условного перехода и их формат представлены в табл. 1.13.

Многие команды условного перехода, представленные в табл. 1.13, эквивалентны, так как в них анализируются одинаковые флаги.

 

Таблица 1.13

Формат команд условного перехода

Название команды Мнемоника и формат команды Критерий условного перехода (в CMP) Значение флагов для перехода
1 2 3 4
Перейти, если равно JE OPR OPR1 = OPR2 ZF = 1
Перейти, если не равно JNE OPR OPR1 <> OPR2 ZF = 0
Перейти, если ниже (меньше)/ не выше или равно (без знака) JB/ JNAE OPR OPR1 < OPR2 CF = 1
Перейти, если не ниже (меньше)/ выше или равно (без знака) JNB/ JAE OPR OPR1 >= OPR 2 CF = 0
Перейти, если ниже или равно/ не выше (без знака) JBE/ JNA OPR OPR1 <= OPR2 CF = 1 или ZF = 1
Перейти, если не ниже или равно/ выше (больше) (без знака) JNBE/ JA OPR OPR1 > OPR2 CF = 0 и ZF = 0
Перейти, если меньше/ не больше (со знаком) JL/ JNGE OPR OPR1 < OPR2 SF <> OF
Перейти, если не меньше/ больше или равно (со знаком) JNL/ JGE OPR OPR1 => OPR2 SF = OF
Перейти, если меньше или равно/ не больше (со знаком) JLE/ JNG OPR OPR1 <= OPR2 SF <> OF или ZF = 1
Перейти, если не меньше или равно/ больше (со знаком) JNLE/ JG OPR OPR1 > OPR2 SF = OF и ZF = 0  
Перейти, если ноль JZ OPR [OPR1 = OPR2] ZF = 1
Перейти, если не ноль JNZ OPR [OPR1 <> OPR2] ZF = 0
Перейти, если знак установлен JS OPR [OPR1 < OPR2] SF = 1
Перейти, если знак сброшен JNS OPR [OPR1 > OPR2] SF = 0
Перейти, если есть переполнение JO OPR - OF = 1
Перейти, если нет переполнения JNO OPR - OF = 0

 

Продолжение таблицы 1.13

1 2 3 4
Перейти, если паритет установлен JP OPR - PF = 1
Перейти, если паритет сброшен JNP OPR - PF = 0
Перейти, если перенос установлен JC OPR - CF = 1
Перейти, если перенос сброшен JNC - CF = 0
       

Рассмотрим примеры использования команд условного перехода:

… sub ah,al jz m1 add ah,3 jmp m2 m1: add al,2 m2: mov ah,4 … … cmp ah,al je m1 add ah,3 jmp m2 m1: add al,2 m2: mov ah,4 …

Левый фрагмент иллюстрирует проверку содержимого регистров ah и al на равенство. При этом используются флаги, в частности, флаг нуля ZF. Предварительно выполняется вычитание содержимого регистров: если их значения равны, то в результате образуется ноль и изменяется значение флага ZF. Команда jz проверяет условие: если флаг ZF равен 1, то выполняется переход на команду с адресом m 1, иначе выполняется команда сложения, следующая за командой условного перехода. Команда с адресом m 2 выполняется в любом случае. Правый фрагмент выполняет ту же проверку, но с использованием команды сравнения cmp и команды перехода по равенству содержимого регистров ah и al (je m 1).

2. Организация циклов. Циклы организуются для многократного повторения одной или нескольких команд программы или процедуры. Цикл можно организовать, используя команды условного и безусловного переходов, рассмотренные выше, а можно с помощью специальных команд.

Формат этих команд представлен в таблице 1.14.

Команда LOOP и её расширения позволяет организовывать циклы, подобные циклам for в языках высокого уровня с автоматическим уменьшением счётчика цикла. Количество повторений содержится в регистре CX, который в командах управления циклами выполняет функции счётчика цикла.

Таблица 1.14

Формат команд циклов

Название команды Мнемоника и формат команды Проверяемое условие
Зациклить LOOP OPR CX <> 0
Зациклить, пока ноль или равно LOOPZ/ LOOPE OPR CX <> 0 или ZF = 0
Зациклить, пока не ноль или не равно LOOPNZ/ LOOPNE OPR CX <> 0 или ZF = 1
Переход по CX JCXZ OPR CX = 0

Команды LOOPZ / LOOPE и LOOPNZ / LOOPNE по принципу своей работы являются взаимообратными. Они расширяют действие команды LOOP тем, что дополнительно анализируют флаг нуля ZF. Это даёт возможность организовывать досрочный выход из цикла по значению флага ZF. Обычно эти команды применяются в операциях поиска определённого значения в последовательности или при сравнении двух чисел.

Команда JCXZ по своему формату идентична командам условного перехода. Она выполняет проверку регистра CX и осуществляет переход на команду с указанным адресом, если содержимое регистра CX равно 0. Но, как и в командах цикла, здесь регистр CX тоже играет роль счётчика цикла.

За исключением команды JCXZ, которая не изменяет счётчик цикла CX, остальные команды управления циклами уменьшают текущее содержимое счётчика CX на 1. Затем, если проверяемое условие удовлетворяется, то выполняется переход по адресу, указанному в команде цикла. В противном случае осуществляется переход на команду, следующую после LOOP или её расширений, т.е. выполняется выход из цикла.

Операнд OPR должен быть меткой, которая находится в диапазоне от -128 до127 байт от команды, следующей за командой цикла. Это означает, что команды цикла позволяют выполнять короткие внутрисегментные переходы. Для работы с длинными циклами следует использовать команды условного перехода и команду JMP.

Часто возникает необходимость в организации вложенных циклов. Основная проблема, которая при этом возникает – как сохранить значения счётчиков CX для каждого цикла. Для временного хранения значений счётчиков внешнего и внутреннего циклов можно использовать другие регистры процессора, ячейки памяти или стек.

Примеры:

m1: cmp ah,al; Сравнение содержимого регистров ah и al

jg m2; Если содержимое ah больше значения в al,

  ; то выполняется переход на метку m2 (выход из цикла)

add ah,3; иначе, увеличивается содержимое регистра ah на 3

jmp m1; Выполняется переход на метку m2 (начало цикла)

m2: mov ah,4

mov cx,20; Количество повторений внешнего цикла

с1: push cx; Помещение счётчика внешнего цикла в стек

…           ; Команды внешнего цикла

mov cx,10; Количество повторений внутреннего цикла

c2:

…           ; Команды внутреннего цикла

loop c2; Конец внутреннего цикла

… ; Команды внешнего цикла

pop cx; Восстановление из стека счётчика внешнего цикла

loop c1; Конец внешнего цикла

В первом примере цикл организуется с помощью команд условного и безусловного переходов. Увеличение содержимого регистра ah на 3 будет выполняться, пока содержимое регистра ah меньше содержимого регистра al.

Во втором примере описаны вложенные циклы. Для временного хранения счётчика внешнего цикла используется стек. Перед запуском внутреннего цикла текущее содержимое регистра cx запоминается в стеке. Затем в cx помещается значение счётчика внутреннего цикла, и выполняются его команды. По окончании внутреннего цикла выполняются команды внешнего цикла. После этого из стека извлекается значение счётчика внешнего цикла для последующей проверки условий внешнего цикла.

3. Процедуры. Процедура (подпрограмма) – это группа команд для решения конкретной подзадачи, обладающая средствами получения управления из точки вызова задачи более высокого уровня и возврата управления в эту точку.

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

Общее описание процедуры представлено на рисунке 10.

Процедура ограничивается операторами PROC и ENDP, перед которыми указывается имя процедуры. После PROC указывается тип процедуры: процедура ближнего вызова (директива NEAR) или процедура дальнего вызова (директива FAR). В первом случае процедура располагается в том же сегменте кода, что и основная программа, и при вызове такой процедуры выполняется внутрисегментный переход. Во втором случае процедура располагается в другом сегменте кода, и при её вызове выполняется межсегментный переход.

Имя процедуры
PROC
NEAR или FAR
Тело процедуры (команды и директивы языка ассемблера)
RET
Имя процедуры
ENDP

Рис. 10. Общее описание процедуры

Между этими операторами располагается тело процедуры, состоящее из команд и директив языка ассемблера. Последней командой процедуры является команда RET, по которой осуществляется возврат из данной процедуры в вызвавшую её программу или другую процедуру на команду, следующую за командой последнего вызова процедуры.

Вызов процедуры осуществляется командой CALL, за которой следует имя процедуры. Формат команды CALL:

CALL Модификатор имя_процедуры

Модификатор может принимать значения NEAR или FAR, для обращения к процедурам ближнего или дальнего вызовов соответственно.

Для работы с процедурами используется стек (дополнительная память, организованная в виде очереди), в который команда вызова помещает текущее значение счётчика команд (IP) при внутрисегментных переходах (или значения регистров IP и CS при межсегментных переходах) – адрес точки возврата. При выходе из процедуры старые значения соответствующих регистров восстанавливаются из стека.

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

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

1. В начале программы (до первой исполняемой команды).

c_s segment

assume cs:c_s

Pr1 proc near

Ret

P1 endp

begin:      ;начало программы

end begin

2. В конце программы (после команды корректного завершения работы и возвращения управления операционной системе – ОС).

c_s segment

assume cs:c_s

begin:

mov ah, 4ch

int 21h;корректное завершение работы и передача управления ОС

P1 proc near

Ret

P1 endp

c_s ends

end begin

3. Внутри тела программы или другой процедуры (должен быть предусмотрен обход процедуры с помощью оператора JMP).

c_s segment

assume cs:c_s

begin:

jmp m1

P1 proc near

Ret

P1 endp

m1: …

mov ah, 4ch

int 21h;корректное завершение работы и передача управления ОС

c_s ends

end begin

4. В другом модуле – часто используемые процедуры выносятся в отдельный файл, который оформляется как обычный файл ассемблера, а затем подвергается трансляции для получения объектного кода. Впоследствии этот объектный файл с помощью компоновщика можно объединить с файлом, в котором все или некоторые данные процедуры используются.

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

Обычно, если в программе используются процедуры, то в ней описывается сегмент стека для резервирования ячеек под дополнительную память. Если сегмент стека в программе отсутствует, то в этом случае операционная система формирует стек самостоятельно.

В обычной последовательности вызовов существует чёткое различие между вызываемой и вызывающей процедурами. Вызываемая процедура каждый раз начинается сначала, сколько бы раз не происходило обращение к ней. Для выхода из вызываемой процедуры используется команда возврата RET.

Взаимодействие вызывающей и вызываемой процедур иллюстрирует рисунке 11.

Вызывающая процедура A
Вызываемая  процедура B
Процедура A вызывается из основной программы
Процедура A возвращается в основную программу

Рис. 11. Взаимодействие вызывающей и вызываемой процедур

Рассмотрим в качестве примера программу, использующую вызов процедуры.

s_s segment stack "stack"

dw 12 dup(?)

s_s ends

d_s segment

 aa dw 10

d_s ends

c_s segment

 assume ss:s_s,ds:d_s,cs:c_s

begin:

 mov ax,d_s

 mov ds,ax

  call pr1;вызов подпрограммы

  mov ah,4ch

 int 21h

pr 1 proc near   ;начало подпрограммы (ближний вызов)

 push ax        ;записать в стек содержимое регистра AX

 mov ax, aa

 pop ax          ;выбрать из стека содержимое регистра AX

  ret                      ;команда возврата на следующую команду после

                      ;вызова процедуры

pr 1 endp        ;конец подпрограммы

c_s ends

end begin

Поскольку процедура расположена в том же сегменте кода, что и основная программа и описана как процедура ближнего вызова (директива NEAR), то переход будет внутрисегментным

При выполнении вызова процедуры pr 1 (команда call pr 1) в стек помещается адрес возврата – значение счётчика команд IP, содержащего на данный момент адрес команды, которая должна будет выполняться после текущей (mov ah,4 ch). Значение регистра IP замещается новым значением – адресом первой команды процедуры. При достижении команды возврата из процедуры (ret) из стека в регистр IP записывается старое значение, что обеспечивает возврат в основную программу на команду, которая непосредственно следует за командой вызова процедуры.

Стековые команды

Организация стека. Стек – это однонаправленная очередь, данные в которую помещаются и извлекаются в строго определённом порядке. Стековая память обеспечивает такой режим работы, когда информация записывается и считывается по принципу «последним записан – первым считан» (LIFO – Last Input First Output). Такая память используется для временного хранения данных, например, запоминания и восстановления регистров процессора (контекста) при обработке подпрограмм и прерываний. Работу стековой памяти поясняет рисунок 12.

 
A
 
A
B
A
B
C
D
E
F
H
A
B
C
D
E
F
H
 
A
B
C
D
E
F
H
 
A
Занесение в стек
Извлечение из стека

Рис.12. Логика работы стековой памяти

Когда слово A заносится в стек, то располагается в первой свободной ячейке. Каждое следующее записываемое слово перемещает всё содержимое стека на одну ячейку вверх и занимает освободившуюся ячейку. Запись очередного слова после H приводит к переполнению стека, поскольку он рассчитан на 7 слов, и потере кода A.

Считывание информации из стека осуществляется в обратном порядке, т.е., начиная с кода H, который был записан последним. Доступ к произвольному коду в стеке формально недопустим до извлечения всех данных, записанных позже.

Занесение информации в стек называется включением, считывание информации из стека – извлечением.

В настоящее время наиболее распространённым является внешний, или аппаратно-программный, стек, в котором для хранения информации отводится область оперативной памяти. Обычно под стек отводится участок памяти с наибольшими адресами, а расширяется стек в сторону уменьшения адресов.

На рисунке 13 показана схема организации стека для процессора Intel 8086. Под стек выделяется отдельный сегмент – сегмент стека, начальный адрес которого помещается в соответствующий сегментный регистр – SS. Адресация стека обеспечивается специальным регистром – указателем стека SP, в который предварительно помещается наибольший адрес области основной памяти, отведённой под стек (дно стека). Адрес последнего включённого в стек элемента называется вершиной стека (TOS – Top Of Stack). Размер стека зависит от режима работы процессора и ограничивается значением 64 Кбайт в обычном режиме (или 4 Гбайт в защищенном режиме).

В каждый момент времени доступен только один стек, начальный адрес сегмента которого содержится в регистре SS. Для перехода к другому стеку необходимо загрузить в SS его адрес. По мере записи данных в стек он растет в сторону младших адресов памяти.

Для работы со стеком существуют две основные операции: добавление элемента в вершину стека (PUSH) и извлечение элемента из вершины стека (POP). Формат команд представлен в табл. 1.15.

Таблица 1.14

Формат стековых команд

Название команды Мнемоника и формат команды Описание действия
Включить в стек PUSH SRC (SP) (SP) – 2 (SS:SP) (SRC)
Извлечь из стека POP DST (DST) (SS:SP) (SP) (SP) + 2

Команда PUSH имеет один операнд, который может быть двухбайтовым регистром, кроме регистра CS, или ячейкой памяти такого же размера. При записи в стек данного сначала производится уменьшение на 2 содержимого указателя стека SP (стек оперирует словами), а затем по адресу, указываемому парой SS: SP, производится запись операнда - источника.

Команда POP также имеет один операнд, который может быть двухбайтовым регистром, кроме регистра CS, или ячейкой памяти. При считывании слова из стека в качестве адреса берётся текущее содержимое указателя стека в сегменте стека (SS: SP), а после извлечения данного слова в операнд - приёмник содержимое SP увеличивается на 2.

Младшие (меньшие) адреса оперативной памяти
Старшие (большие) адреса оперативной памяти
Дно стека
Начальное значение SP (стек пуст)
Адрес начала сегмента стека в SS
Последний элемент
Вершина стека (текущее значение SP)
Направление роста стека

Рис. 13. Схема организации стека для процессора Intel 8086

Когда стек пуст, то значение регистра SP равно адресу последнего байта сегмента (самому старшему адресу ячейки памяти в сегменте), выделенного под стек. Когда стек заполнен, то значение регистра SP становится равным значению регистра SS, и дальнейшее добавление элементов невозможно.

При помещении элементов в стек адрес вершины стека (содержимое регистра SP) уменьшается (смещается в сторону меньших адресов), а при извлечении элементов из стека – увеличивается (смещается в сторону больших адресов).

Рассмотрим следующий пример:

push 35h

push 57h

pop ax

Состояние стека при выполнении указанных выше команд иллюстрирует рисунок 14.



Поделиться:


Последнее изменение этой страницы: 2020-12-09; просмотров: 195; Нарушение авторского права страницы; Мы поможем в написании вашей работы!

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 3.131.110.169 (0.23 с.)