Как использовать инструкцию MOV в ARM с немедленным номером в качестве второго операнда
Я только начинаю изучать язык ассемблера ARM, и не понимаю, как использовать MOV для передачи немедленного числа в регистр.
Как из справочного руководства ARM, так и из моего учебника, он сказал, что диапазон немедленного числа после инструкции MOV равен 0-255. Но когда я тестирую свой компьютер в ADS 1.2 IDE, инструкция
MOV R2, #0xFFFFFFFF
работает хорошо. Не указано ли число 0xFFFFFFFF вне диапазона в соответствии со спецификацией?
Надеюсь, кто-то может дать мне руку.
С уважением.
Ответы
Ответ 1
Помните, что ARM может выполнять определенный набор манипуляций по непосредственному значению как часть переключателя ствола, который включен в коды операций ARM.
В этой небольшой статье есть одно из самых ясных объяснений некоторых из трюков, которые ARM-ассемблер может использовать для установки большого числа в небольшое доступное пространство инструкции ARM:
В статье обсуждается трюк, который, вероятно, используется в вашем конкретном примере генерации кода операции MVN для загрузки поразрядного дополнения к непосредственному значению.
Подобные манипуляции не могут быть выполнены со всеми непосредственными значениями, но ARM-ассемблеры предположительно довольно умны (и компиляторы C, конечно же, есть). Если никакие смены/дополнения не могут быть выполнены, значение, как правило, загружается из местоположения, соответствующего ПК, или, возможно, путем "наращивания" значения из нескольких инструкций.
Ответ 2
Одна команда ARM может кодировать только постоянную константу, которая может быть представлена как 8-битное мгновенное значение, сдвинутое на любую четную мощность двух.
Однако существует также инструкция MVN
, которая похожа на MOV
, но инвертирует все биты. Таким образом, хотя MOV R2, #0xFFFFFFFF
не может быть закодирован как инструкция MOV
, его можно закодировать как MVN R2, #0
. Ассемблер может выполнить это преобразование для вас.
Ответ 3
Несколько сложно определить, находятся ли заданные константы в допустимом диапазоне.
Как уже упоминалось в Мэттью, ассемблер дает вам руку, заменяя приведенные инструкции аналогичными, отрицательными, такими как mov/mvn, cmp/cmn, tst/tne и т.д.
Ответ 4
Инструкция MOV может либо принять значение imm16, либо значение Operator2 (из-за длины инструкции, противоположной выравниванию памяти), которая должна соответствовать любому из следующих правил (скопирована из руководства по набору инструкций CortexM, X и Y - любое шестнадцатеричное значение):
- Любая константа, которая может быть создана путем сдвига 8-битного значения, оставленного любым количеством бит в пределах
32-битное слово.
- Любая константа формы 0x00XY00XY.
- Любая константа формы 0xXY00XY00.
- Любая константа вида 0xXYXYXYXY.
Вот почему принимается 0xFFFFFFFF (соответствует 4-му правилу).
Если вы хотите собрать свою 32-битную константу, вы можете использовать команду MOVT, которая записывается в верхнюю половину регистра.
Ответ 5
Вы можете видеть артефакты с расширением знака исходного значения. Если инструменты, которые вы используете для просмотра дизассемблирования, обрабатываете 0..255 в качестве подписанного байта, тогда, когда он загружает его в более крупный тип (или регистр), он заполняет все верхние биты знаковым битом оригинала стоимость. Или, если это так, если 0xFF является подписанным байтом, его десятичное значение равно -1. Поместите это в 32-битный регистр, и шестнадцатеричный будет выглядеть как 0xFFFFFFFF, а его десятичное значение все равно -1.
Попробуйте использовать значение без набора высоких бит, например 0x7F. Поскольку бит знака не установлен, я предполагаю, что он заполнит верхние биты нулем при загрузке в более крупный регистр типа int или поле.
Также возможно, что компилятор/ассемблер обрезает любое значение, которое вы предоставляете. Я считаю, что это ошибка исходного кода, но сборщики - забавные звери. Если вы даете ему 0x7FF, он компилируется в 0x7FF (не усечен и больше 0,255) или 0xFFFFFFFF (усечен до 0..255, подписанный байт)?
Ответ 6
Если вы хотите переместить 0xffffffff в реестр, вы всегда можете сделать:
MOV R0, #-1
потому что 0xffffffff является представлением с двойным дополнением к -1
Ответ 7
Одна из возможностей заключается в том, что ассемблер ARM отбрасывает значимые биты числа и использует только самый низкий FF.
Инструкция MOV является скобкой во множестве наборов инструкций процессора, и обычно ассемблер разрешает размер целевого регистра и поставляемое мгновенное значение.
Например, следующие команды MOV из набора x86:
MOV BL, 80h, ; 8bit
MOV BX, ACACh ;16bit
MOV EBX, 12123434h ; 32bit