Что такое mov в ассемблере
Перейти к содержимому

Что такое mov в ассемблере

  • автор:

Инструкция MOV

В Контакте Ютуб Почта

Пожалуй, инструкция MOV в ассемблере самая простая. Синтаксис этой команды такой:

MOV ПРИЁМНИК, ИСТОЧНИК

С помощью этой команды можно переместить значение из ИСТОЧНИКА в ПРИЁМНИК . То есть по сути команда MOV копирует содержимое ИСТОЧНИКА и помещает это содержимое в ПРИЁМНИК .

Никакие флаги при этом НЕ изменяются.

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

  • Записывать данные в регистры CS и IP.
  • Копировать данные из одного сегментного регистра в другой сегментный регистр (сначала нужно скопировать данные в регистр общего назначения).
  • Копировать непосредственное значение в сегментный регистр (сначала нужно скопировать данные в регистр общего назначения).

ИСТОЧНИКОМ может быть один из следующих:

  • Область памяти (MEM)
  • Регистр общего назначения (REG)
  • Непосредственное значение (например, число) (IMM)
  • Сегментный регистр (SREG)

ПРИЁМНИКОМ может быть один из следующих:

  • Область памяти (MEM)
  • Регистр общего назначения (REG)
  • Сегментный регистр (SREG)

С учётом ограничений, которые были описаны выше, комбинации ПРИЁМНИК-ИСТОЧНИК могут быть следующими:

REG, MEM SREG, MEM MEM, REG REG, REG SREG, REG MEM, IMM REG, IMM MEM, SREG REG, SREG

Пример использования инструкции MOV:

MOV AX, 0B800h ; установить AX = B800h (память VGA). MOV DS, AX ; копировать значение из AX в DS. MOV CL, 'A' ; CL = 41h (ASCII-код). MOV CH, 01001110b ; CH = атрибуты цвета (желтый текст на красном фоне). MOV BX, 72eh ; BX = позиция на экране = 2*(x + y*80). MOV [BX], CX ; [0B800h:015Eh] = CX.

ПРИМЕЧАНИЕ
Этот пример не будет работать в Windows 2000 и выше, так как эти операционные системы запрещают программам напрямую обращаться к “железу”, а в этом примере мы пытаемся записать данные непосредственно в видеопамять.

Ну и напоследок скажу, почему эта инструкция называется MOV. Это сокращение от английского слова MOVE, которое можно перевести как “переместить, перенести, передвинуть”. И, как теперь вам уже понятно, эта команда соответствует своему названию — она перемещает значение из одного регистра в другой. Хотя с точки зрения русского языка это будет не совсем правильно, потому что перемещения не происходит — значение из ИСТОЧНИКА никуда не исчезает (не перемещается), по сути оно копируется и вставляется в ПРИЁМНИК.

Команда MOV

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

Команда MOV
  1. Требует совпадения размеров источника и приемника
  2. При использовании в качестве приемника сегментного регистра, источником должен быть или несегментный регистр или ячейка памяти соответствующего размера
  3. Не допускается использование сегментного регистра CS в качестве приемника
  4. Не допускается пересылка напрямую данных из одной ячейки памяти в другую. Такая пересылка данных должна производиться через какой-нибудь регистр.
mov ax,8 mov [100h],dx mov ds,cx

Что такое mov в ассемблере

Наиболее распространенной инструкцией является инструкция MOV , которая помещает значение в регистр:

MOV Xd, Xs

В своей самой распространенной форме инструкция принимает два операнда. Первый операнд — Xd представляет регистр, в который надо поместить значение (это может быть, например, 64-разрдяный регистр X0-X30 или 32-разрядный регистр W0-W30). Второй операнд — Xs представляет источник, из которого берется значение. Это может быть другой регистр или какое-то конкретное значение (еще назваемое непосредственным операндом)

Например, поместим значение 22 в регистр X0:

mov X0, #22

Здесь число 22 называет непосредственным операндом (immediate operand). Причем перед числом указывается символ решетки (Хотя этот символ можно опускать). Микропрограмма полностью:

.global _start _start: mov X0, #22 mov X8, #93 // номер функции Linux для выхода из программы svc 0 // вызываем системную функцию

По умолчанию все числа рассматриваются как числа в десятичной системе. Если надо передать шестнадцатеричное значение, то перед числом указываются символы 0x , например:

mov X0, #0xff

Здесь в регистр X0 помещается шестнадцатеричное число 0xFF, которое в десятичной равно 255.

Если надо передать число в двоичной системе, то перед числом указывается префикс 0b , например:

mov X0, #0b11

Здесь в регистр X0 помещается двоичное число 0b11, которое в десятичной равно 3.

Стоит учитывать, что непосредственный операнд должен быть размером не более 2 байт.

Также можно загружать значение из одного регистра в другой:

mov X1, #22 mov X0, X1

В данном случае копируем содержимое регистра X1 в регистр X0. То есть в регистре X0 будет число 22

Если данные помещаются в 32-разрядный регистр W0-W30, то старшие 32 бита соответствующего регистра X0-X30 обнуляются:

Система команд x86

Команда MOV копирует второй операнд (операнд-источник) в первый операнд (операнд-назначение). Оба операнда могут быть регистрами общего назначения, сегментными регистрами, непосредственными значениями и переменными в памяти. Оба операнда должны иметь одинаковую размерность — байт, слово или двойное слово.

Если операнд-назначение — сегментный регистр (DS, ES, FS, GS или SS), тогда в скрытую часть этого регистра также загружаются данные из соответствующего дескриптора. Эти данные извлекаются из элемента таблицы дескрипторов для данного селектора. Сегментный регистр CS не может быть загружен командой MOV. Попытка использования соответствующего кода приводит к генерации особой ситуации #UD. Для загрузки регистра CS должны использоваться команды JMP, CALL или RET.

Пустой селектор (значения 0000, … 0003) может быть загружен в регистры DS, ES, FS и GS не вызывая особой ситуации. Однако попытка использования нулевых селекторов при обращении к памяти вызывает особую ситуацию #GP(0), и никакого обращения к памяти не происходит.

Ниже представлен листинг всех проверок и действий, предпринимаемых процессором при загрузке сегментного регистра в защищенном режиме:

IF (Загружается SS)

IF (Селектор не нулевой) THEN #GP(0); FI;

Индекс селектора должен попадать в пределы таблицы дескрипторов, иначе #GP(Селектор);

Поле RPL селектора должно быть равно CPL, иначе #GP(Селектор);

AR байт должен задавать сегмент данных, доступный для записи, иначе #GP(Селектор);

Поле DPL AR байта должно быть равно CPL, иначе #GP(Селектор);

Сегмент должен быть помечен, как присутствующий, иначе #SS(Селектор);

Загрузить SS селектором;

Загрузить SS дескриптором;

IF (загружается DS, ES, FS или GS не нулевым селектором)

Индекс селектора должен попадать в пределы таблицы дескрипторов, иначе #GP(Селектор);

AR байт должен задавать сегмент данных, или кодовый сегмент доступный для чтения, иначе #GP(Селектор);

IF (Данные или несогласованный код)

THEN RPL и CPL должны быть меньше или равны DPL в AR байте, иначе #GP(Селектор);

Сегмент должен быть помечен, как присутствующий, иначе #NP(Селектор);

Загрузить селектор в сегментный регистр;

Загрузить дескриптор в сегментный регистр;

IF (Загружается DS, ES, FS или GS нулевым селектором)

Загрузить селектор в сегментный регистр;

Очистить внутренний флаг корректности дескриптора (descriptor valid bit);

Команда загрузки сегмента стека SS запрещает все прерывания до завершения выполнения следующей команды (которая может быть командой MOV в ESP). Более эффективным методом загрузки нового указателя стека является команда LSS. Существуют и другие команды, которые задерживают прием прерываний при выполнении следующей за ними команды, но комбинация таких команд (например, STI и MOV SS,EAX) не означает, что прерывания не будут восприниматься на протяжении двух команд. Такие последовательности могут вызвать серьезные сбои, т.к. станет возможным поступление прерывания сразу после команды загрузки стекового сегмента SS.

В процессорах 32-разрядной архитектуры (Intel386, …) команды пересылки между сегментными регистрами и регистрами общего назначения не требуют наличия префикса 16-битного размера операнда (66h) не зависимо от текущего режима работы. Т.е. в этом случае всегда пересылаются 16-битные данные. Многие ассемблеры при встрече подобных мнемоник (например, MOV DS,AX) автоматически вставляют префикс 16-битного размера операнда перед командой пересылки. Это не влияет на результат исполнения команды, а замедляет только время исполнения. Простейшим выходом из данной ситуации является программирование 32-битной мнемоники (MOV DS,EAX), она преобразуется ассемблером в тот же самый код операции, но без префикса размера операнда. Поскольку пересылка данных в этом случае происходит межу 16-битным и 32-битным регистрами, то в 32-битном регистре в операции учавствуют только его младшие 16 бит. Если 32-битный регистр является операндом-назначением такой операции, то значения в его старших 16 битах после окончания пересылки могут быть различны в различных моделях процессоров. В Pentium Pro, … они заполняются нулями, а для более ранних процессоров Intel их значения не определены.

Операция:

Особые ситуации защищенного режима:

#GP(0), если операнд-назначение находится в сегменте, запрещенном для записи, если используется некорректный эффективный адрес операнда в памяти в сегментах CS, DS, ES, FS, GS или нулевой селектор, а также при попытке загрузки регистра SS нулевым селектором.
#GP(Селектор), если индекс загруженного селектора не попадает в пределы таблицы дескрипторов, если при загрузке регистра SS запрашиваемый уровень привилегий селектора RPL или уровень привилегий соответствующего дескриптора сегмента DPL не равны текущему уровню привилегий CPL, если регистр SS загружается селектором, который указывает на сегмент запрещенный для записи, если регистр DS, ES, FS или GS загружается селектором сегмента, который не является доступным для чтения кодовым сегментом или сегментом данных, если регистр DS, ES, FS или GS загружается селектором сегмента, который является сегментом данных или несогласованным кодовым сегментом, и уровень привилегий дескриптора этого сегмента DPL меньше по значению запрашиваемого уровня привилегий селектора RPL и текущего уровня привилегий CPL.
#SS(0) при использовании некорректного эффективного адреса в сегменте SS.
#SS(Селектор), если регистр SS загружается селектором сегмента, который помечен как неприсутствующий.
#NP(Селектор), если регистр DS, ES, FS или GS загружается селектором сегмента, который помечен как неприсутствующий.
#PF(Код ошибки), страничная ошибка.
#AC(0) при невыровненной ссылке в память при текущем уровне привилегий равном 3.
#UD при попытке загрузки регистра CS.

Особые ситуации режима реальной адресации:

#GP, если любая часть операнда находится вне пространства эффективных адресов в сегментах CS, DS, ES, FS или GS.
#SS, если любая часть операнда находится вне пространства эффективных адресов в сегменте SS.
#UD при попытке загрузки регистра CS.

Особые ситуации режима V86:

Такие же, как и в режиме реальной адресации.
#PF(Код ошибки), страничная ошибка.
#AC(0) при невыровненной ссылке в память.

Замечание:

В процессоре Pentium III существуют некоторые ситуации, когда отладчик будет получать неверную информацию в регистрах отладки от команд MOV SS и POP SS. Обратитесь к технической документации Intel за описанием всех возможных случаев проявления ошибки.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *