Преобразование очень простых инструкций ARM в двоичный / шестнадцатеричный
Я пытался использовать эту страницу, а также различные другие руководства, чтобы понять, как выразить очень простые инструкции ARM в двоичном и шестнадцатеричном виде. Кажется, это должен быть простой процесс для меня, но я все еще не понимаю. Вот несколько примеров.
Основной NOP:
what goes here? what goes here?
_↓_ _____↓____
| | | |
mov r0, r0 ; ????00?1101?????????????????????
|__||__|
↑ ↑
how do I express registers?
Тот же основной вопрос для других.
Сравнивая два регистра:
cmp r1, r0
Добавление немедленного к значению регистра:
add r0, #0x1a
Все эти учебные пособия онлайн превосходно описывают, как использовать подобные инструкции, но ни один из них мне не удалось найти, как на самом деле разобраться, как преобразовать инструкцию ARM в двоичный / шестнадцатеричный / машинный код, в который она собирается.
Заранее спасибо за помощь.
3 ответа
Вот как кодируются инструкции по обработке данных:
У вас есть таблица кодов условий на вашей странице. Регистры закодированы 0000
через 1111
,
Все ваши примеры попадают в одну категорию. Изображение извлечено из какого-то документа на моем жестком диске, но мне также удалось найти его в Google. Кодирование этих инструкций - утомительная работа.
Так, mov r0, r0
должно идти так:
1110 00 0 0 1101 0000 0000 00000000
Я поставил Rn на 0, потому что это на самом деле не относится к MOV
, В случае CMP
, Я верю, S
всегда 1.
Прежде всего, вам нужно ARM Архитектурное справочное руководство (ARM ARM) на infocenter.arm.com, справочные руководства, получите самое старое (armv5 или что-то еще). набор инструкций там четко определен.
Во-вторых, почему бы вам просто не собрать некоторые инструкции и посмотреть, что произойдет?
;@test.s
cmp r1, r0
add r0, #0x1a
какой бы у вас ни был кросс-ассемблер (см. http://github.com/dwelch67/raspberrypi в каталоге сборок gcc для скрипта, просто запустите через этот скрипт binutils)
arm-none-linux-gnueabi-as test.s -o test.o
arm-none-linux-gnueabi-objdump -D test.o
arm-none-linux-gnueabi vs arm-none-elf vs arm-elf и т. д. Не имеет значения для этого, все делают то же самое
Disassembly of section .text:
00000000 <.text>:
0: e1510000 cmp r1, r0
4: e280001a add r0, r0, #26
Верхние четыре бита полной инструкции 32-разрядного плеча (не большого пальца) - это код условия, см. Раздел поля условий в ARM ARM. 0xE означает всегда, всегда выполняйте эту инструкцию. 0b0000 - это eq, только если установлен флаг z, 0b0001 ne, только если z очищен и т. Д.
В ARM ARM нажмите на набор инструкций arm, затем алфавитный список инструкций arm, затем найдите cmp. Он начинается с cond 00I10101 rn sbz shift
Из приведенной выше инструкции cmp мы видим 1110 000101010001 ... поэтому я - нулевые биты 15:12 - нулевые биты, 27:26 - ноль, а 24:21 - 1010, так что это инструкция cmp
биты с 19 по 16 выше равны 0b001, то есть rn, так что rn = 1 (r1) для операнда сдвига в ARM ARM он говорит вам посмотреть на операнды Обработки данных режима адресации 1 и имеет ссылку в pdf на страницу
мы знаем, что мы хотим, чтобы второй операнд был просто регистром, который называется операндом обработки данных - регистр и номер страницы. Перейдите на эту страницу на этой странице. 15:12 это rd 11:4 - нули, а 3:0 - rm., мы знаем из инструкции cmp, что это говорит о том, что 15:12 должно быть нулем, интересно, если это волнует, cmp не сохраняет результат в регистр, поэтому rd не используется. rm используется, и в этом случае мы хотим r0, поэтому 0b0000 идет в 3:0, также обратите внимание, что биты 27:25 показаны как нули, в инструкции cmp 25 есть I, теперь мы знаем, что мы хотим получить ноль, так что
между страницей CMP и этой обработкой данных - страница регистрации у нас есть вся картина
1110 condition
000
1010 opcode
1 S (store flags, that is a 1 for a cmp to be useful)
0001 rn
0000 rd/dont care/sbz
00000
000
0000 rm
cmp rn,rm
cmp r1,r0
add аналогичен, но использует немедленное, так что перейдите к инструкции add в альфа-списке инструкций. теперь мы знаем из cmp, что 24:21 для этого класса инструкций является кодом операции, мы можем в значительной степени перейти прямо к вещам с операндами сдвига, чтобы продолжить оттуда
на этот раз мы делаем add rd,rn,# немедленный
так что ищите страницу для #immediate
и кодировка
1110 condition, always
001 (note the immediate bit is set)
0100 (opcode for add for this type of instruction)
0 (S not saving the flags, it would be adds r0,r0,#26 for that)
0000 (rn = r0)
0000 (rd = r0)
Теперь начинается интересная часть, мы можем кодировать 26 различных способов. биты 7:0 являются непосредственными, а биты 11:8 позволяют вращать эти немедленные, 26 - это 0x1A, мы могли бы просто поместить 0x1A в младшие 8 битов и установить вращение в 0, и это то, что сделал ассемблер gnu. вероятно, можно поместить 0x68 в младшие 8 битов и 1 в поле rotate_imm. 1101000 повернутых вправо 1*2 битов составляет 11010 = 0x1A = 26.
Вы должны получить копию ARM ARM, которая описывает кодировку для всех инструкций.
Большинство инструкций ARM используют 4 старших бита для условного кода. Если вы не хотите выполнять инструкцию условно, просто используйте псевдо-условие AL (1110).
Первый регистр (Rn) в кодировании не используется для инструкции MOV, и он должен быть установлен в 0000, как определено ARM ARM.
Второй регистр - это пункт назначения, здесь вы просто кодируете номер регистра, так что в вашем случае это также будет 0000, потому что вы используете r0 в качестве адресата, для r 4 это будет 0100.
Остальная часть - это так называемый операнд сдвига, который очень гибкий. Это может быть простой регистр, как в вашем случае (r0), тогда это просто 0000 0000 0000, где последние 4 бита снова кодируют регистр. Он также может кодировать различные типы сдвигов и вращений с помощью регистра или непосредственных значений для обработки данных.
Но это также может быть момент, когда 8 бит закодированы в нижних битах, а первые 4 бита определяют поворот вправо с шагом в 2 бита. В этом случае бит25 также будет равен 1, во всех остальных случаях - 0.