Как использовать инструкцию 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