что значит mov в ассемблере

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

Влияние команды на флаги и форматы команды:

Описание:

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

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

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

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

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 за описанием всех возможных случаев проявления ошибки.

Источник

Первая команда в ассемблере MOV

Эта команда используется для копирования значения из приёмника в источник. Синтаксис команды:

Mov приемник, источник

Пример:

Mov edx, ecx ; правильно

Размер источника и приемника должны быть одинаковыми.

Mov al, ecx; не правильно

Этот код пытается поместить DWORD (32-битное) значение в байт (8 битов).

Правильные команды:

Mov al, bl

Mov cl, dl

Mov cx, dx

Mov ecx, ebx

Можно получить значение из памяти и поместить его в регистр. Например, имеем следующую схему памяти:

смещение 3A 3B 3C 3D 3E 3F
данные 0D 0A 7A 5E EF 7D FF AD C7

Данные, которые имеют смещение 3A: 25, 7A, 5E, 72, EF, и т.д. Чтобы поместить значение со смещения 3A, например, в регистр, можно воспользоваться командой mov:

mov eax, dword ptr [0000003Ah] ; eax=725E7A25h

При работе с памятью самый младший байт сохраняется в наиболее значимом байте: порядок байтов задом на перед.

dword (32-бит) значение 10203040 шестнадцатиричное сохраняется в памяти как: 40, 30, 20, 10

word (16-бит) значение 4050 шестнадцатиричное сохраняется в памяти как: 50, 40

Пример2:

mov cl, byte ptr [34h] ; cl получит значение 0Dh

mov dx, word ptr [3Eh] ; dx получит значение 7DEFh

Размеры данных для префикса ptr:

Размер можно не указывать:

mov eax, [00403045h]

Пример3:

mov eax, 403045h ; eax= 00403045h

mov cx, [eax] ; CX=значение (размера word) из памяти указанной в EAX (403045)

Стек это область в памяти, на которую указывает регистр стека ESP(SP). Есть две команды, для размещения значения в стеке и извлечения его из стека: PUSH и POP. Команда PUSH размещает значение в стеке, т.е. помещает значение в ячейку памяти, на которую указывает регистр ESP, после этого значение регистра ESP уменьшается на 4. Команда POP извлекает значение из стека, т.е. извлекает значение из ячейки памяти, на которую указывает регистр ESP, после этого увеличивается значение регистра ESP на 4. Значение, помещенное в стек последним, извлекается первым.

Пример:

(1) mov ecx, 100

(2) mov eax, 200

(3) push ecx

(4) push eax

(5) xor ecx, eax

(6) add ecx, 400

(7) mov edx, ecx

(8) pop ebx

(9) pop ecx

1: поместить 100 в ecx

2: поместить 200 в eax

3: разместить значение из ecx (=100) в стеке (размещается первым)

4: разместить значение из eax (=200) в стеке (размещается последним)

5/6/7: выполнение операций над ecx, значение в ecx изменяется

8: извлечение значения из стека в ebx: ebx=200.

9: извлечение значения из стека в ecx: ecx=100.

Пример: Работа со стеком.

Смещение 120A 120B
Значение
ESP

ESP стоит в том месте, на которое он указывает)

Mov ax, 4560h

Push ax

Смещение 120A 120B
Значение
ESP

Mov cx, FFFFh

Push cx

Смещение 120A 120B
Значение FF FF
ESP

Pop edx

Смещение 120A 120B
Значение FF FF
ESP

edx = 4560FFFFh.

Пересылка данных

cmovcc

bswap

Особенности команды mov:

1) нельзя осуществлять пересылку из одной области памяти в другую. При такой необходимости нужно использовать в качестве промежуточного буфера любой доступный регистр общего назначения. Пример: переслать байты из ячейки памяти fls в ячейку fld:

Data

Fls dd 947503b3h

Code

Start

Mov eax, fls

Mov fld,eax

End start

2) нельзя загрузить в сегментный регистр значение непосредственно из памяти. Для выполнения такой загрузки нужно использовать промежуточный объект (регистр общего назначения или стек).

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

Пример: инициализировать регистр es значением регистра ds:

Mov ax,ds

Move es,ax

Можно также использовать стек и команды push и pop:

Push ds ; поместить значение регистра ds в стек

Pop es ; записать в es число из стека

Нельзя использовать сегментный регистр cs в качестве операнда назначения.

5) оператор ptr можно применять и когда требуется принудительно поменять размерность операндов. К примеру, требуется переслать значение 0ffh во второй байт поля flp:

Data

Code

start:

mov byte ptr (flp+1),0ffh

End start

Для двунаправленной пересылки данных применяют команду xchg. Эту же операцию можно выполнить применив последовательность из нескольких команд mov. Общий вид записи:

Содержимое операнда2 копируется в операнд1, а старое содержимое операнда1 — в операнд2. XCHG можно выполнять над двумя регистрами или над регистром и переменной.

Например:

Xchg eax,ebx ; обменять содержимое регистров eax и ebx.

Читайте также:  Что лучше септик или автономная канализация для постоянного проживания

То же, что три команды на языке С:

Xchg al,al ; а эта команда не делает ничего

xchg ax, word ptr [si] ; обменять содержимое регистра ах и слова в памяти по адресу в [si].

Для условной пересылки данных используется команда:

CMOVcc

Набор команд, которые копируют содержимое источника в приемник, если удовлетворяется то или иное условие.

Можно использовать команды CMOVcc сразу после команды СМР (сравнение) с теми же операндами, например:

Источник

STM Урок 201. Assembler. Первый проект. Команды MOV, LDR, STR, B. Часть 1

С данного урока начнём знакомиться с таким интересным языком, как ассемблер.

Я всегда люблю говорить, что ассемблер – это очень лёгкий язык, но писать на нём очень трудно. И вскоре вы поймёте, почему.

Язык C, который мы использовали, является языком высокого уровня, так же как и C++. Инструкции данных языков представляют собой практически английские слова, обозначающие те или иные действия. Только данные действия производятся над абстрактными величинами – массивами, переменными и т.д. Процессор, для которого мы пишем код, таких величин не знает. Поэтому данные языки ещё называют человеко-понятными.

Assembler же является машино-понятным языком, так как оперирует он с помощью своих команд, представляющих собой мнемоники тех или иных действий, регистрами процессора, ячейками памяти, адреса которых также, как правило, находятся в регистрах процессора (регистрах общего назначения или РОН).

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

Писать мы будем в среде программирования Keil, хотя вполне могли бы писать и в Eclipse, просто там мы много бы сил отдали бы настройке проекта, также синтаксис AT&T, который используется по умолчанию в ассемблере GNU с его бесконечными знаками процентов и долларов, мне не очень нравится, хотя в Eclipse также можно настроить и синтаксис Intel. В Keil же по умолчанию используется Intel, а также присутствует ряд полезных макросов, а также настройка проекта там занимает минимальное время.

Я, конечно, не буду томить вас бесконечной теорией, мы будем к ней возвращаться постепенно, но несколько слов по теории сказать всё же придётся.

Писать код мы будем пока для контроллера STM32F103, установленном на недорогой отладочной плате. Пока будем использовать три мануала – STM32F10xxx-20xxx-21xxx-L1xxxx-Programming-Manual, Cortex M3 Technical Reference Manual и ARMv7-M Architecture Reference Manual, которые найти, я думаю, у вас не составит особого труда, ссылки я на них давать не буду по понятным причинам, дабы не нарушить чьих-то авторских прав. Также будут использоваться некоторые интернет ресурсы – понятно, что больше всего будет использоваться ресурс разработчика ядра – arm.com.

Вот как выглядит схематически процессор Cortex M3, который является сердцем контроллера

Мы видим, что в самом центре находится ядро, которое взаимодействует с остальными блоками, в частности в процессор входит сторожевой таймер (DWT), модуль защиты памяти (MPU), контроллер вложенных векторных прерываний NVIC (Nested Vectored Interrupt Controller), модуль точек останова FPB (Flash Patch and Breakpoint), шинная матрица (Bus Matrix), которая соединяет процессор и интерфейс отладки с внешними шинами, расширенный высокопроизводительный порт доступа к шине (AHB-AP).

Ядро, выполненное по архитектуре ARMv7-M, по сравнению с предыдущими архитектурами, претерпело ряд изменений, в частности, применение инструкций нового набора инструкций Thumb-2, позволило в некоторых случаях добиться производительности на 70% больше по сравнению с ядром ARM7TDMI-S, исполняющим инструкции Thumb, и на 35% по сравнению с тем же ядром, исполняющим инструкции ARM. Также применение 3-ступенчатого конвейера обработки инструкций (этап выборки, этап декодирования, этап исполнения) также приводит к ускорению выполнению программы. Также наличие раздельных шин для данных и команд позволяет одновременно считывать процессором и то и другое, что тоже сказывается положительно на производительности работы ядра.

Ядро включает следующий набор регистров

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

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

В нашем коде мы сегодня добьёмся самой простой задачи. Мы попытаемся зажечь светодиод, установленный на плате и подключенный к ножке PC13.

Чтобы нам писать ассемблерный код, надо будет для начала создать пустой проект, поэтому откроем Keil и создадим пустой проект, выбрав следующий пункт меню

Зададим имя проекту и сохраним его в заранее созданном каталоге

Здесь не выбираем вообще ничего

У нас появится вот такое дерево проекта

Переименуем группу, а то как-то некрасиво

Прежде чем наполнять наш проект файлами с исходным кодом, надо его настроить.

В настройках проекта сначала выставим правильную частоту тактирования кварцевого резонатора

Разрешим создание файла прошивки формата HEX

Также настроим создание файла прошивке в бинарном формате, введя вот такую строку:

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

Читайте также:  Что лучше чай или вода

В каталоге с проектом создадим подкаталоги user и inc, подключив путь к последнему здесь

Отключим генерирование предупреждений с кодом 6314

Для тех, кто не знает, предупреждение с кодом 6314 – это сообщение о несоответствии секций определённым шаблонам. Для нас это не страшно, поэтому мы данное предупреждение и отключили, чтобы не маячило.

Выберем правильный отладчик

В свойствах отладчика включим данную настройку

Для того, чтобы были доступны настройки отладчика, плата должна быть подключена к компьютеру.

Включим автоперезагрузку после заливки ПО

Пока, в принципе, с настройками всё. Если, что, то потом донастроим.

Источник

Что значит mov в ассемблере

При изучении данной темы мы рассмотрим всего три типа операндов, которые могут встречаться в любой команде: непосредственно заданное значение (immediate), регистр (register) и память (memory). Из всех перечисленных здесь типов только последний (память) довольно труден для освоения. Список условных обозначений возможных типов операндов, взятых из руководства фирмы Intel по процессору Pentium, приведен в табл. 1. Довайте изучим его, поскольку с этого момента мы будем активно пользоваться этими обозначениями при описании синтаксиса команд процессоров Intel.

Таблица 1. Условное обозначение типов операндов.

Один из 8-разрядных регистров общего назначения: АН, AL, BH, BL, CH, CL, DH, DL

Один из 16-разрядных регистров общего назначения: АХ, BX, СХ, DX, SI, DI, SP, BP

Один из 32-разрядных регистров общего назначения: ЕАХ, ЕВХ, ЕСХ, EDX, ESI, EDI, ESP, EBP

Произвольный регистр общего назначения

Один из 16-разрядных сегментных регистров: CS, DS, SS, ES, FS, GS

Непосредственно заданное 8-разрядное значение (байт)

Непосредственно заданное 16-разрядное значение (слово)

Непосредственно заданное 32-разрядное значение (двойное слово)

Непосредственно заданное 8-, 16- или 32-разрядное значение

8-разрядный операнд, в котором закодирован один из 8-разрядных регистров общего назначения или адрес байта в памяти

16-разрядный операнд, в котором закодирован один из 16-разрядных регистров общего назначения или адрес слова в памяти

32-разрядный операнд, в котором закодирован один из 32-разрядных регистров общего назначения или адрес двойного слова в памяти

Адрес 8-, 16- или 32-разрядного операнда в памяти

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

При выполнении этой команды изменяется содержимое операнда-получателя, а содержимое операнда-источника не меняется. Принцип пересылки данных справа налево соответствует принятому в операторах присваивания языков высокого уровня, таких как C ++:

Практически во всех командах ассемблера операнд-получатель находится слева, а операнд-источник— справа.

В команде MOV могут использоваться самые разные операнды. Кроме того, необходимо учитывать следующие правила и ограничения:

1. Оба операнда должны иметь одинаковую длину.

2. В качестве одного из операндов обязательно должен использоваться регистр (т.е. пересылки типа «память-память» в команде MOV не поддерживаются).

4. Нельзя переслать непосредственно заданное значение в сегментный регистр.

Ниже приведены варианты использования команды MOV с разными операндами (кроме сегментных регистров):

Сегментные регистры в команде MOV обычно используются только в программах, написанных для реального или виртуального режимов работы процессора. При этом могут существовать следующие ее формы (следует учитывать, что регистр CS нельзя указывать в качестве получателя данных):

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

При записи целочисленной константы в переменную или загрузке ее в регистр нужно не забывать про ее минимальную длину в байтах.

Команда MOVZX (Move With Zero-Extend, или Переместить и дополнить нулями) копирует содержимое исходного операнда в больший по размеру регистр получателя данных. При этом оставшиеся неопределенными биты регистра-получателя (как правило, старшие 16 или 24 бита) сбрасываются в ноль. Эта команда используется только при работе с беззнаковыми целыми числами. Существует три варианта команды MOVZX:

Условные обозначения операндов этой команды приведены в табл. 1. В каждом из приведенных трех вариантов первый операнд является получателем, а второй — источником данных. В качестве операнда-получателя может быть задан только 16- или 32-разрядный регистр. На рис. 8 показано, как 8-разрядный исходный операнд загружается с помощью команды MOVZX в 16-разрядный регистр.

Рис. 8. Иллюстрация работы команды MOVZX.

В приведенном ниже примере используются все три варианта команды MOVZX с разными размерами операндов.

movzx eax, bx ; EAX = 0000A69Bh

movzx edx, bl ; EDX = 0000009Bh

movzx cx, bl ; CX = 009Bh

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

short word1 = 0xA69B;

MOVSX r 32, r / m 16

Рис. 9. Иллюстрация работы команды MOVSX.

В приведенном ниже примере используются все три варианта команды MOVSX с разными размерами операндов.

movsx eax, bx ; EAX = FFFFA69Bh

movsx edx, bl ; EDX = FFFFFF9Bh

movsx cx, bl ; CX = FF9Bh

Источник

Библиотека с советами