Попов И.И., Матвеев А.А., Максимов Н.В. Архитектура электронно-вычислительных машин и систем (2004) (1186255), страница 96
Текст из файла (страница 96)
В связи с этим все строковые команды имеют дверазновидности489— для работы со строками из байтов (в мнемонику операций входитбуква B)— для работы со строками из слов (в мнемонику входит W).Имеются следующие операции над строками:— пересылка элементов строк (в память, из памяти, память-память);— сравнение двух строк;— просмотр строки с целью поиска элемента, равного заданному.Каждая из этих операций выполняется только над однимэлементом строки, однако одновременно происходит автоматическаянастройка на следующий или предыдущий элемент строки.
Имеютсяспециальные команды повторения (REP и др.), которые заставляютследующую за ними строковую команду многократно повторяться (до216 раз), в связи с чем такая пара команд позволяет обработать всюстроку, причем намного быстрее, чем запрограммированный цикл.Кроме того, строки можно просматривать вперед (от их начала кконцу) и назад.
Направление просмотра зависит от флага направленияDF, значение которого можно менять с помощью команд STD(DF:=1) и CLD (DF:=0). При DF=0 все последующие строковые командыпрограммы просматривают строки вперед, а при DF=1 - назад.В строковых командах операнды явно не указываются,аподразумеваются. Если команда работает с одной строкой, то адресочередного, обрабатываемого сейчас элемента строки задается паройрегистров DS и SI или парой ES и DI, а если команда работает с двумястроками, то адрес элемента одной из них определяется парой DS:SI, аадрес элемента другой - парой ES:DI. После выполнения операциизначениерегистра SI и/или DI увеличивается (при DF=0) илиуменьшается (при DF=1) на 1 (для байтовых строк) или на 2 (для строкиз слов).Начальная установка всех этих регистров, а также флага DFдолжна быть выполнена до начала операции над строкой.
Еслисегментный регистр DS уже имеет нужное значение, тогда загрузитьрегистр SI можно с помощью командыLEA SI,<начальный/конечный адрес строки>Если же надо загрузить сразу оба регистра DS и SI, тогда можновоспользоваться командойLDS SI,m32которая в регистр SI заносит первое слово, а в регистр DS - второеслово из двойного слова, имеющего адреc m32 (таким образом, поадресу m32+2 должен храниться сегмент, а по адресу m32 - смещениеначального или конечного элемента строки). Начальную загрузкурегистров ES и DI обычно осуществляют одной командойLES DI,m32которая действует аналогично команде LDS.490Перечислим вкратце строковые команды I80Х86.— команда загрузки элемента строки в аккумулятор (LODSB илиLODSW) пересылает в регистр AL или AX очередной элементстроки, на который указывает пара DS:SI, после чего увеличивает(при DF=0) или уменьшает (при DF=1) регистр SI на 1 или 2;— запись аккумулятора в строку (STOSB или STOSW); содержимоерегистра AL или AX заносится в тот элемент строки, на которыйуказывает пара ES:DI, после чего изменяет регистр DI на 1 или 2;— пересылка строк (MOVSB или MOVSW); элемент первой строки,определяемый парой DS:SI, заносится в элемент второй строки,определяемый парой ES:DI, после чего одновременно меняетрегистры SI и DI;— сравнение строк (CMPSB или CMPSW); сравниваются очередныеэлементы строк, указываемые парами DS:SI и ES:DI, и результатсравнения (равно, меньше и т.п.) фиксирует в флагах, после чегоменяется содержание регистров SI и DI;— сканирование строки (SCASB или SCASW) - сравнивается элементстроки, адрес которого задается парой ES:DI, со значением регистраAL или AX и результат сравнения фиксирует в флагах, после чегоменяется содержимое регистра DI.Перед любой строковой командой можно поставить одну из двухкоманд, называемых "префиксами повторения", которая заставитмногократно повториться эту строковую команду.
Число повторений(обычно это длина строки) должно быть указано в регистре CX.Префикс повторения REPZ (синонимы - REPE, REP) сначалазаносит 1 в флаг нуля ZF, после чего, постоянно уменьшая CX на 1,заставляет повторяться следующую за ним строковую команду до техпор, пока в CX не окажется 0 или пока флаг ZF не изменит своезначение на 0.Другой префикс повторения REPNZ (синонимREPNE)действует аналогично, но только вначале устанавливает флаг ZF в 0, апри изменении его на 1 прекращает повторение строковой команды.Пример. Пусть надо переписать 10000 байтов начиная с адреса Aв другое место памяти начиная с адреса B. Если оба этих имениотносятся к сегменту данных, на начало которого указывает регистр DS,тогда эту пересылку можно сделать так:CLD;DF:=0 (просмотр строки вперед)MOV CX,1000 ;CX - число повторенийMOV AX,DSMOV ES,AX ;ES:=DSLEA SI,A;ES:SI - "откуда"LEA DI,B ;DS:DI - "куда"REP MOVSB ;пересылка CX байтов491Стек.
ПодпрограммыСтек. В I80Х86 имеются специальные команды работы со стеком,т.е. областью памяти, доступ к элементам которой осуществляется попринципу "последним записан - первым считан". Но для того, чтобыможно было воспользоваться этими командами, необходимособлюдение ряда условий.Во многих случаях программе требуется временно запомнитьинформацию, а затем считывать ее в обратном порядке. Эта проблема вПК решена посредством реализации стека LIFO ("последний пришел первый ушел"), называемого также стеком включения/извлечения (stack- кипа, например, бумаг).
Наиболее важное использование стека связанос процедурами. Стек обычно рассчитан на косвенную адресацию черезрегистр SP - указатель стека. При включении элементов в стекпроизводится автоматический декремент указателя стека, а приизвлечении - инкремент, то есть стек всегда "растет" в сторону меньшихадресов памяти. Адрес последнего включенного в стек элементаназывается вершиной стека (TOS).Под стек можно отвести область в любом месте памяти. Размер ееможет быть любым, но не должен превосходить 64Кб, а ее начальныйадрес должен быть кратным 16. Другими словами, эта область должнабыть сегментом памяти; он называется сегментом стека.
Начало этогосегмента (первые 16 битов начального адреса) должно обязательнохраниться в сегментном регистре SS.Хранимые в стеке элементы могут иметь любой размер, однакоследует учитывать, что в I80Х86 имеются команды записи в стек ичтения из него только слов. Поэтому для записи байта в стек его надопредварительно расширить до слова, а запись или чтение двойныхслов осуществляются парой команд.В I80Х86 принято заполнять стек снизу вверх, от большихадресов к меньшим: первый элемент записывается в конец области,отведенной под стек, второй элемент - в предыдущую ячейку области ит.д.
Считывается всегда элемент, записанный в стек последним. Всвязи с этим нижняя граница стека всегда фиксирована, а верхняя меняется.Слово памяти, в котором находится элемент стека,записанный последним, называется вершиной стека. Адрес вершины,отсчитанный от начала сегмента стека, обязан находиться в указателестека - регистре SP. Таким образом, абсолютный адрес вершины стекаопределяется парой SS:SP.492Значение 0 в регистре SP свидетельствует о том, что стекполностью заполнен (его вершина "дошла" до начала области стека).Поэтому для контроля за переполнением стека надо перед новойзаписью в стек проверять условие SP=0 (сам I80Х86 этого не делает).Для пустого стека значение SP должно равняться размеру стека, т.е.
параSS:SP должна указывать на байт, следующий за последним байтомобласти стека. Контроль за чтением из пустого стека, если надо, обязанаделать сама программа.Начальная установка регистров SS и SP может быть произведена всамой программе,однако в MASM предусмотрена возможностьавтоматической загрузки этих регистров. Если в директиве SEGMENT,начинающей описание сегмента стека, указать параметр STACK, тогдаассемблер (точнее, загрузчик) перед тем, как передать управление напервую команду машинной программы, загрузит в регистры SS и SPнужные значения.
Например, если в программе сегмент стека описанследующим образом:ST SEGMENT STACKDB 256 DUP(?) ;размер стека - 256 байтовST ENDSи если под этот сегмент была выделена область памяти начиная сабсолютного адреса 12340h, тогда к началу выполнения программы врегистре SS окажется величина 1234h, а в регистре SP - величина 100h(=256).Отметим, что эти значения соответствуют пустому стеку.Основные стековые командыПри соблюдении указанных требований в программе можноиспользовать команды, предназначенные для работы со стеком.Основными из них являются следующие.1. Запись слова в стек:PUSH opЗдесь op обозначает любой 16-битовый регистр (в том числе исегментный) или адрес слова памяти. По этой команде значение493регистра SP уменьшается на 2 (вычитание происходит по модулю 216),после чего указанное операндом слово записывается в cтек по адресуSS:SP.2.
Чтение слова из стека:POP opСлово, считанное из вершины стека, присваивается операнду op(регистру, в том числе сегментному, но не CS, или слову памяти), послечего значение SP увеличивается на 2.3. Переход с возвратом:CALL opЭта команда записывает адрес следующей за ней команды в стек изатем делает переход по адресу, определяемому операндом op. Онаиспользуется для переходов на подпрограммы с запоминанием в стекеадреса возврата. Имеются следующие разновидности этой команды (онианалогичны вариантам команды безусловного перехода JMP):— внутрисегментный относительный длинный переход (op непосредственный операнд размером в слово, а в MASM - это меткаиз текущего сегмента команд или имя близкой процедуры (см.ниже)); в этом случае в стек заносится только текущее значениесчетчика команд IP, т.е.
смещение следующей команды;— внутрисегментный абсолютный косвенный переход (op - адрес словапамяти, в которой находится адрес (смещение) той команды, накоторую и будет сделан переход); и здесь в стек записывается толькосмещение адреса возврата;— межсегментныйабсолютныйпрямойпереход(opнепосредственный операнд вида seg:ofs, а в MASM - это FAR PTR<метка> или имя дальней процедуры (см. ниже)); здесь в стекзаносится текущие значение регистров CS и IP (первым в стекзаписывается содержимое CS), т.е. абсолютный адрес возврата, послечего меняются регистры CS и IP;— межсегментный абсолютный косвенный переход(op - адресдвойного слова, в котором находится пара seg:ofs, задающаяабсолютный адрес перехода); и здесь в стеке спасается содержимоерегистров CS и IP.4.