ARM 处理器有两种主要的运行状态,ARM 和 Thumb。这些状态与特权级别无关。例如,以 SVC 模式运行的代码可以是 ARM 或 Thumb。这两种状态的主要区别在于指令集,ARM 状态下的指令始终是 32 位的,而 Thumb 状态下的指令是 16 位的(但也可以是 32 位的)。
ARM 版本的调用约定非常混乱,并非所有 ARM 版本都支持相同的 Thumb 指令集。在某些时候,ARM 引入了增强的 Thumb 指令集(Thumbv2),它允许 32 位 Thumb 指令甚至条件执行,这在之前的版本中是不可能的。为了在 Thumb 状态下使用条件执行,引入了“it”指令。然而,这条指令在后来的版本中被删除,并与一些本应不那么复杂的东西交换,结果适得其反。我不知道所有不同 ARM 版本的 ARM/Thumb 指令集的所有不同变体,老实说我不关心。你也不应该。您唯一需要知道的是目标设备的 ARM 版本及其特定的 Thumb 支持,以便可以调整代码。 ARM Infocenter 应该可以帮助您确定 ARM 版本的细节
如前所述,有不同的 Thumb 版本。不同的命名只是为了将它们彼此区分开来(处理器本身总是将其称为 Thumb)。
Thumb-1(16 位指令):用于 ARMv6 和更早的架构。
Thumb-2(16 位和 32 位指令):通过添加更多指令并允许它们为 16 位或 32 位宽(ARMv6T2、ARMv7)来扩展 Thumb-1。
ThumbEE:包括一些针对动态生成代码(在执行前不久或执行期间在设备上编译的代码)的更改和添加。
ARM 和 Thumb 的区别:
条件执行:ARM状态下的所有指令都支持条件执行。某些 ARM 处理器版本允许使用 IT 指令在 Thumb 中进行条件执行。条件执行导致更高的代码密度,因为它减少了要执行的指令数量并减少了昂贵的分支指令的数量。
32 位 ARM 和 Thumb 指令:32 位 Thumb 指令有一个 .w 后缀。
桶形移位器是另一个独特的 ARM 模式功能。它可用于将多条指令缩减为一条。例如,不是使用两条指令进行乘法(将寄存器乘以 2 并使用 MOV 将结果存储到另一个寄存器中),而是可以通过使用左移 1 -> Mov R1、R0、LSL 将乘法包含在 MOV 指令中#1; R1 = R0 * 2
要切换处理器执行的状态,必须满足两个条件之一:
我们可以使用分支指令 BX(分支和交换)或 BLX(分支、链接和交换)并将目标寄存器的最低有效位设置为 1。这可以通过将偏移量加 1 来实现,例如 0x5530 + 1。可能这会导致对齐问题,因为指令是 2 字节或 4 字节对齐的。但是因为处理器会忽略最低有效位。
如果设置了当前程序状态寄存器中的 T 位,我们就知道我们处于 Thumb 模式。
ARM指令集的介绍
本部分的目的是简要介绍ARM的指令集和它的一般用途。对我们来说,了解汇编语言的最小部分是如何运作的,它们是如何相互联系的,以及通过组合它们可以实现什么,这一点至关重要。
如前所述,汇编语言是由指令组成的,这些指令是主要的构建块。ARM指令后面通常有一个或两个操作数,一般使用以下模板。
由于ARM指令集的灵活性,并非所有指令都使用模板中提供的所有字段。然而,模板中字段的目的描述如下。
虽然MNEMONIC、S、Rd和Operand1字段是直截了当的,但条件和Operand2字段需要多加说明。条件字段与CPSR寄存器的值密切相关,或者准确地说,与寄存器中特定位的值密切相关。Operand2被称为灵活的操作数,因为我们可以以各种形式使用它--作为即期值(具有有限的值集)、寄存器或带移位的寄存器。例如,我们可以使用这些表达式作为Operand2。
作为一个快速的例子,让我们看看下面的指令清单。
作为一个简单的总结,让我们看看最常见的指令,我们将在未来的例子中使用。
MOV | 移动数据 | EOR | 亦或 |
MVN | 移动并求反 | LDR | 加载 |
ADD | 加 | STR | 存储 |
SUB | 减 | LDM | 加载多个 |
MUL | 乘 | STM | 存储多个 |
LSL | 逻辑左移 | PUSH | push到堆上 |
LSR | 逻辑右移 | POP | 从堆上pop出来 |
ASR | 算术右移 | B | 跳转 |
ROR | 向右旋转 | BL | 跳转并连接 |
CMP | 比较 | BX | 跳转并交换 |
AND | 与 | BLX | 跳转连接并交换 |
ORR | 或 | SWI/SVC | 系统调用 |
本文是ARM汇编系列教程的第3部分, 介绍arm的基本指令集,