Вместо введения. Чем ARM процессоры необычны.
 	Что такое "тумба". Два набора команд в одном процессоре.

 	Младшие версии ARM процессоров имеют 32 разрядный набор команд, ориентированный преимущественно на обработку 32-х разрядных данных. 
Высокая разрядность данных, заложенная в ARM изначально, хорошо подходит для устройств с большой вычислительной нагрузкой. "Широкие" команды дают возможность в коде одной команды реализовать достаточно сложную обработку данных, для которой в других процессорах потребуется несколько команд - например, совместить сдвиг,  сумму, и перенос в другой регистр. Но с другой стороны, эти же свойства снижают применимость младших версий ARM процессоров в качестве вычислительных ядер для недорогих, встраиваемых или мобильных устройств с малоразрядной периферией, получивших сейчас большое распространение. Для реализации простой логики управления 4 байтная команда занимает слишком много места в памяти, а 32 разряда данных используются неэффективно.
 	Для придания современным версиям ARM процессоров большей универсальности, им добавили  второй набор, уже 2 байтных команд, гораздо более эффективный по размеру кода.  Набор укороченных команд называется Thumb, а набор 'стандартных' команд- ARM наборами. Несмотря на то, что 'внутри' процессора команды Thumb преобразуются перед исполнением в ARM инструкции, с точки зрения программиста эти наборы настолько отличаются, что вполне могли бы принадлежать разным процессорам. Переход от одного набора к другому может выполняться в любом месте, практически любой алгоритм можно написать либо на ARM либо на Thumb, по усмотрению программиста. Но, поскольку в Thumb наборе нет команд, требуемых для обработки исключительных ситуаций (к примеру, сброса или прерываний), любая программа требует включения фрагментов ARM. После сброса или  наступления исключительной ситуации процессор принудительно переключается к исполнению команд ARM набора.
 	Набор Thumb, имея меньшую разрядность, оптимизирован, в его состав ввели только команды, реализующие наиболее важные операции, и он несколько ограничивает доступ к ресурсам процессора.  Например,  с 16 до 8 меняется число полностью доступных регистров. Некоторые команды из набора Thumb предоставляют ограниченный доступ к регистрам R8..R15, называемых в этом режиме 'верхними', или 'старшими регистрами' (high registers).  Указатель стека SP (R13), регистр адреса возврата LR (R14), счетчик команд PC (R15) доступны в Thumb через специальные команды, прямой доступ к словам состояния CPRS и SPRS не предоставляется.
 	Программная смена набора команд происходит при выполнении двух специальных команд - "BX" 'перехода на адрес с изменением'  (Branch and eXchange) и вызова подпрограммы  "BLX", (Branch, Link and eXchange). Если при исполнении этих команд младший разряд адреса перехода равен 1, процессор переключится в Thumb режим, если равен 0, то в ARM режим.  Последующие команды,  на которые осуществляется переход, будут рассматриваться как принадлежащие выбранному набору. Эти две команды присутствуют и в Thumb и в ARM, конечно для каждого набора свои  версии. 
 	Команды ARM режима длиной 4 байта, хранятся по адресам, кратным 4-м  (0, 4, 8, 0xC и т.д.), а двухбайтные команды THUMB режима по адресам, кратным 2 (0, 2, 4...). Нетрудно заметить, что в обоих случаях последний разряд адреса равен нулю. Поэтому для реализации перехода в Thumb режим  необходимо устанавливать этот бит  'принудительно', для чего к адресу прибавляют единицу. 
Пример: 
	LDR  	R1,=TProc1 +1;     ( * см. далее “Команды, которых нет”)
 	BX 	R1; переход на адрес TProc1 с изменением набора команд на Thumb.

 	В сам регистр R15 адрес загружается в любом случае с обнуленным младшим разрядом.
В отличии от команд 'BX' и 'BLX', применение 'обычных' команд 'B' и 'BL' или изменение значения регистра R15 любой командой, к смене набора команд не приводит. Поэтому в Thumb режиме +1 к каждому адресу перехода приписывать не надо, что значительно облегчает жизнь программиста.
 	Есть еще один способ сменить набор инструкций. Необходимо установить в нужное состояние флаг T в регистре SPSR и выполнить команду восстановления регистра CPSR из SPSR. 
 	Замечание: в нормальном режиме исполнения программ регистр SPSR недоступен, он есть только в некоторых привилегированных режимах.  Непосредственное изменение T флага в регистре CPSR приводит к НЕПРЕДСКАЗУЕМОМУ результату.
 	Команды, которых нет.

 	Еще одна особенность программирования для ARM, первое время затрудняющая работу - это наличие в исходных текстах программ или листингах деассемблера таких команд или способов адресации, которые не умеет исполнять процессор и которых, соответственно, нет в его описании. Это вызвано тем, что огромное разнообразие возможных форм команд вынуждает для самых часто используемых из них применять специальные сокращенные обозначения. 
	К примеру, формы автоматической адресации команды LDR вызывают немало вопросов.
 	Команда LDR Load Register служит для загрузки в указанный первым операндом регистр 32-х разрядного слова из памяти. Адрес памяти, откуда происходит загрузка, может вычисляться процессором 9-ю различными, порой довольно сложными способами. Подробно способы вычисления адреса будут рассмотрены далее, но сейчас отметим, что все они требуют, чтобы в качестве базового при вычислении адреса использовалось значение, хранящееся в одном из регистров R0:R15.

Самая простая форма вычисления адреса памяти для команды LDR такова:

 	LDR Rd, [Rm,#смещение]
- загрузить в Rd значение хранящееся по адресу Rm + смещение. 

При нулевом смещении допустима такая упрощенная запись:

 	LDR Rd, [Rm] ; - синоним LDR Rd, [Rm, #0]

 	Получается, что если мы хотим при помощи самой простой формы команды LDR загрузить в регистр R1 число 0x22334455, нам нужно:

 1. Сохранить это число в памяти (при компиляции, например)
 2. Загрузить в любой регистр, скажем, в R2  адрес этого числа
 3. Выполнить LDR R1,[R2]

А как нам выполнить пункт 2? Как нам загрузить в регистр 32 битный адрес? Выходом служит вычисление адреса данных относительно состояния регистра R15 (счетчик команд, PC), значение которого всегда определенно и на текущий момент известно – оно равно адресу выполняемой команды. Надо только учитывать, что при любом чтении из R15 в режиме ARM возвращается значение равное (адресу_текущей_команды + 8)*. 

thisAddr: 	LDR	R1,[R15, #SourceData - thisAddr - 8] ; коррекция на 8
...
SourceData:	DD 	0x22334455	; недалеко в памяти данные 
 	; это работающий пример загрузки в регистр R1 числа 0x22334455 

 	Конечно, это сложно и неудобно. Для упрощения жизни программистов у ARM ассемблера есть специальные формы автоматической адресации (здесь под ассемблером подразумевается программа, переводящая исходный *.asm текст в объектный код):

-------------------------------------------------------------------------------
* Примечание: в Thumb чтение R15 дает значение, равное (адресу_текущей_команды + 4)

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

	LDR	R1, SourceData; прочитать значение по адресу SourceData в регистр
	STR	R1, SourceData; записать из регистра в адрес SourceData

SourceData:	DD  0x22334455; адрес недалеко в памяти 

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

 	LDR R1,=0x22334455	; здесь R1 := 0x22334455

Или, как вариант загрузки произвольного 32 разрядного адреса:
...
Label_1:
	LDR R1, =Label_1;   здесь R1 := адресу Label_1 (адрес тоже Число) 
...
Применяя эти формы команды, надо всегда помнить о том, что мы используем не свойство процессора, адресовать данные таким образом, а свойство программы - ассемблера разворачивать эти упрощенные вызовы в конструкции вида  

	LDR	Rd, [PC, #offsetDataStore];
 ...
DataStore: DD 123456789;

Это накладывает ограничения на использование автоматической адресации. Во первых, смещение 12 разрядное (для команд LDRD STRD LDRH STRH LDRSH LDRSB даже 8 разрядное), то есть для загружаемых данных должно найтись место в пределах +/- 4095 (+/- 255) адресов от команды. Во вторых, понятно, что при сохранении данных командой STR надо убедится, что мы не пытаемся записывать в ПЗУ, или, при отладке, мы не должны писать в сегмент кода (запись в него запрещена). Но если в KEIL создать для имитации ОЗУ сегмент данных с разрешением записи, попытка автоматической адресации данных за пределы сегмента кода дает ошибку при ассемблировании: 
error A20: INVALID SIMPLE RELOCATABLE EXPRESSION. 

В некоторых случаях надо быть готовым к тому, что ассемблер заменит конструкцию LDR Rn,=data на команду MOV Rn, #data. Это произойдет, если загружаемое значение можно представить как любое 8 разрядное число от 0x00 до 0xff, циклически сдвинутое на произвольное четное количество разрядов (0,2,4...30) внутри 32 разрядного регистра (просто, не правда ли? =), в этом случае будет произведена оптимизация, и вместо ожидаемой команды LDR будет вставлена команда 
MOV Rn,#data
где #data - так называемые непосредственные данные. Подробнее о них - дальше, в разделе addressing_mode.

IDA умеет 'сворачивать' команды LDR обратно в формы автоматической адресации, но тем не менее не прячет данные, которые участвуют в такой операции:

               LDR     PC, =loc_A000009C; свернутая форма
; -------------------------------------------------
off_A0000004   DCD loc_A000009C ; это те данные, которые грузятся

 	Еще две 'команды', которые встречаются в программах, но которые не умеет исполнять процессор:
 	ADR Rx, Address ; - загрузить в Rx указанный относительный адрес. Реально это команда превращается ассемблером в команду ADD Rx,PC,#xx или SUB Rx,PC,#xx, вычисляя нужное значение прибавлением или вычитанием смещения от PC. Очевидное ограничение - применимое для написания программ смещение между адресом команды и загружаемым адресом не более +/-255 байт. 
	RET – В действительности это команда MOV R15,R14.
 	Еще один вариант “автоматической” команды – MOVL Rx,#data
В Thumb режиме максимальное число, загружаемое в регистр командой mov Rx,#data равно 255. При необходимости загрузить большее число, применяют команду movl Rx,#data, которая автоматически будет заменена на пару команд:  
mov Rx,#data
lsl Rx,Rx,#shift
или
mov Rx,#data1
add Rx,#data2
в зависимости от того, каким образом можно представить число, которое необходимо загрузить. В отличие от IDA, Keil такую форму команды не понимает 
Типы данных и размещение в памяти. Дамп программы.

Для ARM процессора используются   данные четырех типов: байт, полуслово, слово и двойное слово. Некоторые дополнительные команды версии ARM9E используют 32 разрядное значение в регистре как два упакованных 16 разрядных полуслова со знаком.
БАЙТ (byte),
8 разрядов, может храниться по произвольному адресу.  Для чтения и записи используются команды LDRB,LDRSB, STRB.

Пример на ассемблере:
...
org 0x20
MyByte1: DB 0x1	; по адресу 0x20 поместим байт данных равный 0x1
MyByte2: DB 0x2	; по адресу 0x21 поместим байт данных равный 0x2
MyByte3: DB 0x3	; по адресу 0x22 поместим байт данных равный 0x3
MyByte4: DB 0x4	; по адресу 0x23 поместим байт данных равный 0x4
MyByte5: DB 0x5	; по адресу 0x24 поместим байт данных равный 0x5
...
 	Не стоит забывать, что в ARM процессорах подразумевается 32 разрядная шина данных. Поэтому дамп предыдущего примера в отладчике keil, показывающего память в виде 32 разрядных слов,  покажет такой результат: 

дамп keil:
0x00000020  04030201 - байты объединены в слово.
0x00000024  00000005 - продолжение в следующем слове, адрес 0x24.   

Но дамп IDA покажет:
0x00000020  01 02 03 04 05 - обычный порядок байт (данные не объединены в слова)
ПОЛУСЛОВО (halfword), 
16 разрядов, адрес хранения должен быть четным (адрес[0] = 0).  Команды LDRH,LDRSH, STRH

org 0x20
MyHalf1:	DW 0x1111; по адресу MyHalfW поместим полуслово равное 0x1111
NextHalf: 	DW 0x2222; еще полуслово
NextHalf: 	DW 0x3333; еще полуслово

дамп keil:
0x00000020   22221111  
0x00000024   00003333  
дамп IDA:
0x00000020  11 11 22 22 33 33 
СЛОВО (word),
Основной тип данных, 32 разряда. Адрес должен быть выравнен кратно 4м байтам (адрес[0]=0; адрес[1]=0). Команды LDR, STR и другие.

org 0x20
MWord: 	DD 0x12345678 ; по адресу MWоrd поместим слово равное 0x12345678

дамп keil:
0x00000020  12345678  
дамп IDA:
0x00000020  78 56 34 12 ; IDA  показывает (по умолчанию) вместо слов байты
 	Все команды обработки  данных, например ADD, оперируют с 32 разрядными словами. Исключением являются дополнительные команды арифметики с насыщением. Команды передачи данных оперируют с 8, 16, 32 или 64 разрядными значениями. 
 	Все перечисленные типы данных могут рассматриваться как беззнаковые, так и как значения со знаком. При загрузке в 32 разрядные регистры байт или полуслов из памяти специальными командами LDRB, LDRH происходит автоматическое дополнение ведущими нулями, а по команде LDRSB,LDRSH происходит расширение знакового разряда. 
...
start: 	LDRB R3,dataByte	;в R3 загрузится 0x00000081- дополнение нулями 
		LDRSB R4,dataByte	;в R4 загрузится 0xffffff81- расширение знака 
		LDRSB R4,dataByt1	;в R4 загрузится 0x0000007E- расширение знака 
dataByte: 	DB 0x81		; Однобайтовое значение
dataByt1: 	DB 0x7E		; Однобайтовое значение
...		
ДВОЙНОЕ СЛОВО (dword),
 64 разряда, адрес должен быть выравнен кратно 4м байтам (адрес[0]=0; адрес[1]=0).  
Команда LDRD Rd,<addressing_mode> загружает из памяти два последовательных регистра, Rd и Rd+1, команда STRD сохраняет их. Для этой команды в качестве Rd можно указывать только четные регистры R0 R2 R4 R6 R8 R10 или R12.

Работа с дампом программы в IDA
 
В самом начале работы прошивка телефона выглядит как последовательность байт - дамп памяти. И всегда интересно, где нажать 'C', чтобы получить осмысленный результат в виде ассемблерной программы. Что можно предпринять, чтобы достичь желаемого? Рассмотрим для примера участки дампа прошивки Siemens CX70v50
 	Во первых, участок такого вида: 
BCORE:A000087F          DCB    0
BCORE:A0000880          DCB 0x53 ; S
BCORE:A0000881          DCB 0x49 ; I
BCORE:A0000882          DCB 0x45 ; E
BCORE:A0000883          DCB 0x4D ; M
BCORE:A0000884          DCB 0x45 ; E
BCORE:A0000885          DCB 0x4E ; N
BCORE:A0000886          DCB 0x53 ; S
BCORE:A0000887          DCB    0

поощряет нажать клавишу 'A' для создания строки, желательно на адресе, кратном 4  (здесь A0000880), так как чаще всего к строкам обращаются  командами загрузки 32 разрядных регистров, или командами мультирегистровой загрузки, данные для которых выравниваются кратно 4 байтам.
 	Во вторых, если явных признаков строк или данных нет, вспомним, что команды набора ARM четырехбайтные, выравнены в памяти кратно 4, поэтому не могут начинаться с адресов иных, чем с шестнадцатеричными цифрами 0, 4, 8 или C в конце.
 	В третьих, подпрограммы - основа любой программы, поэтому стоит обратить внимание на участки, предположительно, кода в которых на границе слов (4х байт) встречается команда с кодом E92Dxxxx - команда STMFD   SP! ,{xx} сохранения регистров в стек. 

BCORE:A000242C ; --------------------------
BCORE:A0002430              DCB 0x38 ; \  1й байт
BCORE:A0002431              DCB 0x40 ;  | 2й байт
BCORE:A0002432              DCB 0x2D ;  | 3й  команда E9 2D 40 38
BCORE:A0002433              DCB 0xE9 ; /  4й
BCORE:A0002434              DCB    1
BCORE:A0002435              DCB 0x50 ; 
Поместим курсор на первом байте команды (здесь – равен 0x38).  Вот что получилось после нажатия 'C': 
A0002430 ; -----------------------------------------
A0002430    STMFD   SP!, {R3-R5,LR} ;сохранить регистры и адрес возврата
A0002434    MOV     R5, R1
A0002438    MOV     R4, R0
A000243C    BL      sub_A0002574
A0002440    BL      sub_A00027E8
A0002444    CMP     R0, #0
A0002448    LDREQ   R1, =0x1C200
A000244C    MOVEQ   R0, #3
A0002450    LDMEQFD SP!, {R3-R5,LR}
A0002454    BEQ     sub_A0002478
A0002458    MOV     R1, R5
A000245C    MOV     R0, R4
A0002460    BL      sub_A00025B4
A0002464    BL      sub_A0002E40
A0002468    CMP     R0, #0
A000246C    LDMNEFD SP!, {R3-R5,LR}; 
A0002470    BNE     loc_A00063B0   ; 
A0002474    LDMFD   SP!, {R3-R5,PC}; конец подпрограммы

 	Видим, что это вполне осмысленная подпрограмма, нажмем 'P' на ее начале и подтвердим создание.
 	Гораздо реже подпрограмма ARM режима начинается с команды сохранения одиночного регистра LR в стек: 
STR LR, [SP,#-4]!  (E5 2D E0 04) :

 A0824258      DCB    4   \
 A0824259      DCB 0xE0 ;  |
 A082425A      DCB 0x2D ;  | STR LR, [SP,#-4]!  
 A082425B      DCB 0xE5 ; /
 A082425C      DCB 0xB8 ; 
 A082425D      DCB 0xFD ; 
 A082425E      DCB 0xFF ;

Результат 'C':
 A0824258      STR     LR, [SP,#-4]!
 A082425C      BL      sub_A0823944
 A0824260      CMP     R0, #0
 A0824264      BEQ     loc_A0824278
 A0824268      LDR     R1, [R0,#4]
 A082426C      LDR     R2, =0x73617072
 A0824270      CMP     R1, R2
 A0824274      LDREQ   PC, [SP],#4
 A0824278 loc_A0824278               ; CODE XREF:  A0824264_j
 A0824278      MOV     R0, #0
 A082427C      LDR     PC, [SP],#4

Большинство  команд ARM режима обычно имеют старший ниббл (полубайт, тетрада) равный 'E', так как это соответствует признаку  0b1110 - Always, безусловное исполнение команды. Если какой- либо участок памяти выглядит подобно этому (обратите внимание на расположение байтов с E в начале):

A00021C0  28 10 94 E5 63 03 D4 E1-29 00 00 EB 41 00 00 EA 
A00021D0  4B 10 93 E5 48 03 D3 E1-4D 30 A0 E1 41 20 A0 E3 
A00021E0  54 02 00 EB 4F 00 50 E3-56 00 00 0A 2E 10 A0 E1 

то вероятность того, что это  код ARM, очень велика.

Адреса команд Thumb всегда четные. Команды Thumb более компактны,  и код имеет более равномерный "спектр", поэтому отличить код от данных сложнее. Зато 99% подпрограмм начинаются с команды PUSH {regs,LR}, код которой  B5 xx, где xx – маска сохраняемых регистров. 

	Попробуем найти вероятное начало Thumb подпрограммы в таком коде:
 A1714F2B         DCB 0x68 ; h
 A1714F2C         DCB 0x40 ; @
 A1714F2D         DCB 0x18
 A1714F2E         DCB 0x40 ; @
 A1714F2F         DCB 0x68 ; h
 A1714F30         DCB 0x70 ; p
 A1714F31         DCB 0x47 ; G
 A1714F32         DCB 0x80 ; A \<= возможно здесь начало Thumb подпрограммы?
 A1714F33         DCB 0xB5 ; ¦ / 
 A1714F34         DCB 0xFF
 A1714F35         DCB 0xF7 ; ?
 A1714F36         DCB 0xD6 ; a
 A1714F37         DCB 0xFF
 A1714F38         DCB    0

Переключим IDA в режим разбора Thumb команд. Для этого нажмем alt+G и в появившемся диалоге присвоим биту 'T’ значение 1.
Нажмем 'P' на адресе (четном) первого байта команды и посмотрим результат:

sub_A1714F32
 A1714F32         PUSH    {R7,LR}
 A1714F34         BL      sub_A1714EE4
 A1714F38         CMP     R0, #0
 A1714F3A         BEQ     loc_A1714F62
  . . . . .

 A1714F5A         CMP     R0, R1
 A1714F5C         BNE     loc_A1714F62
 A1714F5E         MOV     R0, #1
 A1714F60         POP     {R7,PC}

Наша догадка верна. Если бы мы ошиблись, всегда можно нажать 'U' для отмены.
 	Для автоматического поиска байта или их последовательности можно вызвать диалог, нажав alt+b .
 	
 	Вспомним, что для вызова Thumb кода к адресу прибавляют единицу. Это поможет понять следующий фрагмент:

CODE2:A0CE080F                 DCB    0
CODE2:A0CE0810                 DCB 0x1F
CODE2:A0CE0811 unk_A0CE0811    DCB 0xB5 ;DATA XREF: CODE2:off_A0CE09BC
CODE2:A0CE0812                 DCB 0x81 ; Á
CODE2:A0CE0813                 DCB 0x68 ; h

Очевидно, что IDA обнаружила обращение по нечетному адресу, значит, возможно идет обращение к Thumb подпрограмме с адресом A0CE0810.

ИСКЛЮЧЕНИЯ

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

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

 	ARM поддерживает семь типов исключений. 

Тип					Режим			адрес		адрес резерв.

Сброс					supervisor		0x00000000	0xffff0000
Неизвестная инструкция		undefined		0x00000004	0xffff0004
Программное прерыв. (SWI)	supervisor		0x00000008	0xffff0008
Отказ считывания команды	Abort			0x0000000c	0xffff000c
Отказ доступа к данным		Abort			0x00000010	0xffff0010
Ошибка адреса (устарело)	Address Except.	0x00000014	0xffff0014
IRQ					Irq			0x00000018	0xffff0018
FIQ					Fiq			0x0000001C	0xffff001C
   
Исключение "ошибка адреса" - выход за пределы 26 разрядного адреса, в современных версиях процессоров не происходит. Поведение современных версий при переполнении счетчика команд в документации описывается как непредсказуемое (unpredictable).

 	При наступлении исключения процессор исполняет команды ARM, в регистр R14 заносятся адрес возврата, в SPSR состояние CPSR прерванной задачи. В биты CPSR [4:0] заносится код режима. Запрещается обычное прерывание, а если наступившее исключение - сброс или FIQ, запрещается  быстрое прерывание.

 	Для возврата из обработки необходимо скопировать SPSR_xxx в CPSR и R14_xxx в R15, где _xxx - соответствует банку исключения. 
  	Рекомендуемая последовательность команд для начала и завершения обработки исключения:
 	sub r14,r14,#4 ;сдвинуть указатель стека вниз
 	stmfd sp!, {<список_регистров>,r14}
 	...... обработка
 	ldmfd sp!,{ <список_регистров>,r15}^ 	

 	Модификатор '^' в данном  случае означает  восстановление регистра CPSR из SPSR.

Reversing:  Для реверсинга интересны фиксированные адреса  обработчиков исключений 

РЕЖИМЫ ПРОЦЕССОРА

ARM процессор 4-й версии и старше может находиться в одном из семи 'режимов процессора' 

РЕЖИМ 			ОПИСАНИЕ
------------------------------------------------------------------------- 
User 		usr	! Пользовательский. Стандартный режим исполнения программ
FIQ 		fiq 	! Поддержка высокоскоростной передачи данных или
 			! канальный процесс.
IRQ 		irq 	! Используется для обычной обработки прерываний.
Supervisor 	svc 	! Управляющий. Защищенный режим для операционной системы. 
Abort 	abt 	! Отказ. Применяется для виртуальной памяти и/или защиты 
 			! обычной памяти
Undefined 	und 	! Неопределенный. Поддержка программной эмуляции
 			! аппаратного сопроцессора. 
System 	sys 	! Исполнение привилегированных задач операционной системы.
----------------------------------------------------------------------- 
 	Изменение режимов может происходить под управлением программы, в результате внешних прерываний или при наступлении других исключительных ситуаций.  Большая часть программ выполняется в пользовательском режиме. В этом режиме программе недоступны некоторые защищенные ресурсы системы и невозможна смена режима, кроме как в случае наступления исключительной ситуации.
 	Остальные, кроме пользовательского, режимы известны как Привилегированные.
При этом все ресурсы доступны и возможна свободная смена режимов. Пять из привилегированных режимов известны как режимы обработки исключительной ситуации:

FIQ 
IRQ
Supervisor
Abort
Undefined

 	Переход в эти режимы происходит при наступлении исключительной ситуации (или, как чаще говорят для простоты - исключения). Каждому  из них доступно некоторое число дополнительных регистров, которыми пользуются при обработке исключения, чтобы предохранить от изменения состояние Пользовательского режима.
 	Оставшийся привилегированный режим- Системный, и он присутствует в процессорах 4-й и старше версий. Только в него попадают не в результате исключения и он имеет набор регистров совпадающий с пользовательским режимом. Тем не менее, это привилегированный режим и он не имеет ограничений пользовательского режима. Он используется для выполнения заданий операционной системы, которым должны быть доступны защищенные системные ресурсы. 

РЕГИСТРЫ

 	Всего ARM процессор имеет 37 регистров шириной 32 разряда, из них тридцать один регистр называют регистрами общего назначения R0..R15. Еще 6 регистров являются регистрами состояния CPSR и  SPSR. Они также 32 разрядные, но используется в них только по 12 бит.
 	Регистры объединяются в семь частично перекрывающихся банков регистров. Каждый банк соответствует одному из семи режимов процессора.

------------------------- режимы ----------------------------------------
User System Superv.    Abort		Undef.	Interr. 	Fast Interr.
--------------------- банки регистров ------------------------------------
 R0	R0	R0		R0		R0		R0		R0
 R1	R1	R1		R1 		R1		R1		R1
 R2	R2	R2		R2 		R2		R2		R2
 R3	R3	R3		R3 		R3		R3		R3
 R4	R4	R4		R4 		R4		R4		R4
 R5	R5	R5		R5 		R5		R5		R5
 R6	R6	R6		R6 		R6		R6		R6
 R7	R7	R7		R7 		R7		R7		R7
 R8	R8	R8		R8		R8		R8		R8_fiq
 R9	R9	R9		R9		R9		R9		R9_fiq
 R10	R10	R10		R10		R10		R10		R10_fiq
 R11	R11	R11		R11		R11		R11		R11_fiq
 R12	R12	R12		R12		R12		R12		R12_fiq
 R13	R13	R13_svc	R13_abt	R13_und	R13_irq	R13_fiq
 R14	R14	R14_svc 	R14_abt	R14_und	R14_irq	R14_fiq
 R15	R15	R15		R15		R15		R15		R15
CPSR	CPSR	CPSR		CPSR		CPSR		CPSR		CPSR		
		SPSR_sv	SPSR_abt	SPSR_un	SPSR_ir	SPSR_fiq
	
 	Как видно из таблицы, регистры пользовательского и системного режимов полностью совпадают. 
 	Регистры R0..R12, R15(PC), CPSR (состояния) общие для всех режимов, за исключением  FIQ. 
 	В режимах обработки исключений есть дополнительное, для каждого режима отдельное, так называемое 'сохраненное слово состояния процессора' SPSP и свои регистры R13(SP) R14(LR). 
 	В режиме FIQ ввели дополнительно свой независимый набор регистров R8..R12. Это позволяет приступить к обработке быстрого прерывания сразу, не заботясь о сохранении контекста  прерванной задачи, используя только 'свои' регистры и быстро вернуть управление после завершения обработки.

Регистры общего назначения, используемые особым образом
R13, R14, R15

Несмотря на то, что они могут участвовать как обычные регистры в операциях, почему их и включают в число регистров общего назначения, их специализация обязательно должна учитываться при написании программ. Особенно это относится к регистру R15 (PC). 
 Регистр R13 (SP)
обычно используется в качестве указателя стека (SP). В ARM режиме нет команд, использующих этот регистр особым образом, в наборе Thumb такие команды есть – push и pop. Свой R13 есть в каждом  из банков соответствующих обработке исключений. 

Регистр R14 (LR).   
известен как регистр связывания Link registr (LR) и в двух случаях используется особым образом: 

 	Первый случай. В любом режиме процессора ассоциированный с ним экземпляр регистра R14 используется для сохранения адреса возврата из подпрограммы. Когда подпрограмма вызывается командами BL или BLX, в R14 заносится адрес следующей команды, то есть адрес возврата. Возврат производится копированием R14 в R15 (PC). Это достигается одним из двух стандартных способов:
 	- Исполнением для возврата команд подобных: 
 		MOV R15,R14 (синоним - RET)
		BX LR
 	которые копируют значение регистра R14 в R15 

 	- Или, при входе в подпрограмму можно сохранить R14 вместе с другими регистрами в стек такой командой:
 		STMFD SP!,{<сохраняемые регистры>,LR}
и восстановить сохраненное из R14 значение в R15, используя соответствующую команду при возврате:
 		LDMFD SP!,{<восстанавливаемые регистры>,PC} 

Еще один способ организации подпрограмм:
 		STR  LR, [SP,#-4]! ;сохранить LR в стек
 … 
 		LDR  PC, [SP],#4   ;восстановить из стека в PC 

	Второй случай специального использования R14. Когда происходит исключение, в связанном с режимом исключения экземпляре R14 устанавливается адрес возврата из обработки исключения (для некоторых исключений, сдвинутый на небольшую величину). 
Для корректного возврата из обработки исключения кроме восстановления адреса требуется выполнение некоторого числа операций полного восстановления состояния той программы,  которая исполнялась в момент возникновения исключения.
 	------Замечание:------
 	Если возможны вложенные исключения, специальные применения LR могут конфликтовать. К примеру, мы обрабатываем прерывания и находимся в IRQ режиме. Если при этом разрешить прерывания и будет получено вложенное прерывание, значение хранимое в R14 будет переписано новым адресом. Системный программист должен внимательно следить за тем, чтобы R14 не содержал незаменимых данных, когда разрешаются вложенные исключения. 	
	--------------------------
Регистр R15 (PC)
используется в ARM архитектуре в качестве счетчика команд. 
 	При записи в него нового значения, происходит переход по адресу равному этому значению. 
Для версий архитектуры, поддерживающих Thumb (T вариант) нулевой разряд адреса игнорируется и всегда записывается нулем. Этот бит используется, как уже было описано выше, для смены набора команд специальными командами.
 	Если подразумевается переход на инструкцию ARM режима, все команды которого хранятся по адресам кратным 4, два самых младших разряда адреса должны быть 0, иначе результат непредсказуем. 
 	При чтении регистра R15 в ARM режиме, в регистр результата попадает значение, равное: адресу команды чтения + 8. 

thisAddr: 	MOV R1,R15	; R1:= R15+8 (thisAddr+8)

 	Исключением из этого правила является сохранение R15 командами STR или STM. Они могут сохранять значение R15 как со смещением 8 подобно остальным инструкциям, либо со смещением 12. 
 	При чтении регистра R15 в Thumb режиме, в регистр результата попадает значение, равное: адресу команды чтения + 4. 

Регистры состояния 	
Регистр состояния текущей программы CPSR
В любых режимах процессора используется один и тот же CPSR. Он содержит флаги результата исполнения команд, биты запрета прерывания, текущий режим процессора и другую управляющую информацию, и информацию состояния.

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

Назначение разрядов регистров состояния:

31  30  29  28  27  !   26 ... 8 !  7   6   5 !  4...0 	
----------------------------------------------------------
N   Z   C   V   Q   !   DNM(RAZ) !  I   F   T !  M[4:0]
----------------------------------------------------------

N - Negative  Z - Zero  C - Carry V - oVerflow
- биты, известные, как флаги результата исполнения команд, или просто флаги. 

	Флаги из CPSR могут проверяться перед исполнением некоторых команд и определять будет ли исполнятся эта команда, то есть служат для организации условного исполнения программ (об этом более подробно позже).
 	Флаги изменяют состояние при:
 - Исполнении команд сравнения CMN, CMP, TEQ, TST - в любом случае.
 - Исполнении арифметических, логических команд и команд копирования, у которых регистр назначения не R15, если применена специальная форма команды 
(см. {S} модификатор).  
назначение флагов N Z C V 
Они устанавливаются в единицу в следующих случаях:

N - negative, если 31 (старший, знаковый) разряд в результате выполнения операции равен 1, то есть результат - отрицательное число.

Z - zero, если результат операции равен 0, или как признак 'равно' при операции сравнения

С - carry, перенос, изменяется в следующих случаях:
 	1. если операции сложения, включая операцию сравнения CMN дает переполнение результата (результат больше 0xFFFFFFFF) C:= 1, иначе 0.
 	2. если операция вычитания, включая операцию сравнения CMP, дают 'заем' -  то есть вычитаемое число больше уменьшаемого и разность отрицательна, 'C' устанавливается в 0, иначе в 1.   (Именно так, в 0 при займе, в 1 если его нет!).
 	3. при операциях сдвига C устанавливается в значение последнего бита, выдвинутого за пределы сдвигаемого регистра. 

V - overflow, меняет значение в 1 если в результате операций сложения/вычитания происходит переполнение, в то время когда операнды и результат являются целым со знаком в форме 'дополнение до двух'.
Флаги также могут быть изменены также другими способами:
 - исполнением команды MSR, которая записывает новое значение в CPSR или SPSR
 - исполнением MRC, когда целевым регистром является R15. Эта инструкция дополнительно переносит флаги результатов команд из сопроцессора в ARM  процессор.
 - Исполнение некоторых вариантов команды LDM. Эти варианты копируют SPSR в  CPSR и в основном используются для возврата из обработки исключения.
Q флаг. 
 	В варианте ARM 5 E архитектуры и более старших, бит[27] CPSR известен как Q флаг, используемый для индикации различных переполнений операций DSP.
В 9E версии процессора также используется в SATURATED формах команд обработки данных, к примеру, QADD, QDADD и т д.
I, F, T и M[4:0]
 	Младшие 8 разрядов регистров статуса , включающие I, F, T и M[4:0], вместе называются контрольными битами. Программный доступ к ним возможен только при нахождении процессора в привилегированном режиме.
 
I = 1 запрещает прерывания
F = 1 запрещает быстрые прерывания

T бит должен быть 0 в Thumb несовместимых версиях процессора. 

В 'T' вариантах процессора: 

T = 0 процессор находится в режиме исполнения ARM команд
T = 1 процессор находится в режиме исполнения Thumb команд
Биты режима процессора M[4:0]:

 значение   режим 
------------------------
0b10000 user 
0b10001 FIQ
0b10010 IRQ
0b10011 supervisor
0b10111 Abort
0b11011 Undefined
0b11111 System

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

Как заставить команду изменять флаги. {S} модификатор.

	Большинство из команд имеют как стандартную форму, сохраняющую значения флагов, так и форму, изменяющую значение флагов в зависимости от результата операции, получаемую добавлением S к мнемонике команды. 

Пример:
...
	MOV R0, #0; флаг Z не изменится, форма команды простая
	MOV R0, #1; флаг Z не изменится, форма команды простая
	MOVS R0,#0; флаг Z := 1, форма команды с S
	MOVS R0,#1; флаг Z := 0, форма команды с S
...
Замечание: Если вы хотите, чтобы  логические и арифметические операции изменяли значения флагов результата,  к ним необходимо применять специальный модификатор. Это отличает язык ассемблера ARM от большинства других, где флаги изменяются “по умолчанию”.

Как использовать флаги. Модификаторы проверки условий <cond>

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

Пример:
 	SUBS	R0, R0, #1; Уменьшить R0 на 1, установить флаги по результату 
 	ADDEQ	R1, R1, #1; Если предыдущей командой флаг Z установлен в 1, увеличить R1 на 1 

 	Эти модификаторы изменяют старшие биты [31:28] кода команды, значение  в которых должно соответствовать состоянию флагов в момент исполнения. 
	Есть одно особое состояние этих бит, когда все они равны 1 (0b1111). В этом случае их действие зависит от версии процессора. В версиях до 3 это соответствует тому, что команда никогда не исполняется. В 3 и 4 версиях это значение неприменимо. Начиная с 5 версии, такое значение соответствует различным дополнительным командам,  исполнение которых уже не может зависеть от состояния флагов.  
 	Еще одно важное значение 0b1110 - Always, исполнение команды в любом случае, независимо от состояния флагов.

Биты	Модификатор	Условие					Значение флагов

0000	EQ		Равно						Z = 1
0001	NE		Не равно					Z = 0
0010	CS/HS		перенос/беззнак больше или равно	C = 1
0011	CC/LO		Нет переноса/беззнаковое меньше	C = 0
0100	MI		Минус/отрицательное			N = 1
0101	PL		Плюс/положительное или нуль		N = 0
0110	VS		Переполнение				V = 1
0111	VC		Нет переполнения				V = 0
1000	HI		Беззнаковое больше			C = 1 Z = 0
1001	LS		Беззнаковое меньше или равно		C = 0 Z = 1
1010	GE		Больше или равно, со знаком		N  = V
1011	LT		Меньше чем, со знаком			N != V
1100	GT		Больше чем, со знаком			Z=0 N=V	
1101	LE		Меньше или равно, со знаком		Z=1 or N!=V
1110	AL		Безусловное выполнение
1111			---Зависит от версии процессора---

Reversing: 	Мы уже упоминали, что большинство команд набора ARM не проверяют условий и  начинаются с байта 'E*' (Always)  и выравнены по адресам, кратным четырем, что визуально облегчает их опознание.

Вычисляемые операнды, методы адресации данных ARM набора.

Для изучения команд ARM набора надо понимать такие базовые понятия, как: 
- правила вычисления значения непосредственных операндов <immediate>, которые хранится внутри кода команды.
- правила вычисления универсальных операндов <shifter_operand>, к которым может применятся операция сдвига.
-  а также различные способы  вычисления адреса для операций с памятью. 
Непосредственный операнд <immediate>

 	Первое понятие, встречающееся в командах ARM набора,  так называемый, непосредственный  операнд: 

 	#<immediate>

 	Это число, хранящееся внутри кода команды, в виде 8 разрядного базового значения и 4 разрядной величины сдвига. 
 	Значение непосредственного операнда вычисляется так: берется упомянутое 8 разрядное число (от 0x00 до 0xff), и оно циклически (по кольцу) сдвигается на некоторое четное количество разрядов (0,2,4...30) внутри 32 разрядного регистра. Величина сдвига получается умножением 4-х разрядного значения  на 2 и может быть нулевой. Остальные двадцать четыре разряда, за пределами сдвинутых в новое положение восьми разрядов исходного числа, заполняются нулями.
 	Конечно, в виде  непосредственного операнда  можно представить далеко не всякое 32 разрядное число. 
  	К примеру, возьмем как исходный байт число 0xFF.  Сдвигая, производным от него можно получить:

 сдвиг, разрядов 	получившееся значение
 	0	 		0xff
  	на 2			0x3fc
 	на 4			0xff0
  	на 6			0x3fc0
  	на 8			0xff00
  	на 10			0x3fc00
  	на 12			0xff000
и так далее, до 0xff000000 и даже, сдвинув еще больше по кольцу,0xFC000003, 0xF000000F, 0xC000003F -соответственно, все это допустимые значения для того, чтобы представить их как непосредственный операнд. А числа 0x1ff,  0x4fc или 0x100203 получить сдвигом восьмиразрядного числа нельзя.
 	
 	Еще раз обратим внимание, сдвиг на четное число разрядов. К примеру, значение 0x1fe, полученное сдвигом 0xFF на 1, в виде непосредственного операнда также представлено быть  не может.
 	В качестве базового для сдвига, как уже говорилось, можно взять любое число от 0 до 0xFF.
 	Напомним, все, что здесь сказано, относится к ARM режиму. 

Универсальный операнд <shifter_operand> 
В документации на KEIL его называют Flexible Operand или Op2

<shifter_operand> бывает трех видов:

#<immediate>	- непосредственный операнд
<Rn> 			- регистровый операнд
<Rn>,  ShiftMode,  Shift - регистровый операнд со сдвигом

 	Значение такого операнда (регистрового со сдвигом) вычисляется следующим образом:
В качестве исходного берется содержимое регистра общего назначения <Rn> , затем к нему применяется один из пяти типов сдвигов. Величина сдвига может быть указана либо непосредственно в команде, либо как ссылка на другой регистр общего назначения.
Пять типов сдвига 

Здесь будут описаны действия, соответствующие сдвигу конкретного типа на один разряд. Последовательно сдвигая по этим правилам несколько раз, можно получить  сдвиги на любую требуемую величину от 1 до 32 разрядов для всех типов, кроме RRX, для которого применим сдвиг только на один разряд, и для которого величина сдвига в команде не указывается.
Процессор выполняет сдвиг сразу на необходимое число разрядов, но результат, естественно, совпадает с тем, который был бы при последовательном сдвиге.      
LSL 
 - логический сдвиг 32 разрядного числа влево, в младший разряд помещается 0, старший разряд, выдвигаясь за пределы регистра, теряется, но его значение сохраняется в флаге C.

LSR  
- логический сдвиг 32 разрядного числа вправо, в старший разряд помещается 0, младший разряд, выдвигаясь за пределы регистра, теряется, но его значение сохраняется в флаге C.

ASR  
- арифметический сдвиг 32 разрядного числа вправо, старший разряд устанавливаются в значение знакового разряда (31 бита) исходного числа (1 для отрицательного, 0 для положительного), младший разряд, выдвигаясь за пределы регистра, теряется, но его значение сохраняется в флаге C.

ROR 
- циклический сдвиг 32 разрядного числа вправо 'по кольцу', в старший разряд помещается значение, выдвинутое из младшего, одновременно значение младшего разряда в флаге C.

RRX 
- циклический правый сдвиг через флаг ‘C’, сдвиг вправо 'по кольцу' в псевдо 33 разрядном регистре, образованном 32 разрядным регистром и значением флага C в качестве 33-го разряда. В старший разряд помещается значение из флага C, в флаге С сохраняется значение младшего разряда.

Одиннадцать форм <shifter_operand>:

Полный список возможных видов этого типа операндов
  #<immediate> 
- этот вид мы уже рассматривали. 
 <Rn>  
Значение, хранимое в 32 разрядном регистре R0-R15.
 <Rn>, LSL #shift
 - значение, полученное LSL сдвигом хранимого в Rn числа на #shift разрядов.
 <Rn>, LSL <Rm>
- значение, полученное LSL сдвигом хранимого в Rn числа на число разрядов указанных в Rm.
 <Rn>, LSR #shift 
- значение, полученное LSR сдвигом хранимого в Rn числа на #shift разрядов.
 <Rn>, LSR <Rm>
- значение, полученное LSR сдвигом хранимого в Rn числа на число разрядов указанных в Rm.
 <Rn>, ASR #shift
 - значение, полученное ASR сдвигом хранимого в Rn числа на #shift разрядов.
 <Rn>,ASR <Rm>
- значение, полученное ASR сдвигом хранимого в Rn числа на число разрядов указанных в Rm.
 <Rn>, ROR #shift
 - значение, полученное ROR сдвигом хранимого в Rn числа на #shift разрядов.
 <Rn>, ROR <Rm>
- значение, полученное ROR сдвигом хранимого в Rn числа на число разрядов указанных в Rm.
 <Rn>, RRX 
- сдвиг на 1 разряд по правилам RRX.

Примеры команд, использующих  <shifter_operand>:

	mov    r2,   #0x0	         	; #0
	mov    r2,   r3		   	; r3
	mov    r2,   r3,lsl #0x15 	; r3, lsl #0x15
	mov    r2,   r3,lsl r4	   	; r3, lsl r4
	mov    r2,   r3,lsr #0xC   	; r3, lsr #0xC
	mov    r2,   r3,lsr r4	   	; r3, lsr r4
	mov    r2,   r3,asr #0	   	; r3, asr #0
	mov    r2,   r3,asr r4	   	; r3, asr r4
	mov    r2,   r3,ror #0x12   	; r3, ror #0x12
	mov    r2,   r3,ror r4	   	; r3, ror r4
	mov    r2,   r3,rrx	   	; r3, rrx 

Режимы адресации  <addressing_mode>
Адресация для загрузки и сохранения слова или байта без знака <addressing_mode 1>
команды LDR STR LDRB STRB LDRT STRT LDRBT STRBT

Команды LDR и STR загрузки или сохранения word/byte формируются по следующей схеме:

 	LDR | STR {<cond>}{B}{T}    <Rd>, <addressing_mode 1>

Где:

<cond>  - модификаторы проверки условий, описаны выше. 
{B} - модификатор загрузки байта. При его наличии младшие 8 разрядов регистра загружается значения адресуемого байта памяти. Старшие 24 разряда заполняются нулями. При записи в память модифицируется значение только адресуемого байта. 

{T} - модификатор доступа к памяти в непривилегированном режиме (User mode). Если такого модификатора нет, доступ идет с привилегиями текущего режима процессора.  Для команд с таким модификатором допустимы только режимы с постиндексацией (последние три режима адресации).

<addressing_mode 1>
[<Rn>]
 -Адрес операнда хранится в регистре.
	ldr r3, [r2]; в r3 загрузить слово хранимое по адресу r2 

[<Rn>, # -/+<offset_12>]
 - адрес операнда вычисляется сложением или вычитанием значения в базовом регистре Rn и 12 разрядного непосредственного смещения. Знак хранится в отдельном бите ‘U’ кода команды, поэтому смещение занимает полные 12 разрядов 
(0 ... 0xFFF ).
	str r3, [r2, # -0xFE8] ; r3 сохранить по адресу (r2-0xFE8)

[<Rn>, # -/+<offset_12>]!
  - Прединдексация. Операция совпадает с предыдущей, но добавленный в конце восклицательный знак означает, что вычисленное значение адреса заносится в Rn.
	ldr r3, [r2, # 0x30]! ] ; r3 сохранить по адресу (r2+0x30), r2 := (r2+0x30)

[<Rn>, +/- <Rm>]
 - адрес операнда хранится в регистре Rn, смещение в Rm. Адрес операнда получается сложением или вычитанием Rn и Rm.
	str r1,[r2,- r0] 	

[<Rn>, +/- <Rm>]!
 - Прединдексация. Операция совпадает с предыдущей, но восклицательный знак, добавленный в конце, заставляет изменять  Rn, туда заносится вычисленное значение адреса.
	ldr r4,[r5, r7]! 	

 [<Rn>, +/- <Rm>, <shift> #<shift_imm>]
 - адрес операнда хранится в регистре Rn, смещение в Rm, величина сдвига для Rm в shift_imm, тип сдвига в shift . Адрес операнда вычисляется так:
 addr := Rn +/- (Rm SHIFT shift_imm), то есть к Rm предварительно применяется операция сдвига.
Тип сдвигов <shift> - один из следующего ряда LSL LSR ASR ROR RRX, они были описаны ранее.
Допустимые величины сдвигов 1..32 для всех типов, кроме LSL ,  для LSL - 0..31. Для RRX величина сдвига не указывается, она всегда равна 1.
	ldr r3,[r2, -r3, lsr #5] 	

 [<Rn>, +/- <Rm>, <shift> #<shift_imm>]!
 - Прединдексация. Операция совпадает с предыдущей, но восклицательный знак, добавленный в конце, заставляет изменять  Rn, туда заносится вычисленное значение адреса.
	ldr r0,[r2, -r3, lsl #7]! 	
[<Rn>],  # -/+<offset_12> 
 - Постиндексация. В качестве адреса доступа к памяти берется значение Rn, после чего Rn изменяется, туда заносится значение полученное сложением или вычитанием Rn и 12 разрядного непосредственного смещения
	str r5,[r3], #44
[<Rn>], +/- <Rm>
 - Постиндексация. В качестве адреса доступа к памяти берется значение Rn, после чего Rn изменяется, туда заносится значение полученное сложением или вычитанием Rn и Rm.
	ldr r1,[r7], -r2
[<Rn>], +/- <Rm>, <shift> #<shift_imm>
 - Постиндексация. Адрес операнда хранится в регистре Rn, смещение в Rm, величина сдвига Rm в shift_imm, тип сдвига в shift . В качестве адреса доступа к памяти берется значение Rn, после чего  Rn изменяется. Новый базовый адрес Rn  вычисляется так:
 addr := Rn +/- (Rm SHIFT shift_imm), то есть к Rm предварительно применяется операция сдвига.
Тип сдвигов <shift> - один из следующего ряда LSL LSR ASR ROR RRX, они были описаны ранее.
Допустимые величины сдвигов 1..32 для всех типов, кроме LSL ,  для LSL - 0..31. Для RRX величина сдвига не указывается, она всегда равна 1.
	ldr r3,[r2], r5, ror #22

Адресация для дополнительных команд загрузки и сохранения  <addressing_mode 2>
команды LDRD STRD LDRH STRH LDRSH LDRSB
[<Rn>]
 -Адрес операнда хранится в регистре.
	ldrh r3, [r2]; в r3 загрузить слово хранимое по адресу r2 
[<Rn>, # -/+<offset_8>]
 - адрес операнда вычисляется сложением или вычитанием значения в базовом регистре Rn и 8 разрядного непосредственного смещения. Знак хранится в отдельном бите U кода команды, поэтому смещение занимает полные 8 разрядов (0 ... 0xFF ).
	strh r3, [r2, # -0xE8] ; r3 сохранить по адресу (r2-0xe8)
[<Rn>, # -/+<offset_8>]!
  - Прединдексация. Операция совпадает с предыдущей, но восклицательный знак, добавленный в конце, заставляет, заносить вычисленное значение адреса в Rn.
	strd r3, [r2, # 0x30]! ;
[<Rn>, +/- <Rm>]
 - адрес операнда хранится в регистре Rn, смещение в Rm. Адрес операнда получается сложением или вычитанием Rn и Rm.
	ldrsb r1,[r2,- r0]; 	
[<Rn>, +/- <Rm>]!
 - Прединдексация. Операция совпадает с предыдущей, но восклицательный знак, добавленный в конце, заставляет изменять  Rn, туда заносится вычисленное значение адреса.
	ldrd r4,[r5, r7]! 	
[<Rn>],  # -/+<offset_8> 
 - Постиндексация. В качестве адреса доступа к памяти берется значение Rn, после чего Rn изменяется , туда заносится значение полученное сложением или вычитанием Rn и 8 разрядного непосредственного смещения
	strh r5,[r3], #44
[<Rn>], +/- <Rm>
 - Постиндексация. В качестве адреса доступа к памяти берется значение Rn, после чего Rn изменяется , туда заносится значение полученное сложением или вычитанием Rn и Rm.
	ldrsh r1,[r7], -r2

Адресация для мультирегисторной загрузки и сохранения  <addressing_mode 3>
Команды STM LDM

Команда STM сохраняет  любое число регистров общего назначения в памяти (возможно, все), а команда LDM загружает их.  Режимы адресации таких команд генерируют последовательные адреса. Регистры с наименьшим номером сохраняются по младшим адресам, а регистры с наибольшими номерами, соответственно,  по старшим. В коде команды младшие шестнадцать разрядов соответствуют шестнадцати регистрам общего назначения. Бит[0] соответствует R0, бит[15] регистру R15.  Если какой-либо бит установлен в единицу, соответствующий регистр участвует в операции.  

LDM | STM {<cond>} <addressing_mode>   <Rn>{!},   <registers> {^}

<cond> 		условия выполнения

<addressing_mode> одно из IB, FA, IA, EA, DB,  FD,  DA,  ED - способ адресации

<Rn> 			регистр, в котором находится базовый адрес (базовый регистр)

{!} 			Признак постфиксной модификации базового регистра. Если присутствует, то значение Rn в конце операции увеличивается или уменьшается  на величину (количество_регистров_в_операции * 4).  

<registers>  	Список регистров, задается в виде помещенного между '{'  и '}' разделенного запятыми или дефисом списка регистров в порядке возрастания. Форма SP LR PC для специальных регистров также допускается.   

Пример:  	{R1-R5, R7, R9-R11, SP,LR,PC}; список из регистров с номерами 1,2,3,4,5,7,9,10,11,13,14,15

{^}			Если в списке регистров загружаемых  командой LDM нет регистра PC, этот модификатор указывает, что надо восстанавливать регистры банка пользовательского режима  (текущий режим процессора может быть другим, со своим банком регистров). 
 	Если в списке регистров команды LDM есть регистр PC, то этот модификатор означает восстановление в конце операции регистра CPSR из SPSR текущего банка. 
 	Для команды STM этот модификатор означает, что сохранять надо регистры пользовательского режима.

Типы  < addressing_mode 3>:
IA
 (increment after). В качестве первого адреса берется значение из базового регистра Rn. Последующие адреса получаются увеличением предыдущего на  четыре. Таким образом формируются адреса для всех загружаемых или сохраняемых регистров. 
IB
(increment before). В качестве первого адреса берется значение Rn+4. Последующие адреса получаются увеличением предыдущего на  четыре. 
DA
(decrement after). В качестве первого адреса берется значение из базового регистра Rn. Последующие адреса получаются уменьшением предыдущего на  четыре. 
DB
(decrement before). В качестве первого адреса берется значение Rn-4. Последующие адреса получаются уменьшением предыдущего на  четыре. 
Стек.  Адресация FA FD EA ED

 	Если в качестве базового операнда используется регистр R13, используемый как  указатель стека SP, то признаки  <addressing_mode 3> для удобства понимания могут быть заменены синонимами FA FD EA ED , указывающими тип стека. 

По какому принципу они выбираются. 
 	Если считается, что стек растет вниз, то есть при сохранении в стек указатель стека автоматически уменьшается, а при извлечении из него – увеличивается, тогда такой стек обозначают как Descending, модификатор D. 
 	Если полагают, что адресуемая указателем стека ячейка памяти занята и перед началом операции сохранения требуется сдвинуть указатель, такое поведение описывается модификатором F - Full. При считывании из F стека, соответственно предварительного сдвига не требуется, сначала необходимо взять значение, только затем изменить указатель.

Иное поведение стека описывается следующими модификаторами:
E - Empty. Ячейка памяти при сохранении считается пустой, сдвиг не нужен. Перед  чтением необходим сдвиг.
A - Ascending. Применяется для стека, растущего вверх, который увеличивается при сохранении.

Из вышесказанного следует, что:
При сохранении:
FD = DB
ED = DA
EA = IA
FA = IB

При извлечении из стека:
FA = DA
FD = IA
EA = DB
ED = IB

В прошивке применяется FD тип стека.

Попробуем разобрать такую команду:

ldmeqib r0!,{r1,r3-r7,r9,r12,sp,lr};
LDM 	загрузить несколько регистров 
EQ 	команду выполнять, если Z=1
IB 	адреса, откуда загружать, увеличивать последовательно  на 4(increment), включая адрес для первого регистра (before)
R0	базовый адрес находится в R0
! 	R0 в конце операции присвоить значение R0+(4*10)
{R1,R3,R4,R5,R6,R7,R9,R12,R13,R14} какие 10 регистров загружать

Адресация операций загрузки или сохранения регистров сопроцессора <addressing_mode C>
Команды LDC STC 

LDC{<cond>}{L}   <coproc>,<CRd>,<addressing_mode C>

{L} - long load. 
<coproc> - имя сопроцессора (p0...p15)

<addressing_mode C> 
[<Rn>, #+/-<offset_8>*4]
Непосредственное смещение.
Этот режим адресации вызывает упорядоченную последовательность адресов. Первый адрес вычисляется прибавлением (или вычитанием) учетверенного значения смещения к значению регистра <Rn>. Последовательность следующих адресов формируется увеличением предыдущего на четыре. Это продолжается, пока  сопроцессор не просигнализирует об окончании операции, что позволяет сопроцессору получить доступ к данным, размер которых определяется им. Сопроцессор не может требовать переноса более чем 16 слов. 
[<Rn>, #+/-<offset_8>*4]!
Непосредственное смещение с прединдексацией.
Этот режим адресации вызывает упорядоченную последовательность адресов. Первый адрес вычисляется прибавлением (или вычитанием) учетверенного значения смещения к значению регистра <Rn>. Если поле условия в команде соответствует коду состояния, то первый вычисленный  адрес записывается в <Rn>. Последовательность следующих адресов формируется увеличением предыдущего на четыре. Это продолжается, пока  сопроцессор не просигнализирует об окончании операции, что позволяет сопроцессору получить доступ к данным, размер которых определяется им. Сопроцессор не может требовать переноса более чем 16 слов. 

[<Rn>],  #+/-<offset_8>*4
Непосредственное смещение с постиндексацией.
Этот режим адресации вызывает упорядоченную последовательность адресов. Первый адрес равен значению базового регистра [Rn]. Последовательность следующих адресов формируется увеличением предыдущего на четыре. Это продолжается, пока  сопроцессор не просигнализирует об окончании операции, что позволяет сопроцессору получить доступ к данным, размер которых определяется им. Сопроцессор не может требовать переноса более чем 16 слов. 
Если поле условия в команде соответствует коду состояния, то новое значение <Rn>  вычисляется прибавлением (или вычитанием) учетверенного значения смещения к значению регистра <Rn>.
[<Rn>],  <option>
Адресация без индексирования.
Этот режим адресации вызывает упорядоченную последовательность адресов. Первый адрес равен значению базового регистра [Rn].   Последовательность следующих адресов формируется увеличением предыдущего на четыре Это продолжается, пока  сопроцессор не просигнализирует об окончании операции, что позволяет сопроцессору получить доступ к данным, размер которых определяется им. Сопроцессор не может требовать переноса более чем 16 слов. 
Содержимое [Rn] не изменяется 
<option> - указывает дополнительные опции инструкции сопроцессора. Определяется синтаксисом инструкции как целое в диапазоне 0-255 окруженное { и }.

Команды ARM режима

Обозначения:
< > - в таких скобках указываются изменяемые части команды - модификаторы или операнды. 
<cond> 	- модификатор условия выполнения
S 		- модификатор установки флагов
<Rd> 		- регистр получатель результата
<Rn>,<Rm>	- регистр, содержащий операнд. 
<Op2> 	– синоним <shifter_operand>
SP 		- R13 указатель стека
PC 		- R15 счетчик команд
LR 		- R14 регистр связывания

Фигурные скобки означают возможное присутствие необязательных модификаторов.
ADC 
ADC{<cond>}{S}   <Rd>,<Rn>,<Op2> 
 	Rd := Rn + Op2 + C 
сумма с учетом переноса. 
S - разрешение установки флагов C Z N V по результату операции. Если <Rd> - R15, то S разрешает копировать SPSR в CPSR. Текущий режим процессора в этом случае должен иметь SPSR, иначе результат непредсказуем!
ADD 
ADD{<cond>}{S}   <Rd>,<Rn>,<Op2> 
 	Rd := Rn + Op2 
Сумма. 
S - разрешение установки флагов C Z N V по результату операции. Если <Rd> - R15, то S разрешает копировать SPSR в CPSR. Текущий режим процессора в этом случае должен иметь SPSR, иначе результат непредсказуем!
AND 
AND{<cond>}{S}   <Rd>,<Rn>,<Op2> 
  	Rd := Rn AND Op2 
побитная операция AND.
Нулевой (младший) разряд результата равен 1, если равны 1 младшие разряды в обоих операндах, иначе равен 0. Первый разряд результата равен 1, если равны 1 первые разряды в обоих операндах ... и.т.д. 
S - разрешение установки флагов Z N по результату операции. Флаг C устанавливается в результате сдвига операнда <Op2>. Если <Rd> - R15, то S разрешает копировать SPSR в CPSR. Текущий режим процессора в этом случае должен иметь SPSR, иначе результат непредсказуем!
B 
B{<cond>}    <target_address> 
 	R15:= <target_address> 
Относительный переход по адресу <target_address> отстоящему от текущего  максимум на 32 Mбайта вверх или вниз. Поле адреса в команде 24 разряда, значение умножается на 2, так и получается + - 32М адресов.
BL 
BL{<cond>}    <target_address> 
 	R14:=  R15 + 4; адрес следующей команды для возврата 
 	R15:= <target_address>;
Вызов подпрограммы по относительному адресу <target_address> отстоящему от текущего  максимум на 32 Mбайта вверх или вниз. В R14 заносится адрес следующей за BL команды (адрес возврата).

BIC
BIC{<cond>}{S}   <Rd>,<Rn>,<Op2>
 	Rd := Rn AND (NOT Op2) 
Очистка бит. 
Обнуление бит в тех позициях, в которых  присутствует 1 в  Op2 .
S - разрешение установки флагов Z N по результату операции. Флаг C устанавливается в результате сдвига операнда <Op2>. Если <Rd> - R15, то S разрешает копировать SPSR в CPSR. Текущий режим процессора в этом случае должен иметь SPSR, иначе результат непредсказуем!
BKPT 
BKPT <16bitDebugInfo>
Вызов отладочного прерывания.
в отладчик передается любое 16 битное число указанное в качестве операнда, как информация о месте прерывания. Тип вызываемого  исключения - Prefeth Abort
BLX   
BLX   <target_address> 	R14:=  R15 + 4; адрес следующей команды для возврата 
 	R15:= <target_address>;
Вызов подпрограммы с возможной сменой набора команд.
Первая форма. Вызов подпрограммы по относительному адресу <target_address> на, примерно 32 мегабайта вверх или вниз. В R14 заносится адрес возврата. Используется для вызова подпрограммы Thumb, если младший бит адреса равен 1.  
BLX   
BLX{<cond>}   <Rm> 
 	R14:= R15 + 4; адрес следующей команды для возврата 
 	R15:= Rm;
Вызов подпрограммы с возможной сменой набора команд.
Вторая форма. Вызов подпрограммы по абсолютному адресу Rm.  В R14 заносится адрес возврата. Используется для вызова подпрограммы Thumb  режима при 1 в младшем бите адреса. 
BX 
BX{<cond>}   <Rm> 
 	R15:= Rm
Переход по абсолютному адресу Rm с возможной сменой набора команд.
Используется для перехода на коды Thumb  режима при 1 в младшем бите адреса. 
CDP
CDP{<cond>}   <coproc>, <opcode_1>,<CRd>,<CRn>,<CRm>,<opcode_2>
Выполнение инструкции сопроцессора
<coproc> - имя сопроцессора (p0...p15)
<opcode_1> - указывает какую инструкцию исполнять сопроцессору
<CRd> - регистр сопроцессора, получатель результата
<CRn> - регистр сопроцессора, первый операнд
<CRm> - регистр сопроцессора, второй операнд
<opcode_2>- указывает какую инструкцию исполнять сопроцессору (второе поле)
CDP (форма 2)
CDP     <coproc>, <opcode_1>,<CRd>,<CRn>,<CRm>,<opcode_2>
Выполнение инструкции сопроцессора
<coproc> - имя сопроцессора (p0...p15)
<opcode_1> - указывает какую инструкцию исполнять сопроцессору
<CRd> - регистр сопроцессора, получатель результата
<CRn> - регистр сопроцессора, первый операнд
<CRm> - регистр сопроцессора, второй операнд
<opcode_2>- указывает какую инструкцию исполнять сопроцессору (второе поле)
В этой форме под коды инструкций выделяются дополнительные разряды.

CLZ 
CLZ{<cond>}   <Rd>,<Rn> (только ARM9E)
В Rd возвращается число ведущих двоичных нулей числа в Rn.
Пример: Если в Rn число 0x00800000, в Rd вернется 8.
CMN   
CMN{<cond>}   <Rn>, <Op2> 
Сравнение со сменой знака. 
Флаги N Z C V устанавливаются в результате операции Rn + Op2, результат операции нигде не сохраняется. К примеру, 0xFFFFFFFF + 1 = 0, с переполнением, будут установлены в 1 флаги Z и C.
CMP   
CMP{<cond>}   <Rn>, <Op2> 
Сравнение. 
Флаги N Z C V устанавливаются в результате операции Rn - Op2, результат операции нигде не сохраняется. 
EOR 
EOR{<cond>}{S}   <Rd>,<Rn>,<Op2> 
 	Rd := Rn XOR Op2 
Исключающее ИЛИ. 
Единица  будет установлена в тех двоичных разрядах  Rd, в которых у операндов несовпадающее значение. Операция более известна под именем XOR. 
S - разрешение установки флагов Z N по результату операции. Флаг C устанавливается в результате сдвига операнда <Op2>. Если <Rd> - R15, то S разрешает копировать SPSR в CPSR. Текущий режим процессора в этом случае должен иметь SPSR, иначе результат непредсказуем!
LDC
LDC{<cond>}{L}   <coproc>, <CRd>,<addressing_mode C>
Загрузка нескольких регистров сопроцессора из памяти.
{L} - long load. Удвоение точности данных
<coproc> - имя сопроцессора (p0...p15)
<CRd> - первый из загружаемых регистров сопроцессора
<addressing_mode> - метод вычисления адреса
Количество регистров определяется сопроцессором, но не более 16.
LDC2
LDC2{L}   <coproc>, <CRd>,<addressing_mode C>
Загрузка нескольких регистров сопроцессора из памяти.
{L} - long load. 
<coproc> - имя сопроцессора (p0...p15)
<CRd> - первый из загружаемых регистров сопроцессора
<addressing_mode> - метод вычисления адреса
Количество регистров определяется сопроцессором, но не более 16. Отличается отсутствием условия исполнения, что дает дополнительное место для опкодов сопроцессора.
LDM
LDM{<cond>}<addressing_mode 3>   <Rn>{!},   <registers> {^}
Загрузка нескольких регистров из памяти.
См. addressing_mode 3
LDR
LDR{<cond>}    <Rd>, <addressing_mode 1>
 	Rd := [address][31:0]
Загрузка 32 битного значения в регистр Rd из памяти.
<addressing_mode 1> - вычисляемый адрес.   

LDRB
LDRB{<cond>}    <Rd>, <addressing_mode 1>
 	Rd[31:8] := 0x000000
 	Rd[7:0]  := [address][7:0]
Загрузка байта из памяти с дополнением нулями в регистр Rd.
<addressing_mode> - вычисляемый адрес
LDRH
LDRH{<cond>}    <Rd>, <addressing_mode 2>
 	Rd[31:16] := 0x0000
 	Rd[15:0]  := [address][15:0]
Загрузка полуслова из памяти с дополнением нулями в регистр Rd 
<addressing_mode> - вычисляемый адрес
LDRSB
LDRSB{<cond>}    <Rd>, <addressing_mode 2>
	Rd[31:8] := 0xSSSSSS ; if ([address][7]== 1) S := F; else S: = 0;
 	Rd[7:0]  := [address][7:0]
Загрузка байта с расширением знака в регистр Rd из памяти
<addressing_mode> - вычисляемый адрес
Если загружаемое число отрицательное (старший разряд =1)  Rd[31:8] :=0xFFFFFF
Если загружаемое число положительно  (старший разряд =0)  Rd[31:8] :=0x000000
LDRSH
LDRSH{<cond>}    <Rd>, <addressing_mode 2>
	Rd[31:16] := 0xSSSS ; if ([address][15]== 1) S := F; else S: = 0;
 	Rd[15:0] := [address][15:0]
Загрузка полуслова с расширением знака в регистр Rd из памяти.
Если загружаемое число отрицательно (старший разряд =1)  Rd[31:16] :=0xFFFF
Если загружаемое число положительно (старший разряд =0)  Rd[31:16] :=0x0000
<addressing_mode 2> - вычисляемый адрес
LDRD
LDRD{<cond>}    <Rd>, <addressing_mode 2>
 	Rd   := [address][31:0] 
 	Rd+1 := [address+4][31:0] 
Загрузка пары регистров. 
Rd должен быть четным (R0 R2 R4 R6 R8 R10 R12)
<addressing_mode 2> - вычисляемый адрес
MCR
MCR{<cond>}   <coproc>,  <opcode1>, <Rd>, <CRn>, <CRm>{, <opcode_2>}
Выполнение копирования данных из процессора в сопроцессор
<coproc> - имя сопроцессора (p0...p15)
<opcode_1> - указывает какую инструкцию исполнять сопроцессору
<Rd> - регистр (R0-R14) процессора, источник данных 
<CRn> - регистр получатель сопроцессора
<CRm> - дополнительный регистр сопроцессора, получатель либо источник данных
<opcode_2>- указывает какую инструкцию исполнять сопроцессору (второе поле). Если в команде не указано, считается равным 0.
 	CRn := rRn {<op>cRm}

MCR2
MCR2   <coproc>,  <opcode1>, <Rd>, <CRn>, <CRm>{, <opcode_2>}
Выполнение копирования данных из процессора в сопроцессор. Вторая форма с большей разрядностью команд сопроцессора.
<coproc> - имя сопроцессора (p0...p15)
<opcode_1> - указывает какую инструкцию исполнять сопроцессору
<Rd> - регистр (R0-R14) процессора, источник данных 
<CRn> - регистр получатель сопроцессора
<CRm> - дополнительный регистр сопроцессора, получатель либо источник данных
<opcode_2>- указывает какую инструкцию исполнять сопроцессору (второе поле). Если в команде не указано, считается равным 0.
 	CRn := rRn {<op>cRm}
MCRR
MCRR{<cond>}    <coproc>,  <opcode>, <Rd>, <Rn>, <CRm>
Выполнение копирования данных из двух регистров процессора в сопроцессор. 
<coproc> - имя сопроцессора (p0...p15)
<opcode_1> - указывает какую инструкцию исполнять сопроцессору
<Rd> - регистр (R0-R14) процессора, первый источник данных 
<Rn> - регистр (R0-R14) процессора, второй источник данных 
<CRm> - регистр сопроцессора, получатель  данных

MLA
MLA{<cond>}{S}   <Rd>,<Rm>,<Rs> ,<Rn>
 	Rd := (Rm * Rs) + Rn 
Умножение с накоплением со знаком либо без знака. Результат 32 разрядный. 
S - разрешение установки флагов Z N по результату операции.
MOV
MOV{<cond>}{S}   <Rn>, <Op2>
 	Rd :=  Op2
Копирование значения в регистр
S - разрешение установки флагов Z N соответствует переносимому значению. Флаг C устанавливается в результате сдвига операнда <Op2>. Если <Rd> - R15, то S разрешает копировать SPSR в CPSR. Текущий режим процессора в этом случае должен иметь SPSR, иначе результат непредсказуем!
MRC
MCR{<cond>}   <coproc>,  <opcode1>, <Rd>, <CRn>, <CRm>{, <opcode_2>}
 	Rd:=cRn {<op>cRm}
Выполнение копирования данных из процессора в сопроцессор
<coproc> - имя сопроцессора (p0...p15)
<opcode_1> - указывает какую инструкцию исполнять сопроцессору
<Rd> - регистр процессора, получатель данных 
<CRn> - регистр сопроцессора содержащий первый операнд
<CRm> - дополнительный регистр сопроцессора, получатель либо источник данных
<opcode_2>- указывает какую инструкцию исполнять сопроцессору (второе поле). Если в команде не указано, считается равным 0.
MRC2
MCR2   <coproc>,  <opcode1>, <Rd>, <CRn>, <CRm>{, <opcode_2>}
См. MRC
Форма команды MRC без возможности проверки условия выполнения, с большей разрядностью опкодов сопроцессора.

MRRC
MRRC{<cond>}    <coproc>,  <opcode>, <Rd>, <Rn>, <CRm>
Выполнение копирования данных в два регистра процессора из сопроцессора. 
<coproc> - имя сопроцессора (p0...p15)
<opcode_1> - указывает какую инструкцию исполнять сопроцессору
<Rd> - регистр (R0-R14) процессора, первый получатель данных 
<Rn> - регистр (R0-R14) процессора, второй получатель данных 
<CRm> - регистр сопроцессора, источник  данных
MRS
MRS{<cond>}   <Rd>, CPSR
MRS{<cond>}   <Rd>, SPSR
 	Rn := xPSR 
Копирование регистра статуса в регистр общего назначения
MSR
MSR{<cond>} CPSR_<fields>, <Rd> 
MSR{<cond>} SPSR_<fields>, #immediate
MSR{<cond>} CPSR_<fields>, <Rd> 
MSR{<cond>} SPSR_<fields>, #immediate

<fields> - одно или больше из последовательности 
 	c разрешить изменять PSR[7:0]
 	x разрешить изменять PSR[15:8]
 	s разрешить изменять PSR[23:16]
 	f разрешить изменять PSR[31:24]
Эти модификаторы устанавливают в единицу биты [19:16] в коде команды, которые используются как признаки разрешения обновления соответствующих полей в регистре состояния.
Инструкция предназначена для изменения значения флагов, битов разрешения прерываний, или процессорного режима в слове состояния. Из пользовательского режима (USER mode) в привилегированные переключиться не получится, так как операция работает только в привилегированных режимах.

Пример смены режима процессора:
 	MRS R0, CPSR 	; Прочитать слово состояния
 	BIC R0, R0, #0x1F ; Очистить поле режима процессора
 	ORR R0, R0, #0x13 ; Установить в Supervisor
 	MSR CPSR_c, R0	; Переключится в режим Supervisor
MUL
MUL{<cond>}{S}   <Rd>,<Rm>,<Rs> 
 	Rd := Rm * Rs; 
Умножение операндов со знаком или без знака.
S - разрешение установки флагов Z N по результату операции.
MVN
MVN{<cond>}{S}   <Rd>,<Op2>
Rd := NOT Op2
Перенести в <Rd> инвертированное значение <Op2>
S - разрешение установки флагов Z N соответствует переносимому значению. Флаг C устанавливается в результате сдвига операнда <Op2>. Если <Rd> - R15, то S разрешает копировать SPSR в CPSR. Текущий режим процессора в этом случае должен иметь SPSR, иначе результат непредсказуем!

NOP
Нет действия

ORR
ORR{<cond>}{S}   <Rd>,<Rn>,<Op2> 
 	Rd := Rn OR Op2 ; 
Побитная операция ИЛИ.
Нулевой (младший) разряд результата равен 0, если равны 0 младшие разряды в обоих операндах, иначе равен 1. Первый разряд результата равен 0, если равны 0 первые разряды в обоих операндах ... и.т.д. 
S - разрешение установки флагов Z N по результату операции. Флаг C устанавливается в результате сдвига операнда <Op2>. Если <Rd> - R15, то S разрешает копировать SPSR в CPSR. Текущий режим процессора в этом случае должен иметь SPSR, иначе результат непредсказуем!
PLD
PLD <addressing_mode >
Подготавливает систему памяти к тому, что в ближайшем будущем к указанному адресу будут произведены обращения. Данные по этому адресу операцией загружаются в кэш. Адрес не может быть задан в форме прединдексации  и постиндексации.
RSB 
RSB{<cond>}{S}   <Rd>,<Rn>,<Op2>
 	Rd := Op2 - Rn; Reverse Subtract 
Перевернутое вычитание.
Вычитание из второго операнда первого. S - разрешение установки флагов Z N C V по результату операции. Если <Rd> - R15, то S разрешает копировать SPSR в CPSR. Текущий режим процессора в этом случае должен иметь SPSR, иначе результат непредсказуем!
RSC
RSC{<cond>}{S}   <Rd>,<Rn>,<Op2>
 	Rd := Op2 - Rn – 1 + Carry; Reverse Subtract with Carry
Перевернутое вычитание с учетом переноса.
Вычитание из второго операнда первого. Если C==0, результат уменьшить на 1.
S - разрешение установки флагов Z N C V по результату операции. Если <Rd> - R15, то S разрешает копировать SPSR в CPSR. Текущий режим процессора в этом случае должен иметь SPSR, иначе результат непредсказуем!
SBC
SBC{<cond>}{S} <Rd>,<Rn>,<Op2>
 	Rd := Rn - Op2 – 1 + Carry; Subtract with Carry 
Вычитание с учетом переноса.
Вычитание из первого операнда второго. Если C==0, результат уменьшить на 1.
S - разрешение установки флагов Z N C V по результату операции. Если <Rd> - R15, то S разрешает копировать SPSR в CPSR. Текущий режим процессора в этом случае должен иметь SPSR, иначе результат непредсказуем!
STC
STC{<cond>}{L}   <coproc>, <CRd>,<addressing_mode C>
{L} - long load. 
<coproc> - имя сопроцессора (p0...p15)
<CRd> - первый из сохраняемых регистров сопроцессора
См. <addressing_mode C> - метод вычисления адреса
Сохранение нескольких регистров сопроцессора в памяти. Количество регистров определяется сопроцессором, но не более 16.
STC2
STC2{L}   <coproc>, <CRd>,<addressing_mode C>
{L} - long load. 
<coproc> - имя сопроцессора (p0...p15)
<CRd> - первый из сохраняемых регистров сопроцессора
См. <addressing_mode C> - метод вычисления адреса
Сохранение нескольких регистров сопроцессора в память. Количество регистров определяется сопроцессором, но не более 16. Отличается отсутствием условия исполнения, что дает дополнительное место для опкодов сопроцессора.
STM
STM{<cond>}<addressing_mode 3>   <Rn>{!},   <registers> {^}
Сохранение нескольких регистров в память. 
См. addressing_mode 3
STR
STR{<cond>} <Rd>, <addressing_mode 1>
 	[address]  [7:0] := Rd [7:0] 
	[address+1][7:0] := Rd [15:8]
	[address+2][7:0] := Rd [23:16]
	[address+3][7:0] := Rd [31:24]
Сохранение 32 битного значения из регистр Rd в память.
См. <addressing_mode 1> - вычисляемый адрес.   
STRB
STRB{<cond>} <Rd>, <addressing_mode 1>
 	address[7:0] := Rd[7:0] 
Сохранение байта из регистра Rd в память.
См. <addressing_mode 1> - вычисляемый адрес
STRH 
STRB{<cond>} <Rd>, <addressing_mode 2>
	[address]  [7:0] := Rd [7:0] 
	[address+1][7:0] := Rd [15:8]
Сохранение полуслова из регистра Rd в память.
См. <addressing_mode 2> - вычисляемый адрес
STRD
STRD{<cond>} <Rd>,<addressing_mode 2>
	[address]  [7:0] := Rd [7:0] 
	[address+1][7:0] := Rd [15:8]
	[address+2][7:0] := Rd [23:16]
	[address+3][7:0] := Rd [31:24]
  	[address+4][7:0] := Rd+1 [7:0] 
	[address+5][7:0] := Rd+1 [15:8]
	[address+6][7:0] := Rd+1 [23:16]
	[address+7][7:0] := Rd+1 [31:24]
Сохранение 64 разрядного числа из регистров Rd и Rd+1 в память.
См. <addressing_mode 2> - вычисляемый адрес
SUB
SUB{<cond>}{S} <Rd>,<Rn>,<Op2>
 	Rd := Rn - Op2;
Вычитание.
S - разрешение установки флагов Z N C V по результату операции. Если <Rd> - R15, то S разрешает копировать SPSR в CPSR. Текущий режим процессора в этом случае должен иметь SPSR, иначе результат непредсказуем!
SWI
SWI{<cond>} <24 бит значение>
Программное прерывание, вызов обслуживания ОS. 
Исключение с вектором 0x8, в LR заносится адрес следующей за SWI команды.
Передаваемое значение должно быть в пределах от 0 до 255, оно игнорируется процессором, но передается в операционную систему для определения требуемой операции OS. 

SWP 
SWP{<cond>} <Rd>,<Rm>,[<Rn>]
Rd := [Rn], [Rn] := Rm 
Обмен значением между памятью и регистром.
Содержимое ячейки с адресом Rn помещается в Rd. 
Содержимое Rm сохраняется в ячейке с адресом Rn. Операция служит  
SWPB
SWPB{<cond>} <Rd>,<Rm>,[<Rn>]
 	Rd := ZeroExtended[Rn][7:0] 
 	[Rn][7:0] := Rm
Обмен байта между памятью и байтом.
TEQ
TEQ{<cond>}{S}  <Rn>,<Op2>
 	CPSR flags:= Rn EOR Op2 
Установка флагов в N Z результате операции EOR(XOR) между Rn и Op2. Результат операции нигде не сохраняется. 
Флаг C может быть установлен операцией сдвига Op2 (См. shifter_operand). 
TST
 	CPSR flags:= Rn AND Op2 
Установка флагов в N Z результате операции AND между Rn и Op2. Результат операции нигде не сохраняется. 
Флаг C может быть установлен операцией сдвига Op2 (См. shifter_operand). 

DSP - подобные операции 
Арифметика с насыщением. QADD QDADD QSUB QDSUB 
Насыщение – случай превышения результатом операции максимального (или минимального для отрицательного числа) возможного, определяемого его разрядностью, значения. В отличие от  случая переполнения,  результат операции ограничивается максимальным (минимальным) значением.   
QADD
QADD{<cond>} <Rd>,<Rm>,<Rn>
Rd := SAT (Rm + Rn) Saturated add 
Сложение с насыщением. Оба операнда рассматриваются как 32 разрядные числа со знаком. Если в результате сложения двух положительных чисел результат превосходит величину 0x7FFFFFFF, то возвращается результат 0x7FFFFFFF и устанавливается в 1 флаг Q.
Если в результате сложения двух отрицательных чисел получаемый результат меньше величины 0x80000000 (минимального 32 разр. отрицательного числа), то возвращается результат 0x80000000 и устанавливается в 1 флаг Q.

Пример для ARMDebugger :
$ARM9E				; версия процессора
AREA   STARTUPCODE, CODE
code32
start_:
	ldr r0, =0x7FFFFFFE ;уже большое число 
	ldr r1, =0xFF		;добавим чуть - чуть
	qadd r2,r0,r1		;вернет R2 = 0x7FFFFFFF, Q flag =1 
	bx lr
END
QDADD
QDADD{<cond>} <Rd>,<Rm>,<Rn>
 	Rd := SAT (Rm + SAT (Rn * 2)) 
Прибавление удвоенного с насыщением.
Rn умножается на 2, результат умножения - с насыщением. Полученное произведение прибавляется к Rm, сумма – с насыщением. Q флаг устанавливается при любом насыщении.
QSUB
QSUB{<cond>} <Rd>,<Rm>,<Rn>
 	Rd := SAT (Rm - Rn) 
Вычитание с насыщением. Для подробностей см. QADD
QDSUB 
QDSUB{<cond>} <Rd>,<Rm>,<Rn>
 	Rd := SAT (Rm - SAT (Rn*2)); 
Вычитание удвоенного с насыщением. Q флаг устанавливается при любом насыщении.
См. QADD QDADD
Команды арифметики с учетом знака и установкой флага Q.  SMULxy SMULWy  …

В большинстве последующих команд регистры рассматриваются как два 16 разрядных значения (halfword) со знаком. Под x и y в мнемонике команды понимается указатель на старшее (top) или младшее (bottom) 16 разрядное полуслово. Комбинации для xy - BB BT TB TT, соответственно указывают, какие полуслова будут участвовать в операции. 
BB – из обоих регистров в операции участвуют младшие полуслова. 
BT – из первого регистра младшее из второго старшее, и т д...  
Если в мнемонике указан только y модификатор, он указывает, какое полуслово берется из второго операнда – регистра и, соответственно, может быть B или T.

SMULxy
SMULxy{<COND>} <Rd>,<Rm>,<Rs> 
 	Rd := Rm[x] * Rs[y]
Умножение двух 16 разрядных чисел со знаком, 32 разрядный результат в Rd.
Пример: 
 	smultb r0,r1,r2; R0 = R1[31:16] * R2[15:0]  
 	smulbb r0,r0,r0; Возведение R0[15:0] в квадрат
SMULWy
SMULWy{<COND>} <Rd>,<Rm>,<Rs> 
 	Rd := (Rm * Rs[y])[47:16] 
Умножение (32 x 16) разрядов
Умножение 32 разрядного числа со знаком Rm на 16 разрядное Rs[y] со знаком, 32 старших разряда из полученного 48 разрядного результата поместить в Rd
SMLAxy
SMLAxy{<COND>} <Rd>,<Rm>,<Rs>,<Rn> 
 	Rd := Rn + Rm[x] * Rs[y] 
умножение (16 x 16) разрядов с 32 разрядным накоплением
Умножение двух 16 разрядных чисел со знаком Rm[x] Rs[y], 32 разрядный результат прибавить к Rn с учетом знака, сумму поместить в Rd. Если при накоплении наступит насыщение, флаг Q будет установлен в 1, но результат не ограничивается.
SMLAWy
SMLAWy{<COND>} <Rd>,<Rm>,<Rs>,<Rn> 
 	Rd := Rn+(Rm * Rs[y])[47:16] 
Умножение (32 x 16) разрядов с 32 разрядным накоплением.
Умножение 32 разрядного числа со знаком Rm на 16 разрядное Rs[y] со знаком, 32 старших разряда из полученного 48 разрядного результата прибавить к Rn с учетом знака, сумму поместить в Rd. Если при накоплении наступит насыщение, флаг Q будет установлен в 1, но результат не ограничивается.
SMLALxy
SMLALxy{<COND>} <RHi>,<RLo>,<Rm>,<Rs> 
 	RdHi,RdLo := RdHi,RdLo + Rm[x]*Rs[y] 
умножение (16 x 16) разрядов с 64 разрядным накоплением.
В качестве 64 разрядного значения выступает пара регистров RdHi,RdLo.
Умножение двух 16 разрядных чисел со знаком Rm[x] Rs[y], 32 разрядный результат прибавить к RdHi,RdLo  с учетом знака, сумму поместить в RdHi,RdLo. 

Набор команд Thumb.

Команды Thumb набора имеют гораздо меньше возможных форм и проще в изучении.

Некоторые пояснения:
< > - в таких скобках указываются изменяемые части команды - модификаторы или операнды. 
Операнды могут быть:
#<imm_X> - X битное непосредственное значение, хранится в коде программы
<Rx> - регистр, в команде хранится его номер.
Модификаторы:
<cond> - поле условного выполнения. Совпадает с ARM набором. 

Команды описаны в “развернутом” виде, приближенном к тому, как они хранятся в памяти программ и исполняются ядром процессора. Что это дает? К примеру, команда перехода B:

B(1)
B<cond> <signed imm_8>
	PC := (signed imm_8 * 2) + PC + 4;	
Условный относительный переход на, приблизительно, +/-255 байт, только на четные адреса.   
<cond> - поле условий, полностью совпадает с режимом ARM. 
	beq address;

Что можно увидеть в таком описании? Во первых, команда имеет модификатор 
условия <cond>. Во вторых, смещение хранится в виде восьмиразрядного значения со знаком. В третьих, перед прибавлением к PC это значение умножается на 2, соответственно адрес перехода может быть только четным и отстоять от текущего не более чем на ~127*2 = 255 байт (127 – потому что один бит уходит на знак). Ну и в четвертых, видно, что максимальное положительное смещение  больше, чем максимальное отрицательное из-за известного свойства чтения регистра R15 (в режиме Thumb считываемое из него значение равно текущему адресу + 4).
ADC		
ADC <Rd>,<Rm>
 	Rd := Rd + Rm + C		
Сложение с переносом
Применимы только регистры R0-R7
Изменяемые флаги: N, Z, C, V
 	adc r0,r1;
ADD(1)
ADD <Rd>,<Rm>,#<imm_3>
 	Rd := Rm + #imm_3
Прибавление к Rm трехразрядного значения. Результат в Rd. 
Применимы только регистры R0-R7
Изменяемые флаги: N, Z, C, V
Примечание: несмотря на то, что второе слагаемое для этой команды - только положительное число не большее, чем 7 (111b), можно указывать и отрицательное, тогда в программу будет вставлена команда sub Rd,Rm,#imm_3. Это относится ко многим командам add, имеющим  sub “пары”.
 	add r0,r1,#7;
 	add r0,r1,#-7; пара sub r0,r1,#7
ADD(2)
ADD <Rd>,#<imm_8>
 	Rd := Rd + #<imm_8>
Сумма Rd и imm_8, результат поместить в Rd
Применимы только регистры R0-R7
Изменяемые флаги: N, Z, C, V
 	add r0,#255 ;
 	add r0,#-255 ; sub пара

ADD(3)
ADD <Rd>,<Rn>,<Rm>
 	Rd := Rn + Rm
Сумма Rn и Rm, результат поместить в Rd
Применимы только регистры R0-R7
Изменяемые флаги: N, Z, C, V
 	add r0,r1,r2;
ADD(4)
ADD <Rd>,<Rm>
 	Rd := Rd + Rm
Применимы регистры R0-R15. Но применение одновременно двух младших регистров недопустимо, результат непредсказуем.
флаги не изменяются
 	add r0,r1;
ADD(5)
ADD <Rd>,PC,<#imm_8> * 4
 	Rd := (PC AND 0xFFFFFFFC)+ #immed_8 << 2
Применимы регистры R0-R7. Только значение кратное 4 и меньшее, чем 1020 можно указывать в качестве слагаемого. 
флаги не изменяются
 	add r0,pc,#4; -допустимо 
 	add r0,pc,#5; -недопустимо, не кратно 4
 	add r0,pc,#1020;  255 * 4 =1020 максимально допустимое смещение
 	add r0,pc,#1024;  недопустимо, больше 1020
	add r0,pc,#-24;  недопустимо, пары sub нет
ADD(6)
ADD <Rd>,SP,#<imm_8> * 4
 	Rd := SP + #immed_8 << 2
Применимы регистры R0-R7. Только значение кратное 4 и меньшее, чем 1020 можно указывать в качестве смещения. Максимальное слагаемое равно (2**8-1)*4 = 1020.
флаги не изменяются
	add r0,sp,#20; 
 	add r0,sp,#-4; недопустимо, пары sub нет 	
ADD(7)
ADD SP,#<imm_7> * 4
 	SP := SP + #imm_7 << 2
Только значение кратное 4 и меньшее, чем 508 можно указывать в качестве слагаемого.
флаги не изменяются
 	add sp,#16;
 	add sp,#-16; sub пара
AND
AND <Rd>,<Rm>
 	Rd := Rd AND Rm
Логическое И
Применимы регистры R0-R7. 
Изменяемые флаги: N, Z
 	and r0,r1;

ASR(1)
ASR <Rd>,<Rm>,#<imm_5>
 	Rd := (signed) Rm >> imm_5	
Арифметический сдвиг вправо со знаком (деление на степень 2). В отличии от логического сдвига, при арифметическом происходит расширение знакового разряда (т. е. во все старшие разряды, “освобожденные” при сдвиге заносится 1 для отрицательного или 0 для положительного числа). Применимы регистры R0-R7. 
Изменяемые флаги: N, Z, последний выдвинутый в результате сдвига разряд помещается в C.
Если указать сдвиг на 0, это трактуется как сдвиг на 32! 
 	asr r0,r1,#31;
ASR(2)
ASR <Rd>,<Rs>
 	Rd := (signed) Rm >> Rs	
Арифметический сдвиг вправо со знаком (деление на степень двойки). В отличие от логического сдвига, при арифметическом происходит расширение знакового разряда (т. е. во все старшие разряды, “освобожденные” при сдвиге заносится 1 для отрицательного или 0 для положительного числа). 
Применимы регистры R0-R7. 
Изменяемые флаги: N, Z, последний выдвинутый в результате сдвига разряд помещается в C.
 	asr r0,r1;
B(1)
B<cond> <signed imm_8>
	R15 := (signed imm_8 * 2) + PC + 4;	
Условный относительный переход на, приблизительно, +/-255 байт, только на четные адреса.   
<cond> - поле условий, полностью совпадает с режимом ARM. 
 	beq address;
B(2)
B <signed imm_12>
	R15 := (signed imm_12 * 2) + PC + 4;	
Безусловный относительный переход на, приблизительно, +/-2048 байт, только на четные адреса.   
 	b address;
BIC	
BIC <Rd>,<Rm>
 	Rd := Rd AND NOT Rm
Очистка бит.
Сбрасывает в 0 биты в тех разрядах Rd, которые равны 1 в Rm. 
Применимы регистры R0-R7. 
Изменяемые флаги: N, Z
 	bic r0,r1;
BKPT
BKPT #<imm_8>
 	LR:= адрес возврата
 	PC:= 0x0C (или 0xFFFF000C)
Точка отладочного останова. 
Восьмиразрядное значение передается в отладчик для индикации места останова.
 	bkpt #123;

BL 
BL <address>
	PC:= address
 	LR:= адрес следующей команды
Вызов подпрограммы по относительному адресу. Команда занимает в памяти 4 байта и состоит из двух 2х байтных частей, в первой из которых находится старшие 11 разрядов, а во второй младшие 11 разрядов смещения. Максимальное смещение адреса примерно равно +/- 0x3FFFFF (~ +/-4MB) 
 	bl address;   	
BLX(1) 
BLX <address>
	PC:= address & 0xFFFFFFFC
 	LR:= адрес следующей команды
 	T = 0
Вызов подпрограммы по относительному адресу с обязательной сменой набора команд на ARM. Команда занимает в памяти 4 байта и состоит из двух 2х байтных частей, в первой из которых находится старшие 11 разрядов, а во второй младшие 11 разрядов смещения. Максимальное смещение адреса примерно равно +/- 0x3FFFFF (~ +/-4MB) 
 	blx address;
BLX(2) 
BLX <Rm>
	PC:= Rm & 0xFFFFFFFE
 	LR:= адрес следующей команды
 	T = Rm[0]
Вызов подпрограммы по адресу в Rm с возможной сменой набора команд на ARM. Если младший бит адреса == 0, происходит смена набора команд, при этом недопустим переход на адрес не выравненный кратно четырем.
Применимы регистры R0-R14.
 	ldr r0,=address;
 	blx r0;
BX 
BX <Rm>
	PC:= Rm & 0xFFFFFFFE
	T = Rm[0]
Переход по адресу в Rm с возможной сменой набора команд на ARM. Если младший бит адреса == 0, происходит смена набора команд, при этом недопустим переход на адрес не выравненный кратно четырем.
Применимы регистры R0-R14.
	ldr r0,=address;
 	bx  r0;
CMN
CMN <Rn>,<Rm>
 	Установка флагов в соответствии с результатом сложения Rn + Rm. Результат не сохраняется.
Применимы только регистры R0-R7
Изменяемые флаги: N, Z, C, V
 	cmn r0,r1;
CMP(1)
CMP <Rn>, #imm_8
	Установка флагов в соответствии с результатом операции Rn – imm_8, результат не сохраняется. Максимальное значение второго операнда равно 255.
Применимы только регистры R0-R7
Изменяемые флаги: N, Z, C, V
 	cmp r0,#0xEB;
CMP(2)
CMP <Rn>, <Rm>
 	Установка флагов в соответствии с результатом операции Rn - Rm. Результат не сохраняется.
Применимы регистры R0-R15. В случае присутствия в качестве любого операнда старшего регистра, формируется команда с другим кодом. Это не имеет никакого значения при программировании, но иногда приходится учитывать при деассемблировании.
Изменяемые флаги: N, Z, C, V
 	cmp r0,r1;
 	cmp r12,r3; - другой код

EOR
EOR <Rd>,<Rm>
 	Rd := Rd EOR Rm
Исключающее ИЛИ.
Логическая операция, при которой каждый разряд результата устанавливается в 
Применимы регистры R0-R7. 
Изменяемые флаги: N, Z
 	eor r0,r1;
LDMIA
LDMIA <Rn>!, <registers>
Загрузка нескольких регистров по списку, регистры загружаются последовательно, начиная с самого маленького номера и заканчивая наибольшим, первый регистр загружается значением, хранящимся по адресу Rn, адрес загружаемого значения для каждого следующего регистра увеличивается на 4 (Load Multiple Increment After). 
<Rn> регистр, хранящий перед началом операции стартовый адрес. 
! – указывает, что по завершению операции значение <Rn> обновляется, увеличиваясь на величину равную учетверенному количеству загруженных регистров, это не опция, указывается для подсказки.
<registers> - список из нескольких (возможно, всех) младших регистров.
 	ldmia r0!,{r1,r3,r5-r7};
LDR(1)
LDR <Rd>, [<Rn>, #<imm_5> * 4]
 	Rd:=(Rn+imm_5*4)[31:0]
<Rd> - регистр в которое загружается значение
<Rn> - базовый адрес для операции. Должен быть выравнен кратно 4 байтам, иначе загрузится непредсказуемое значение.
<imm_5> - пятибитное число, которое умножается на 4 и прибавляется к значению Rn для получения адреса загружаемого значения. 
Максимальное смещение равно (2**5 -1) * 4 = 124.
Применимы регистры R0-R7.
 	ldr r0,[r1,#120];
LDR(2)
LDR <Rd>, [<Rn>, <Rm>]
	Rd:=(Rn+Rm)[31:0]
<Rd> - регистр в которое загружается значение
<Rn> - базовый адрес для операции. 
<Rm> - регистр содержащий смещение прибавляемое к базовому адресу в Rn для получения адреса загружаемого значения. Полученный адрес должен быть выравнен кратно 4 байтам, иначе загрузится непредсказуемое значение.
Применимы регистры R0-R7.
	ldr r0,[r1,r2];

LDR(3)
LDR <Rd>, [PC, #<imm_8> * 4]
 	Rd=((PC & 0xFFFFFFFC) + (imm_8*4))[31:0] 
<Rd> - регистр в которое загружается значение
PC – счетчик команд.
<imm_8> - восьмибитное число, которое умножается на 4 и прибавляется к значению PC  для получения адреса загружаемого значения. Обратите внимание, что значение из PC берется с обнуленными двумя младшими битами. Максимальное смещение равно (2**8 -1) * 4 = 1020.
Применимы регистры R0-R7.
 	ldr r0,[r15,#120];
LDR(4)
LDR <Rd>, [SP, #<imm_8> * 4]
 	Rd:= (SP  + imm_8 * 4)[31:0] 
<Rd> - регистр в которое загружается значение
SP – R13 указатель стека.
<imm_8> - пятибитное число, которое умножается на 4 и прибавляется к значению SP для получения адреса загружаемого значения. Полученный адрес должен быть выравнен кратно 4 байтам, иначе загрузится непредсказуемое значение. Эта форма команды обычно используется для извлечения значения параметров функции, передаваемых через стек. Максимальное смещение равно (2**8 - 1) * 4 = 1020.
Применимы регистры R0-R7.
 	ldr r0,[sp,#12];
LDRB(1)
LDRB <Rd>, [<Rn>, #<imm_5>]
 	Rd[31:8]:=0x000000;
	Rd[7:0]:=(Rn+imm_5)[7:0];
Загрузка в регистр байта с дополнением нулями из памяти 
<Rd> - регистр в которое загружается значение
<Rn> - базовый адрес для операции.
<imm_5> - пятибитное число, которое прибавляется к значению Rn для получения адреса загружаемого значения. Максимальное смещение равно (2**5-1)= 31.
Применимы регистры R0-R7.
 	ldrb r0,[r1,#31]
LDRB(2)
LDRB <Rd>, [<Rn>, <Rm>]
	Rd[31:8]:=0x000000;
	Rd[7:0]:=(Rn+Rm)[7:0]
Загрузка в регистр байта с дополнением нулями из памяти 
<Rd> - регистр в которое загружается значение
<Rn> - базовый адрес для операции. 
<Rm> - регистр содержащий смещение прибавляемое к базовому адресу в Rn для получения адреса загружаемого значения. 
Применимы регистры R0-R7.
 	ldrb r0,[r1,r2];
LDRH(1)
LDRH <Rd>, [<Rn>, #<imm_5> * 2]
 	Rd[31:16]:=0x0000;
	Rd[15:0]:=(Rn+imm_5 * 2)[15:0];
Загрузка в регистр полуслова с дополнением нулями из памяти 
<Rd> - регистр в которое загружается значение
<Rn> - базовый адрес для операции. Адрес должен быть выравнен кратно 2 байтам.
<imm_5> - пятибитное число, удвоенное значение которого прибавляется к Rn для получения адреса загрузки. Максимальное смещение равно (2**5 -1) *2 = 62.  
Применимы регистры R0-R7.
 	ldrh r0,[r1,#62];

LDRH(2)
LDRH <Rd>, [<Rn>, <Rm>]
	Rd[31:16]:=0x0000;
	Rd[15:0]:=(Rn+Rm)[15:0]
Загрузка в регистр полуслова с дополнением нулями из памяти 
<Rd> - регистр в которое загружается значение
<Rn> - базовый адрес для операции. 
<Rm> - регистр содержащий смещение прибавляемое к базовому адресу в Rn для получения адреса загружаемого значения. Полученный адрес должен быть выравнен кратно 2 байтам, иначе загрузится непредсказуемое значение. 
Применимы регистры R0-R7.
 	ldrh r0,[r1,r2];
LDRSB
LDRB <Rd>, [<Rn>, <Rm>]
	if ((Rn+Rm)[7] == 0)  Rd[31:8]:=0x000000; 
      else                  Rd[31:8]:=0xFFFFFF; 
	Rd[7:0]:=(Rn+Rm)[7:0]
Загрузка в регистр байта с расширением знака из памяти 
<Rd> - регистр в которое загружается значение
<Rn> - базовый адрес для операции. 
<Rm> - регистр содержащий смещение прибавляемое к базовому адресу в Rn для получения адреса загружаемого значения. 
Применимы регистры R0-R7.
 	ldrsb r0,[r1,r2];
LDRSH
LDRH <Rd>, [<Rn>, <Rm>]
	if ((Rn+Rm)[15] == 0)
         Rd[31:16]:=0x0000; 
      else
         Rd[31:16]:=0xFFFF; 
	Rd[15:0]:=(Rn+Rm)[15:0];
Загрузка в регистр полуслова с расширением знака из памяти 
<Rd> - регистр в которое загружается значение
<Rn> - базовый адрес для операции. 
<Rm> - регистр содержащий смещение прибавляемое к базовому адресу в Rn для получения адреса загружаемого значения. 
Применимы регистры R0-R7.
 	ldrsh r0,[r1,r2];
LSL(1)
LSL <Rd>, <Rm>, #imm_5
	Rd := Rm <<  imm5;
Логический сдвиг влево значения из Rm, результат поместить в Rd.
Применимы регистры R0-R7. 	
Изменяемые флаги: C, N, Z
 	lsl r0,r1,#31;
LSL(2)
LSL <Rd>, <Rm>, <Rs>
	Rd := Rm << Rs;
Логический сдвиг влево значения из Rm, результат поместить в Rd.
Применимы регистры R0-R7. 	
Изменяемые флаги: C, N, Z
 	lsl r1,r2,r3;

LSR(1)
LSR <Rd>, <Rm>, #imm_5
	Rd := Rm >>  imm5;
Логический сдвиг вправо значения из Rm, результат поместить в Rd.
Применимы регистры R0-R7. 	
Изменяемые флаги: C, N, Z
 	lsr r0,r1,#31; 
LSR(2)
LSR <Rd>, <Rm>, <Rs>
	Rd := Rm >> Rs;
Логический сдвиг вправо значения из Rm, результат поместить в Rd.
Применимы регистры R0-R7. 	
Изменяемые флаги: C, N, Z
	lsr r0,r1,r3; 
MOV(1)
MOV <Rd>,#<imm_8>
Занесение в Rd непосредственного 8 разрядного значения.
Применимы регистры R0-R7. 	
Изменяемые флаги:  Z
 	mov r0,#255;
MOV(2)
MOV <Rd>,<Rn>
	Rd := Rn
Занесение в Rd  значения из Rn. Оба регистра должны быть младшими.
Применимы регистры R0-R7. 	
Изменяемые флаги:  N,Z
 	mov r0,r1;
MOV(3)
MOV <Rd>,<Rn>
	Rd := Rn
Занесение в Rd  значения из Rn. В этой форме команды один или оба регистра должны быть старшими, код команды отличается от предыдущей, флаги не меняются.
Применимы регистры R0-R15.	
Флагов не меняет.
	mov r0,r8;
 	mov r15,r14; синоним RET 
MUL
MUL <Rd>,<Rm>
	Rd := (Rm * Rs)[31:0]
Умножение двух регистров со знаком или без знака, младшие 32 бита результата помещаются в Rd.
Применимы регистры R0-R7. 	
Изменяемые флаги:  N,Z
 	mul r0,r1;
MVN
MVN <Rd>,<Rm>
 	Rd := NOT Rm	
Поместить в Rd инвертированное значение из Rm. 
Применимы регистры R0-R7. 	
Изменяемые флаги:  N,Z
 	mvn r0,r1;

NEG
NEG <Rd>,<Rm>
	Rd := -Rm
Поместить в Rd значение из Rm, предварительно сменив знак числа. 
Применимы регистры R0-R7. Изменяемые флаги:  N,Z,C,V
 	neg r0,r1;
ORR
ORR <Rd>,<Rm>
	Rd := Rd OR Rm	
Логическое ИЛИ.
Применимы регистры R0-R7. Изменяемые флаги:  N,Z
 	orr r0,r1;
POP
POP <registers>
Загрузка из стека нескольких (возможно, всех) младших регистров и, возможно, регистра PC. Регистры загружаются последовательно, начиная с самого младшего номера и заканчивая наибольшим номером. Начальный адрес для загрузки первого регистра равен значению SP. Адрес для загрузки каждого следующего регистра увеличивается на 4. В конце операции значение SP увеличивается на учетверенное число загруженных регистров.
<registers> - список регистров разделенных запятой или указанных через дефис, в фигурных скобках.
Применимы регистры R0-R7,PC. 	
	pop {r0,r2,r3};
 	pop {r0,r2,r4-r6,PC};
PUSH
PUSH <registers>
Сохранение в стек нескольких (возможно, всех) младших регистров и, возможно, регистра LR.
Регистры сохраняются последовательно, начиная с самого большого номера и заканчивая самым маленьким номером. Начальный адрес для сохранения первого регистра равен значению SP. Адрес для сохранения каждого следующего регистра уменьшается на 4. В конце операции значение SP уменьшается на учетверенное число сохраненных регистров.
<registers> - список регистров разделенных запятой или указанных через дефис, в фигурных скобках.
Применимы регистры R0-R7,LR. 	
	push {r0,r2,r3};
 	push {r0,r2,r4-r6,LR};
ROR
ROR <Rd>,<Rs>
	Rd := Rd ROR Rs[7:0]
Команда правого циклического сдвига значения в Rd на число разрядов указанное в Rs. Биты выдвинутые из регистра справа помещаются в освободившиеся слева разряды.  
Применимы регистры R0-R7
Изменяемые флаги:  N,Z по результату операции, C равно последнему выдвинутому справа разряду.
 	ror r0,r1;
SBC
SBC <Rd>,<Rm>
	Rd := Rd - Rm - NOT C
Вычитание с учетом переноса.
Применимы регистры R0-R7. Изменяемые флаги:  N,Z,C,V
 	sbc r0,r1;

STMIA
STMIA <Rn>!, <registers>
Сохранение нескольких регистров по списку.
Регистры сохраняются последовательно, начиная с самого маленького номера и заканчивая наибольшим. Первый регистр сохраняется в ячейку  по адресу Rn, адрес сохранения для каждого следующего регистра увеличивается на 4 (Load Multiple Increment After). 
<Rn> регистр, хранящий перед началом операции стартовый адрес. 
! – указывает, что по завершению операции значение <Rn> обновляется, увеличиваясь на величину равную учетверенному количеству сохраненных регистров, это не опция, указывается для подсказки.
<registers> - список из нескольких (возможно, всех) младших регистров разделенных запятой или указанных через дефис, в фигурных скобках.
 	stmia r0!,{r1,r3,r5-r7};
STR(1)
STR <Rd>, [<Rn>, #<imm_5> * 4]
 	 (Rn+imm_5*4)[31:0] := Rd
Сохранение значения из регистра в память.
<Rd> - регистр в значение которого сохраняется. 
<Rn> - базовый адрес для операции. Должен быть выравнен кратно 4 байтам.
<imm_5> - пятибитное число, которое умножается на 4 и прибавляется к значению Rn для получения адреса сохранения. 
Максимальное смещение равно (2**5 -1) * 4 = 124.
Применимы регистры R0-R7.
 	str r0,[r1,#120];
STR(2)
STR <Rd>, [<Rn>, <Rm>]
	(Rn+Rm)[31:0]:= Rd
Сохранение значения из регистра в память.
<Rd> - регистр значение  которого сохраняется. 
<Rn> - базовый адрес для операции. 
<Rm> - регистр содержащий смещение прибавляемое к базовому адресу в Rn для получения адреса сохранения. Полученный адрес должен быть выравнен кратно 4 байтам, иначе результат непредсказуем.
Применимы регистры R0-R7.
	str r0,[r1,r2];
STR(3)
STR <Rd>, [SP, #<imm_8> * 4]
 	(SP + imm_8 * 4)[31:0] := Rd 
Сохранение значения из регистра в стек.
<Rd> - регистр значение  которого сохраняется.
SP – R13 указатель стека.
<imm_8> - восьмибитное число, которое умножается на 4 и прибавляется к значению SP для получения адреса сохранения регистра. Полученный адрес должен быть выравнен кратно 4 байтам. Максимальное смещение равно (2**8 - 1) * 4 = 1020.
Применимы регистры R0-R7.
 	str r0,[sp,#40];
STRB(1)
STRB <Rd>, [<Rn>, #<imm_5>]
 	 (Rn+imm_5)[7:0] := Rd[7:0];
Сохранение байта из регистра в память 
<Rd> - регистр в которое загружается значение
<Rn> - базовый адрес для операции.
<imm_5> - пятибитное число, которое прибавляется к значению Rn для получения адреса сохранения. Максимальное смещение равно (2**5-1)= 31.
Применимы регистры R0-R7.
 	strb r0,[r1,#31]
STRB(2)
STRB <Rd>, [<Rn>, <Rm>]
	 (Rn+Rm)[7:0] := Rd[7:0]
Сохранение байта из регистра в память
<Rd> - регистр в которое загружается значение
<Rn> - базовый адрес для операции. 
<Rm> - регистр содержащий смещение прибавляемое к базовому адресу в Rn для получения адреса сохранения. 
Применимы регистры R0-R7.
 	strb r0,[r1,r2];
STRH(1)
STRH <Rd>, [<Rn>, #<imm_5> * 2]
	 (Rn+imm_5 * 2)[15:0] := Rd[15:0]
Сохранение полуслова из регистра в память
<Rd> - регистр в которое загружается значение
<Rn> - базовый адрес для операции. Адрес должен быть выравнен кратно 2 байтам.
<imm_5> - пятибитное число, удвоенное значение которого прибавляется к Rn для получения адреса сохранения. Максимальное смещение равно (2**5 -1) *2 = 62.  
Применимы регистры R0-R7.
 	strh r0,[r1,#62];

STRH(2)
STRH <Rd>, [<Rn>, <Rm>]
	 (Rn+Rm)[15:0] := Rd[15:0]
Сохранение полуслова из регистра в память
<Rd> - регистр в которое загружается значение
<Rn> - базовый адрес для операции. 
<Rm> - регистр содержащий смещение прибавляемое к базовому адресу в Rn для получения адреса сохранения. Полученный адрес должен быть выравнен кратно 2 байтам. 
Применимы регистры R0-R7.
 	strh r0,[r1,r2];

SWI
Программное прерывание, вызов сервисов ОS. 
Исключение с вектором 0x8, в LR заносится адрес следующей за SWI команды.
Передаваемое значение должно быть в пределах от 0 до 255, оно игнорируется процессором, но передается в операционную систему для определения требуемой операции OS.

SUB(1)
SUB <Rd>,<Rm>,#<imm_3>
 	Rd := Rm - #imm_3
Вычитание из Rm трехразрядного значения. Результат в Rd. 
Применимы только регистры R0-R7
Изменяемые флаги: N, Z, C, V
	sub r0,r1,#7;
SUB(2)
SUB <Rd>,#<imm_8>
 	Rd := Rd - #<imm_8>
Разность Rd и imm_8, результат поместить в Rd
Применимы только регистры R0-R7
Изменяемые флаги: N, Z, C, V
 	sub r0,#255 ;

SUB(3)
SUB <Rd>,<Rn>,<Rm>
 	Rd := Rn + Rm
Разность Rn и Rm, результат поместить в Rd
Применимы только регистры R0-R7
Изменяемые флаги: N, Z, C, V
 	sub r0,r1,r2;
SUB(4)
SUB SP,#<imm_7> * 4
 	SP := SP - #imm_7 << 2
Только значение кратное 4 и меньшее, чем 508 можно указывать в качестве вычитаемого.
Флаги не изменяются
 	sub sp,#16;
TST
TST <Rn>,<Rm>
CPSR flags:= Rn AND Rm 
Установка флагов в N Z результате операции AND между Rn и Rm. Результат операции не сохраняется. 
Применимы только регистры R0-R7
 	tst r0,r1;

Вместо введения. Чем ARM процессоры необычны.
Что такое "тумба". Два набора команд в одном процессоре.
Команды, которых нет.
Типы данных и размещение в памяти. Дамп программы.
БАЙТ (byte),
ПОЛУСЛОВО (halfword),
СЛОВО (word),
ДВОЙНОЕ СЛОВО (dword),
Работа с дампом программы в IDA
ИСКЛЮЧЕНИЯ
РЕЖИМЫ ПРОЦЕССОРА
РЕГИСТРЫ
Регистры общего назначения, используемые особым образом
Регистр R13 (SP)
Регистр R14 (LR).
Регистр R15 (PC)
Регистры состояния
Регистр состояния текущей программы CPSR
Сохраненный регистр состояния программы SPSR
Назначение разрядов регистров состояния:
назначение флагов N Z C V
Q флаг.
I, F, T и M[4:0]
Биты режима процессора M[4:0]:
Как заставить команду изменять флаги. {S} модификатор.
Как использовать флаги. Модификаторы проверки условий <cond>
Вычисляемые операнды, методы адресации данных ARM набора.
Непосредственный операнд <immediate>
Универсальный операнд <shifter_operand>
Пять типов сдвига
LSL
LSR
ASR
ROR
RRX
Одиннадцать форм <shifter_operand>:
#<immediate>
<Rn>
<Rn>, LSL #shift
<Rn>, LSL <Rm>
<Rn>, LSR #shift
<Rn>, LSR <Rm>
<Rn>, ASR #shift
<Rn>,ASR <Rm>
<Rn>, ROR #shift
<Rn>, ROR <Rm>
<Rn>, RRX
Режимы адресации  <addressing_mode>
Адресация для загрузки и сохранения слова или байта без знака <addressing_mode 1>
команды LDR STR LDRB STRB LDRT STRT LDRBT STRBT
[<Rn>]
[<Rn>, # -/+<offset_12>]
[<Rn>, # -/+<offset_12>]!
[<Rn>, +/- <Rm>]
[<Rn>, +/- <Rm>]!
[<Rn>, +/- <Rm>, <shift> #<shift_imm>]
[<Rn>, +/- <Rm>, <shift> #<shift_imm>]!
[<Rn>],  # -/+<offset_12>
[<Rn>], +/- <Rm>
[<Rn>], +/- <Rm>, <shift> #<shift_imm>
Адресация для дополнительных команд загрузки и сохранения  <addressing_mode 2>
команды LDRD STRD LDRH STRH LDRSH LDRSB
[<Rn>]
[<Rn>, # -/+<offset_8>]
[<Rn>, # -/+<offset_8>]!
[<Rn>, +/- <Rm>]
[<Rn>, +/- <Rm>]!
[<Rn>],  # -/+<offset_8>
[<Rn>], +/- <Rm>
Адресация для мультирегисторной загрузки и сохранения  <addressing_mode 3>
Команды STM LDM
Типы  < addressing_mode 3>:
IA
IB
DA
DB
Стек.  Адресация FA FD EA ED
Адресация операций загрузки или сохранения регистров сопроцессора <addressing_mode C>
Команды LDC STC
[<Rn>, #+/-<offset_8>*4]
[<Rn>, #+/-<offset_8>*4]!
[<Rn>],  #+/-<offset_8>*4
[<Rn>],  <option>
Команды ARM режима
ADC
ADD
AND
B
BL
BIC
BKPT
BLX
BLX
BX
CDP
CDP (форма 2)
CLZ
CMN
CMP
EOR
LDC
LDC2
LDM
LDR
LDRB
LDRH
LDRSB
LDRSH
LDRD
MCR
MCR2
MCRR
MLA
MOV
MRC
MRC2
MRRC
MRS
MSR
MUL
MVN
NOP
ORR
PLD
RSB
RSC
SBC
STC
STC2
STM
STR
STRB
STRH
STRD
SUB
SWI
SWP
SWPB
TEQ
TST
DSP - подобные операции
Арифметика с насыщением. QADD QDADD QSUB QDSUB
QADD
QDADD
QSUB
QDSUB
Команды арифметики с учетом знака и установкой флага Q.  SMULxy SMULWy  …
SMULxy
SMULWy
SMLAxy
SMLAWy
SMLALxy
Набор команд Thumb.
ADC
ADD(1)
ADD(2)
ADD(3)
ADD(4)
ADD(5)
ADD(6)
ADD(7)
AND
ASR(1)
ASR(2)
B(1)
B(2)
BIC
BKPT
BL
BLX(1)
BLX(2)
BX
CMN
CMP(1)
CMP(2)
EOR
LDMIA
LDR(1)
LDR(2)
LDR(3)
LDR(4)
LDRB(1)
LDRB(2)
LDRH(1)
LDRH(2)
LDRSB
LDRSH
LSL(1)
LSL(2)
LSR(1)
LSR(2)
MOV(1)
MOV(2)
MOV(3)
MUL
MVN
NEG
ORR
POP
PUSH
ROR
SBC
STMIA
STR(1)
STR(2)
STR(3)
STRB(1)
STRB(2)
STRH(1)
STRH(2)
SWI
SUB(1)
SUB(2)
SUB(3)
SUB(4)
TST

(c) Mnemo