ХАНДЫФАР

Инструкция 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.


  1. title Автор: Довгополов Евгений Сергеевич
  2. .model small
  3. .stack 100h
  4. data segment public
  5. ____aArray__db__1, 2, 3, 4, 5, 6, 7
  6. ____aArrlen equ_($-aArray)_______; Длина массива aArray
  7. ____bArray _db__aArrlen dup(0)___; Длина массива bArray равна длине массива aArray
  8. data ends
  9. code segment public _____________; Начало сегмента кода
  10. ____assume ds:data, cs:code
  11. ____main proc ___________________; Начало процедуры main
  12. ________mov_____ax, seg data_____; Получаем адрес сегмента памяти данных и сохраняем его в ax
  13. ________mov_____ds, ax___________; Передаём адрес сегмента памяти данных из регистра ax в ds
  14. ________mov_____es, ax___________; Передаём адрес сегмента памяти данных из регистра ax в es
  15. ________mov_____cx, aArrlen______; Устанавливаем счётчик равным длине массива aArray
  16. ________lea_____di, es:[bArray]__; Загружаем адрес переменной bArray в регистр es:di
  17. ________lea_____si, ds:[aArray]__; Загружаем адрес переменной aArray в регистр ds:si
  18. ____CopyForwardLoop:
  19. ________movsb____________________; Копируем значение из ds:si в es:di увеличивая si и di на 1
  20. ________loop____CopyForwardLoop__; Выполняем цикл пока CX≠0
  21. __
  22. ________mov_____ax, 4C00h________; Копируем значение функции завершения процесса в ah а значение в al
  23. ________int_____21h _____________; Вызываем прерывание DOS
  24. ____main endp ___________________; Конец процедуры main
  25. code ends _______________________; Конец сегмента кода
  26. end main ________________________; Конец файла. Точкой входа указывается процедура main

В качестве второго примера рассмотрим случай, когда у нас есть массив слов и нам необходимо скопировать\ переместить данные в другой массив слов начиная с конца массива. Количество копируемых\перемещаемых данных\элементов указывается в регистре cx. В данном примере мы воспользуемся префиксом REP который повторяет стоковую инструкцию количество раз, указанное в регистре cx, или до тех пор, пока указанное условие флага ZF больше не будет выполнено. Если для копирования/перемещения данных мы воспользуемся циклом, как в примере выше то, на копирование/перемещение данных массива у нас уйдет 27 байт. Используя префикс rep с инструкцией movsw у нас уйдет 18 байт. Это на много быстрей чем цикл.

  1. title Автор: Довгополов Евгений Сергеевич
  2. .model small
  3. .stack 100h
  4. data segment public
  5. ____aArray__dw__1, 2, 3, 4, 5, 6, 7, 8, 9
  6. ____aArrlen equ_($-aArray) / 2___; Длина массива aArray
  7. ____bArray _dw__aArrlen dup(0)___; Длина массива bArray равна длине массива aArray
  8. data ends
  9. code segment public _____________; Начало сегмента кода
  10. ____assume ds:data, cs:code
  11. ____main proc ___________________; Начало процедуры main
  12. ________mov_____ax, seg data_____; Получаем адрес сегмента памяти данных и сохраняем его в ax
  13. ________mov_____ds, ax___________; Передаём адрес сегмента памяти данных из регистра ax в ds
  14. ________mov_____es, ax___________; Передаём адрес сегмента памяти данных из регистра ax в es
  15. ________mov_____cx, aArrlen______; Устанавливаем счётчик равным длине массива aArray
  16. ________lea_____di, es:[bArray]__; Загружаем адрес переменной bArray в регистр es:di
  17. ________lea_____si, ds:[aArray]__; Загружаем адрес переменной aArray в регистр ds:si
  18. ________shl_____cx, 1____________; Умножаем значение в регистре cx на 2
  19. ________sub_____cx, 2____________; Вычитаем из cx 2
  20. ________add_____si, cx___________; К si прибавляем cx. Теперь указывает на последний элемент массива
  21. ________add_____di, cx___________; К di прибавляем cx. Теперь указывает на последний элемент массива
  22. ________mov_____cx, aArrlen______; Обратно устанавливаем счётчик равным длине aArray
  23. ________std______________________; Устанавливаем флаг направления; DF=1
  24. ____rep movsw____________________; Копируем из ds:si в es:di увеличивая si и di на 2 пока CX≠0
  25. ________cld______________________; Сбрасываем флаг направления; DF=0
  26. __
  27. ________mov_____ax, 4C00h________; Копируем значение функции завершения процесса в ah а значение в al
  28. ________int_____21h _____________; Вызываем прерывание DOS
  29. ____main endp ___________________; Конец процедуры main
  30. code ends _______________________; Конец сегмента кода
  31. end main ________________________; Конец файла. Точкой входа указывается процедура main

В качестве третьего примера рассмотрим случай, когда у нас есть байтовая строка "Hello " и нам необходимо скопировать\переместить данные в другую байтовую строку "______World!" которая находится в другом сегменте. Для этого мы создадим дополнительный сегмент extr и в нем объявим вторую строку. Затем мы в начале нашей второй байтовой строки выделяем дополнительные 6 байт и заполним их нулевым значением. В это место мы скопируем слово "Hello " из первого байтового массива что бы образовалась целая строка "Hello World!" Количество копируемых\перемещаемых данных\элементов указывается в регистре cx.

  1. title Автор: Довгополов Евгений Сергеевич
  2. .model small
  3. .stack 100h
  4. data segment public
  5. ____string db__"Hello "
  6. ____strlen_equ ($-string)
  7. data ends
  8. extr segment public
  9. ____strdst db 6 dup(?), "World!"
  10. ____strptr dd strdst
  11. extr ends
  12. code segment public _____________; Начало сегмента кода
  13. ____assume ds:data, es:extr, cs:code
  14. ____main proc ___________________; Начало процедуры main
  15. ________mov_____ax, seg data_____; Получаем адрес сегмента памяти данных data и сохраняем его в ax
  16. ________mov_____ds, ax___________; Передаём адрес сегмента памяти данных из регистра ax в ds
  17. ________mov_____ax, seg extr_____; Получаем адрес сегмента памяти данных extr и сохраняем его в ax
  18. ________mov_____es, ax___________; Передаём адрес сегмента памяти данных из регистра ax в es
  19. ________mov_____cx, strlen_______; Устанавливаем счётчик равным длине string
  20. ________les_____di, es:[strptr]__; Загружаем дальний указатель strptr в регистр es:di
  21. ________lea_____si, ds:[string]__; Загружаем адрес переменной string в регистр ds:si
  22. __repnz movsb____________________; Копируем из ds:si в es:di увеличивая si и di на 1 пока CX≠0
  23. __
  24. ________mov_____ax, 4C00h________; Копируем значение функции завершения процесса в ah а значение в al
  25. ________int_____21h _____________; Вызываем прерывание DOS
  26. ____main endp ___________________; Конец процедуры main
  27. code ends _______________________; Конец сегмента кода
  28. end main ________________________; Конец файла. Точкой входа указывается процедура main
Made on
Tilda