Инструкция MOVSB/MOVSW
Перемещение байта или слова из памяти в память
____________________________MOVSB - Переместить байт с адреса DS:SI на ES:DI.
____________________________MOVSW - Переместить слово с адреса DS:SI на ES:DI.
Перемещает байт или слово, указанное вторым операндом (исходный операнд), в местоположение, указанное первым операндом (целевой операнд). Как исходный, так и конечный операнды находятся в памяти. Адрес исходного операнда считывается из регистра ds:si. Адрес конечного операнда считывается из регистра es:di. Сегмент ds может быть переопределен префиксом переопределения сегмента, но сегмент es не может быть переопределен.
Местоположения исходного и конечного операндов всегда задаются регистрами ds:si и es:di, которые должны быть правильно загружены перед выполнением команды перемещения строки.
После операции перемещения регистры si и di автоматически увеличиваются или уменьшаются в соответствии с установкой флага DF в регистре FLAGS. (Если флаг DF равен 0, регистры si и di увеличиваются; если флаг DF равен 1, регистры si и di уменьшаются.) Регистры увеличиваются или уменьшаются на 1 для операций с байтами или на 2 для операций со словами.
В качестве первого примера рассмотрим случай, когда у нас есть байтовый массив чисел и нам необходимо скопировать\переместить данные в другой массив. Количество копируемых\перемещаемых данных\элементов указывается в регистре cx.
- title Автор: Довгополов Евгений Сергеевич
- .model small
- .stack 100h
- data segment public
- ____aArray__db__1, 2, 3, 4, 5, 6, 7
- ____aArrlen equ_($-aArray)_______; Длина массива aArray
- ____bArray _db__aArrlen dup(0)___; Длина массива bArray равна длине массива aArray
- data ends
- code segment public _____________; Начало сегмента кода
- ____assume ds:data, cs:code
- ____main proc ___________________; Начало процедуры main
- ________mov_____ax, seg data_____; Получаем адрес сегмента памяти данных и сохраняем его в ax
- ________mov_____ds, ax___________; Передаём адрес сегмента памяти данных из регистра ax в ds
- ________mov_____es, ax___________; Передаём адрес сегмента памяти данных из регистра ax в es
- ________mov_____cx, aArrlen______; Устанавливаем счётчик равным длине массива aArray
- ________lea_____di, es:[bArray]__; Загружаем адрес переменной bArray в регистр es:di
- ________lea_____si, ds:[aArray]__; Загружаем адрес переменной aArray в регистр ds:si
- ____CopyForwardLoop:
- ________movsb____________________; Копируем значение из ds:si в es:di увеличивая si и di на 1
- ________loop____CopyForwardLoop__; Выполняем цикл пока CX≠0
- __
- ________mov_____ax, 4C00h________; Копируем значение функции завершения процесса в ah а значение в al
- ________int_____21h _____________; Вызываем прерывание DOS
- ____main endp ___________________; Конец процедуры main
- code ends _______________________; Конец сегмента кода
- end main ________________________; Конец файла. Точкой входа указывается процедура main
В качестве второго примера рассмотрим случай, когда у нас есть массив слов и нам необходимо скопировать\ переместить данные в другой массив слов начиная с конца массива. Количество копируемых\перемещаемых данных\элементов указывается в регистре
cx. В данном примере мы воспользуемся префиксом REP который повторяет стоковую инструкцию количество раз, указанное в регистре
cx, или до тех пор, пока указанное условие флага ZF больше не будет выполнено. Если для копирования/перемещения данных мы воспользуемся циклом, как в примере выше то, на копирование/перемещение данных массива у нас уйдет 27 байт. Используя префикс rep с инструкцией movsw у нас уйдет 18 байт. Это на много быстрей чем цикл.
- title Автор: Довгополов Евгений Сергеевич
- .model small
- .stack 100h
- data segment public
- ____aArray__dw__1, 2, 3, 4, 5, 6, 7, 8, 9
- ____aArrlen equ_($-aArray) / 2___; Длина массива aArray
- ____bArray _dw__aArrlen dup(0)___; Длина массива bArray равна длине массива aArray
- data ends
- code segment public _____________; Начало сегмента кода
- ____assume ds:data, cs:code
- ____main proc ___________________; Начало процедуры main
- ________mov_____ax, seg data_____; Получаем адрес сегмента памяти данных и сохраняем его в ax
- ________mov_____ds, ax___________; Передаём адрес сегмента памяти данных из регистра ax в ds
- ________mov_____es, ax___________; Передаём адрес сегмента памяти данных из регистра ax в es
- ________mov_____cx, aArrlen______; Устанавливаем счётчик равным длине массива aArray
- ________lea_____di, es:[bArray]__; Загружаем адрес переменной bArray в регистр es:di
- ________lea_____si, ds:[aArray]__; Загружаем адрес переменной aArray в регистр ds:si
- ________shl_____cx, 1____________; Умножаем значение в регистре cx на 2
- ________sub_____cx, 2____________; Вычитаем из cx 2
- ________add_____si, cx___________; К si прибавляем cx. Теперь указывает на последний элемент массива
- ________add_____di, cx___________; К di прибавляем cx. Теперь указывает на последний элемент массива
- ________mov_____cx, aArrlen______; Обратно устанавливаем счётчик равным длине aArray
- ________std______________________; Устанавливаем флаг направления; DF=1
- ____rep movsw____________________; Копируем из ds:si в es:di увеличивая si и di на 2 пока CX≠0
- ________cld______________________; Сбрасываем флаг направления; DF=0
- __
- ________mov_____ax, 4C00h________; Копируем значение функции завершения процесса в ah а значение в al
- ________int_____21h _____________; Вызываем прерывание DOS
- ____main endp ___________________; Конец процедуры main
- code ends _______________________; Конец сегмента кода
- end main ________________________; Конец файла. Точкой входа указывается процедура main
В качестве третьего примера рассмотрим случай, когда у нас есть байтовая строка
"Hello " и нам необходимо скопировать\переместить данные в другую байтовую строку
"______World!" которая находится в другом сегменте. Для этого мы создадим дополнительный сегмент extr и в нем объявим вторую строку. Затем мы в начале нашей второй байтовой строки выделяем дополнительные 6 байт и заполним их нулевым значением. В это место мы скопируем слово
"Hello " из первого байтового массива что бы образовалась целая строка
"Hello World!" Количество копируемых\перемещаемых данных\элементов указывается в регистре
cx.
- title Автор: Довгополов Евгений Сергеевич
- .model small
- .stack 100h
- data segment public
- ____string db__"Hello "
- ____strlen_equ ($-string)
- data ends
- extr segment public
- ____strdst db 6 dup(?), "World!"
- ____strptr dd strdst
- extr ends
- code segment public _____________; Начало сегмента кода
- ____assume ds:data, es:extr, cs:code
- ____main proc ___________________; Начало процедуры main
- ________mov_____ax, seg data_____; Получаем адрес сегмента памяти данных data и сохраняем его в ax
- ________mov_____ds, ax___________; Передаём адрес сегмента памяти данных из регистра ax в ds
- ________mov_____ax, seg extr_____; Получаем адрес сегмента памяти данных extr и сохраняем его в ax
- ________mov_____es, ax___________; Передаём адрес сегмента памяти данных из регистра ax в es
- ________mov_____cx, strlen_______; Устанавливаем счётчик равным длине string
- ________les_____di, es:[strptr]__; Загружаем дальний указатель strptr в регистр es:di
- ________lea_____si, ds:[string]__; Загружаем адрес переменной string в регистр ds:si
- __repnz movsb____________________; Копируем из ds:si в es:di увеличивая si и di на 1 пока CX≠0
- __
- ________mov_____ax, 4C00h________; Копируем значение функции завершения процесса в ah а значение в al
- ________int_____21h _____________; Вызываем прерывание DOS
- ____main endp ___________________; Конец процедуры main
- code ends _______________________; Конец сегмента кода
- end main ________________________; Конец файла. Точкой входа указывается процедура main