Инструкция 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, которое можно перевести как “переместить, перенести, передвинуть”. И, как теперь вам уже понятно, эта команда соответствует своему названию — она перемещает значение из одного регистра в другой. Хотя с точки зрения русского языка это будет не совсем правильно, потому что перемещения не происходит — значение из ИСТОЧНИКА никуда не исчезает (не перемещается), по сути оно копируется и вставляется в ПРИЁМНИК.
Подписаться на Дзен-канал
Вступить в группу «Основы программирования» Подписаться на рассылки по программированию |
Первые шаги в программирование
Главный вопрос начинающего программиста – с чего начать? Вроде бы есть желание, но иногда «не знаешь, как начать думать, чтобы до такого додуматься». У человека, который никогда не имел дело с информационными технологиями, даже простые вопросы могут вызвать большие трудности и отнять много времени на решение. Подробнее… |
Ассемблер ARM64 | Инструкция MOV
Последнее обновление: 28.12.2022
Инструкция MOV помещает значение в регистр. Например, поместим значение 1 в регистр X0:
mov X0, #1
В качестве второго операнда инструкция принимает 16-битное значение.
непосредственный операнд
. Для числа 1 требуется не больше 16 бит, поэтому проблем не возникнет. Но что если мы захотим поместить в
регистр гораздо большее значение, например, 400000000, памятуя о том, что регистры у нас могут содержать 64-битные значения? При компиляции через GCC GNU мы получим ошибку:Error: immediate cannot be moved by a single instruction
Чтобы загрузить значения гораздо большей разрядности нам может помочь инструкция MOVK, которая рассматривается далее.
Также с помочь инструкции MOV можно загружать значение из одного реггистра в другой:
MOV X1, X2
В данном случае копируем содержимое регистра X2 в регистр X1.
Применение сдвига и вращения
При помещении значения в регистр команда mov позволяет сдвинуть его на определенное количество бит. Для сдвига и вращения значения применяются следующие операции:
LSL: логический сдвиг влево
LSR: логический сдвиг вправо
ASR: арифметический сдвиг вправо
ROR: поворот вправо
После команды идет непосредственный операнд, который указывает, на сколько бит надо сдвинуть значение. Например:
mov X1, #22 mov X2, X1, LSL #1 // логический сдвиг влево на 1 разряд mov X2, X1, LSR #1 // логический сдвиг вправо на 1 разряд mov X2, X1, ASR #1 // арифметический сдвиг вправо на 1 разряд mov X2, X1, ROR #1 // поворот вправо на 1 разряд
В данном случае кладем в регистр X1 значение 22, затем берем его, применяем сдвиг/поворот и кладем в регистр X2. Следует учитывать, что команда mov позволяет только применить сдвиг к значению из регистра.
Операции сдвига настолько распространены, что для них имеются псевдонимы:
mov X1, #22 LSL X2, X1, #1 // логический сдвиг влево на 1 разряд LSR X2, X1, #1 // логический сдвиг вправо на 1 разряд ASR X2, X1, #1 // арифметический сдвиг вправо на 1 разряд ROR X2, X1, #1 // поворот вправо на 1 разряд
MOVK
Инструкция MOVK (move keep) представляет разновидность инструкции MOV
и
позволяет загрузить все 64 бита регистра. В реальности она загружает 16-битные операнды в одну из 4 частей регистра, не оказывая никакого влияния на другие 48 бит. Например,
допустим, мы хотим загрузить в регистр X2 64-битное шестнадцатеричное значение 0x1234ABCD5F5F8D7E. В этом случае мы могли бы написать:
MOV X2, #0x8D7E MOVK X2, #0x5F5F, LSL #16 MOVK X2, #0xABCD, LSL #32 MOVK X2, #0x1234, LSL #48
Команда MOVK
для заполнения нужной части регистра выполняет сдвиг на определенное количество бит, которое должно быть кратно 16.
Следует отметить, что первый вызов инструкции mov
в реальности эквивалентен инструкции MOVZ, которая аналогична MOVK за тем
исключением, что заполняет оставшиеся 48 байт нулями.
MOVN
Инструкция MOVN (Move Not) работает аналогично MOV
за тем исключением, что она инвертирует все разряды числа
при загрузке в регистр, то есть 1 изменяет на 0, а 0 — на 1. Эта инструкция ценна тем, что может применяться для получения отрицательного значения числа, ведь отрицательное значение
по сути предполагает инвертирование разрядов и прибавление 1 к инвертированному числу. Что производительнее, чем использовать инструкцию умножения.
Кроме того, инструкция MOVN
за счет дополнительного знакового бита (17 бит вместо 16 бит для mov) позволяет использовать значение в два раза больше.
При этом если ассемблер видит, что указанное число превышает 16 бит, допустимых для инструкции MOV
,
то он автоматически преобразует инструкцию в MOVN
. Например:
MOV W1, #0xFFFFFFFE // (-2)
Здесь инструкция MOV преобразуется в MOVN, так как переданное значение
Применение инструкций MOV
Пример небольшой программы, которая использует различные инструкции MOV:
// Пример применения инструкций MOV .global _start // адрес входной точки в программу // Загружаем в регистр X2 значение 0x1234ABCD5678EF1A _start: MOV X2, #0xEF1A MOVK X2, #0x5678, LSL #16 MOVK X2, #0xABCD, LSL #32 MOVK X2, #0x1234, LSL #48 // Перемещаем значение регистра W2 в W1 (32-х битные регистры) MOV W1, W2 // пример операций сдвига и вращения MOV X1, X2, LSL #1 // Логический сдвиг влево на 1 бит MOV X1, X2, LSR #1 // Логический сдвиг вправо на 1 бит MOV X1, X2, ASR #1 // Арифметический сдвиг вправо на 1 бит MOV X1, X2, ROR #1 // Поворот вправо на 1 бит // те же инструкции только с использованием мнемоник LSL X1, X2, #1 // Логический сдвиг влево на 1 бит LSR X1, X2, #1 // Логический сдвиг вправо на 1 бит ASR X1, X2, #1 // Арифметический сдвиг вправо на 1 бит ROR X1, X2, #1 // Поворот вправо на 1 бит // пример инструкции MOVN MOVN X3, #45 // устанавливаем параметры и вызываем системный вызов Linux для выхода из программв MOV X0, #0 // 0 - код возврата MOV X8, #93 // номер функции Linux для выхода из программы - 93 SVC 0 // Вызываем функцию и выходим из программы
НазадСодержаниеВперед
— MOV src, dest (или) MOV dest, src?
спросил
Изменено 3 года, 2 месяца назад
Просмотрено 22к раз
MOV, наверное, первая инструкция, которую все узнают при изучении ASM.
Только что я наткнулся на книгу Раджата Муны «Программирование на языке ассемблера в GNU/Linux для архитектур IA32», в которой говорится: (ссылка удалена)
Но я узнал, что это MOV dest, src
. Это похоже на «Загрузить dest
с src
». Даже Вики говорит то же самое.
Я не говорю, что автор не прав. Я знаю, что он прав. Но что мне здесь не хватает?
кстати… он использует GCC как
для сборки этих инструкций. Но это не должно изменить синтаксис инструкции, верно?
- сборка
- x86
- nasm
- masm
- gnu-assembler
mov dest, src
называется Синтаксис Intel . (например, mov eax, 123
)
mov src, dest
называется синтаксис AT&T . (например, mov $123, %eax
)
Ассемблер UNIX, включая ассемблер GNU, использует синтаксис AT&T, все другие известные мне ассемблеры x86 используют синтаксис Intel. Вы можете прочитать о различиях в википедии.
5 Да, as/gas использует синтаксис AT&T, в котором используется порядок src,dest. MASM, TASM, NASM и т. д. используют порядок «dest, src». Как оказалось, синтаксис AT&T не очень хорошо подходит для процессоров Intel и (по крайней мере, IMO) представляет собой почти нечитаемый беспорядок. Например, movzx
получается особенно плохо
Существует два различных типа синтаксиса языка ассемблера — синтаксис Intel и AT&T. Вы можете найти сравнение обоих на странице языка ассемблера Википедии.
Скорее всего, в вашей книге используется синтаксис AT&T, где исходный операнд стоит перед адресатом.
Как уже упоминалось в ответе Джерри Коффина, синтаксис Intel лучше подходит для кодировки инструкций для архитектуры x86. Как говорится в комментарии к дизассемблеру моего отладчика, «операнды появляются в инструкции в том же порядке, в каком они появляются в выводе дизассемблирования». Например, рассмотрим эту инструкцию:
-a 1772:0100 тестовое слово [AA55], 1234 1772:0106 -у 100 л 1 1772:0100 F70655AA3412 тестовое слово [AA55], 1234 -
Как вы можете прочитать в шестнадцатеричном дампе кода операции, сначала идет код операции 0F7h
, затем байт ModR/M 06h
, затем слово смещения с прямым порядком байтов 0AA55h
и, наконец, непосредственное слово 1234h 9 0016 . Синтаксис Intel соответствует этому порядку в исходном коде сборки. В синтаксисе AT&T это выглядело бы как
testw $0x1234, (0xAA55)
, что меняет порядок по сравнению с кодировкой.
Другим примером, который подчиняется порядку синтаксиса Intel, являются условия сравнения. Например, рассмотрим эту последовательность:
Топор смр, 26 Джей лейбл
Это перейдет к .label
, если ax
больше или равно 26 (в беззнаковом сравнении). Эта мнемоника верна только для порядка операндов cmp dest, src
, который устанавливает флаги как для dest -= src
.
Зарегистрируйтесь или войдите в систему
Зарегистрируйтесь с помощью Google Зарегистрироваться через Facebook Зарегистрируйтесь, используя электронную почту и парольОпубликовать как гость
Электронная почтаТребуется, но не отображается
Опубликовать как гость
Электронная почтаТребуется, но не отображается
Нажимая «Опубликовать свой ответ», вы соглашаетесь с нашими условиями обслуживания и подтверждаете, что прочитали и поняли нашу политику конфиденциальности и кодекс поведения.
Сборка- Как я могу использовать MOV в ассемблере?
спросил
Изменено 1 год, 8 месяцев назад
Просмотрено 2к раз
Я кодирую ASM и совершенно не понимаю правил mov
, поэтому
mov rax, 100 ; это означает, что число 100 находится в rax? мов ракс, а ; это означает, что значение a находится в rax? или это направление памяти? мов ракс, [а] ; это означает значение a? или что? мов [а], ракс ; направление мемори при смене на rax? мов ракс, rbx ; rbx теперь rax?
Извините, если мой вопрос глупый, но я действительно запутался. .. спасибо
- сборка
- x86
- x86-64
- mov
Поскольку у нас есть mov rax, 100
как действительный, мы знаем, что это синтаксис Intel. Продолжая и предполагая, что a является меткой, а не макросом или equ, в результате получается константа:
mov rax, 100 ; Всегда означает поставить константу 100 в rax мов ракс, а ; Либо означает поместить адрес a в rax, ; или поставить в rax смотря какой ассемблер. ; Для nasm это всегда адрес a. мов ракс, [а] ; Всегда означает 8-байтовое значение, хранящееся в ; для смещений более 2 ГБ целевой регистр должен быть al, ax, eax или rax мов [а], ракс ; Поместите значение rax в значение, хранящееся в мов ракс, rbx ; Поместите значение rbx в rax (без доступа к памяти) mov rax, [rbx] ; Поместите значение, сохраненное там, где rbx указывает на rax
Я добавил последний для полноты картины. Не занимайтесь математикой в [] операциях здесь.