Movs адрес_приемника,адрес_источника



Команда копирует байт, слово или двойное слово из цепочки, адресуемой операндом адрес_источника, в цепочку, адресуемую операндом адрес_приемника.

Размер пересылаемых элементов ассемблер определяет, исходя из атрибутов идентификаторов, указывающих на области памяти приемника и источника. К примеру, если эти идентификаторы были определены директивой db, то пересылаться будут байты, если идентификаторы были определены с помощью директивы dd, то пересылке подлежат 32-битовые элементы, то есть двойные слова.

Ранее уже было отмечено, что для цепочечных команд с операндами, к которым относится и команда пересылки movs адрес_приемника,адрес_источника, не существует машинного аналога.

При трансляции в зависимости от типа операндов транслятор преобразует ее в одну из трех машинных команд:

movsb, movsw или movsd.

Сама по себе команда movs пересылает только один элемент, исходя из его типа, и модифицирует значения регистров esi/si и edi/di. Если перед командой написать префикс rep, то одной командой можно переслать до 64 Кбайт данных (если размер адреса в сегменте 16 бит — use16) или до 4 Гбайт данных (если размер адреса в сегменте 32 бит - use32).

Число пересылаемых элементов должно быть загружено в счетчик — регистр cx (use16) или ecx (use32).

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

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

  • Установить значение флага df в зависимости от того, в каком направлении будут обрабатываться элементы цепочки — в направлении возрастания или убывания адресов.
  • Загрузить указатели на адреса цепочек в памяти в пары регистров ds:(e)si и es: (e)di.
  • Загрузить в регистр ecx/cx количество элементов, подлежащих обработке.
  • Выдать команду movs с префиксом rep.

На примере листинга 1 рассмотрим, как эти действия реализуются программно. В этой программе производится пересылка символов из одной строки в другую. Строки находятся в одном сегменте памяти. Для пересылки используется команда-примитив movs с префиксом повторения rep.

Листинг 1 Пересылка строк командой movs;prg_11_1.asmMASMMODEL smallSTACK 256.datasource db 'Тестируемая строка','$';строка-источникdest db 19 DUP (' ') ;строка-приёмник.code assume ds:@data,es:@datamain: ;точка входа в программу mov ax,@data ;загрузка сегментных регистров mov ds,ax ;настройка регистров DS и ES ;на адрес сегмента данных mov es,ax cld ;сброс флага DF — обработка строки от начала к концу lea si,source ;загрузка в si смещения строки-источника lea di,dest ;загрузка в DS смещения строки-приёмника mov cx,20 ;для префикса rep — счетчик повторений (длина строки)rep movs dest,source ;пересылка строки lea dx,dest mov ah,09h ;вывод на экран строки-приёмника int 21hexit: mov ax,4c00h int 21hend main

Операция сравнения цепочек

Команды, реализующие эту операцию-примитив, производят сравнение элементов цепочки-источника с элементами цепочки-приемника. Здесь ситуация с набором команд и методами работы с ними аналогична операции-примитиву пересылки цепочек.

TASM предоставляет программисту четыре команды сравнения цепочек, работающие с разными размерами элементов цепочки:

cmps адрес_приемника,адрес_источника(CoMPare String) — сравнить строки;

cmpsb (CoMPare String Byte) — сравнить строку байт;

cmpsw (CoMPare String Word) — сравнить строку слов;

cmpsd (CoMPare String Double word) — сравнить строку двойных слов.

Команда cmps

Синтаксис команды cmps:

Cmps адрес_приемника,адрес_источника

Здесь:

  • адрес_источника определяет цепочку-источник в сегменте данных. Адрес цепочки должен быть заранее загружен в пару ds:esi/si;
  • адрес_приемника определяет цепочку-приемник. Цепочка должна находиться в дополнительном сегменте, и ее адрес должен быть заранее загружен в пару es:edi/di.

Алгоритм работы команды cmps заключается в последовательном выполнении вычитания (элемент цепочки-источника — элемент цепочки-получателя) над очередными элементами обеих цепочек.

Принцип выполнения вычитания командой cmps аналогичен команде сравнения cmp. Она, так же, как и cmp, производит вычитание элементов, не записывая при этом результата, и устанавливает флаги zf, sf и of.

После выполнения вычитания очередных элементов цепочек командой cmps, индексные регистры esi/si и edi/di автоматически изменяются в соответствии со значением флага df на значение, равное размеру элемента сравниваемых цепочек.

Чтобы заставить команду cmps выполняться несколько раз, то есть производить последовательное сравнение элементов цепочек, необходимо перед командой cmps определить префикс повторения.

С командой cmps можно использовать префикс повторения repe/repz или repne/repnz:

  • repe или repz — если необходимо организовать сравнение до тех пор, пока не будет выполнено одно из двух условий:
    • достигнут конец цепочки (содержимое ecx/cx равно нулю);
    • в цепочках встретились разные элементы (флаг zf стал равен нулю);
  • repne или repnz — если нужно проводить сравнение до тех пор, пока:
    • не будет достигнут конец цепочки (содержимое ecx/cx равно нулю);
    • в цепочках встретились одинаковые элементы (флаг zf стал равен единице).

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

Выбор префикса определяется причиной, которая приводит к выходу из цикла. Таких причин может быть две для каждого из префиксов. Для определения конкретной причины наиболее подходящим является способ, использующий команду условного перехода jcxz. Ее работа заключается в анализе содержимого регистра ecx/cx, и если оно равно нулю, то управление передается на метку, указанную в качестве операнда jcxz. Так как в регистре ecx/cx содержится счетчик повторений для цепочечной команды, имеющей любой из префиксов повторения, то, анализируя ecx/cx, можно определить причину выхода из зацикливания цепочечной команды. Если значение в ecx/cx не равно нулю, то это означает, что выход произошел по причине совпадения либо несовпадения очередных элементов цепочек.

Существует возможность еще больше конкретизировать информацию о причине, приведшей к окончанию операции сравнения. Сделать это можно с помощью команд условной передачи управления (табл. 1 и 2).

Таблица 1. Сочетание команд условной передачи управления с результатами команды cmps (для чисел со знаком)

Причина прекращения операции сравнения Команда условного перехода, реализующая переход по этой причине
операнд_источник > операнд_приемник jg
операнд_источник = операнд_приемник je
операнд_источник <> операнд_приемник jne
операнд_источник < операнд_приемник jl
операнд_источник <= операнд_приемник jle
операнд_источник >= операнд_приемник jge

Таблица 2. Сочетание команд условной передачи управления с результатами команды cmps (для чисел без знака)

Причина прекращения операции сравнения Команда условного перехода, реализующая переход по этой причине
операнд_источник > операнд_приемник ja
операнд_источник = операнд_приемник je
операнд_источник <> операнд_приемник jne
операнд_источник < операнд_приемник jb
операнд_источник <= операнд_приемник jbe
операнд_источник >= операнд_приемник jae

Как определить местоположение очередных совпавших или не совпавших элементов в цепочках?

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

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

В качестве примера рассмотрим программу из листинга 2, которая сравнивает две строки, находящиеся в одном сегменте. Используется команда cmps. Префикс повторения - repe.

Листинг 2. Сравнение двух строк командой cmps<1> ;prg_11_2.asm<2> MODEL small<3> STACK 256<4> .data<5> match db 0ah,0dh,'Строки совпадают.','$'<6> failed db 0ah,0dh,'Строки не совпадают','$'<7> string1 db '0123456789',0ah,0dh,'$';исследуемые строки<8> string2 db '0123406789','$'<9> .code<10> ASSUME ds:@data,es:@data ;привязка DS и ES к сегменту данных<11> main:<12> mov ax,@data ;загрузка сегментных регистров<13> mov ds,ax<14> mov es,ax ;настройка ES на DS<15> ;вывод на экран исходных строк string1 и string2<16> mov ah,09h<17> lea dx,string1<18> int 21h<19> lea dx,string2<20> int 21h<21> ;сброс флага DF — сравнение в направлении возрастания адресов<22> cld<23> lea si,string1 ;загрузка в si смещения string1<24> lea di,string2 ;загрузка в di смещения string2<25> mov cx,10 ;длина строки для префикса repe<26> ;сравнение строк (пока сравниваемые элементы строк равны)<27> ;выход при обнаружении не совпавшего элемента<28> cycl:<29> repe cmps string1,string2<30> jcxz equal ;cx=0, то есть строки совпадают<31> jne not_match ;если не равны — переход на not_match<32> equal: ;иначе, если совпадают, то<33> mov ah,09h ;вывод сообщения<34> lea dx,match<35> int 21h<36> jmp exit ;выход<37> not_match: ;не совпали<38> mov ah,09h<39> lea dx,failed<40> int 21h ;вывод сообщения<41> ;теперь, чтобы обработать не совпавший элемент в строке, необходимо уменьшить значения регистров si и di<42> dec si<43> dec di<44> ;сейчас в ds:si и es:di адреса несовпавших элементов<45> ;здесь вставить код по обработке несовпавшего элемента<46> ;после этого продолжить поиск в строке:<47> inc si<48> inc di<49> jmp cycl<50> exit: ;выход<51> mov ax,4c00h<52> int 21h<53> end main ;конец программы

Программа достаточно прозрачна, только два момента, на мой взгляд, требуют пояснения:


Дата добавления: 2019-09-13; просмотров: 259; Мы поможем в написании вашей работы!

Поделиться с друзьями:






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