ARM语法 Part 3[ARM指令集]

  目录

ARM模式和Thumb模式

ARM处理器主要有两种工作模式(先不算Jazelle)-ARM状态和Thumb状态。这些状态模式与权限级别无关,它们主要区别是指令集,在ARM模式下指令集始终是32-bit,但是在Thumb模式下可以是16-bit或者32-bit。学会怎么使用Thumb模式对于ARM开发很重要。编写ARM壳代码时,我们需要避免NULL字节,使用16位Thumb指令而不是32位ARM指令可以降低这种风险。ARM各版本的调用规范容易让人混淆,不是所有的ARM版本都支持相同的Thumb指令集。后来,ARM 引入了增强的 Thumb 指令集(伪名称:Thumbv2),它允许 32 位 Thumb 指令甚至允许条件执行,在之前的版本中是不行的。为了在Thumb模式中支持条件执行,引入了“it”指令。但是,该指令随后又在更高版本中删除了,被一种更简单的方式所替换。不同ARM/Thumb指令集的有各种不同变体,一般不同关心这些。只需要知道的是你的目标设备的 ARM 版本及其特定的 Thumb 支持,然后再调整代码。ARM 信息中可以帮助您确定ARM 版本的细节(http://infocenter.arm.com/help/index.jsp)。

  • Thumb-1(16 位指令):在ARMv6和更早的体系结构中使用。
  • Thumb-2(16 位和 32 位指令):在Thumb-1基础上添加更多指令并允许它们为 16 位或 32 位宽(ARMv6T2、ARMv7)。
  • ThumbEE:更改和添加了一些支持动态生成代码的功能(在执行之前或执行期间在设备上编译代码)。

ARM模式和Thumb模式的态区别:

  • 条件执行:在ARM模式下所有的指令都支持条件执行。一些版本的ARM处理器可以通过it指令在Thumb工作模式下支持条件执行。

  • ARM和Thumb模式下的32-bit指令:在Thumb模式下的32-bit指令有.w后缀。

  • 桶型位移器(barrel shifter)是ARM模式下的另一个特点。它可以将多条指令缩减为一条。例如,你可以通过向左位移1位的指令后缀将乘法运算直接包含在一条MOV指令中(将一个寄存器的值乘以2,再将结果MOV到另一个寄存器):
    MOV R1, R0, LSL#1 ;R1 = R0 * 2,而不需要使用专门的乘法指令来运算。

    要切换处理器在其中执行的状态,必须满足以下两个条件之一:

  • 我们可以使用分支指令 BX(分支和切换状态)或 BLX(分支、链接和切换状态),并将目标寄存器的最小有效位设置为 1。可以通过偏移量加1来实现,例如0x5530+1。您可能会认为这将导致对齐问题,因为指令是 2 或 4 字节对齐的。这不是问题,因为处理器将忽略最低有效位。详见Part 6:条件执行和分支。

  • 如果当前程序状态寄存器的T位被置位,就说明工作在Thumb模式下。

ARM指令简介

本节简单介绍ARM指令集以及基本用法。了解汇编语言中的最小部分如何操作,它们之间如何衔接,它们之间能组合成什么样的功能。

ARM指令后面通常跟着两个操作数,像下面这样的形式:

MNEMONIC{S}{condition} {Rd}, Operand1, Operand2

由于ARM指令集的灵活性,并不是所有的指令都用到这些字段。这些字段的解释如下:

MNEMONIC     - 操作指令(机器码对应的助记符)。
{S}          - 可选后缀. 如果指定了该后缀,那么条件标志将根据操作结果进行更新。
{condition}  - 执行指令所需满足的条件。
{Rd}         - 目标寄存器,存储操作结果。
Operand1     - 第一操作数(寄存器或者立即数)
Operand2     - 第二操作数. 立即数或者带有位移操作后缀(可选)的寄存器。

MNEMONIC, S, RdOperand1字段比较明了,conditionOperand2字段需要再解释一下。condition字段与CPSR寄存器的值有关,准确的说是和CPSR某些位有关。Operand2也叫可变操作数,因为它可以有多种形式–立即数、寄存器、带有位移操作的寄存器。例如Operand2可以有以下多种形式:

#123                    - 立即数。
Rx                      - 寄存器x (如 R1, R2, R3 ...)。
Rx, ASR n               - 寄存器x,算术右移n位 (1 = n = 32)。
Rx, LSL n               - 寄存器x,逻辑左移n位 (0 = n = 31)。
Rx, LSR n               - 寄存器x,逻辑右移n位 (1 = n = 32)。
Rx, ROR n               - 寄存器x,循环右移n位 (1 = n = 31)。
Rx, RRX                 - 寄存器x,扩展的循环位移,右移1位。

让我们以一个简单的例子看一下这些指令的不同:

ADD   R0, R1, R2         - 将寄存器R1内的值与寄存器R2内的值相加,结果存储到R0。
ADD   R0, R1, #2         - 将寄存器R1内的值加上立即数2,结果存储到R0。
MOVLE R0, #5             - 仅当满足条件LE(小于或等于)时,才将立即数5移动到R0(编译器会把它看作MOVLE R0, R0, #5)。
MOV   R0, R1, LSL #1     - 将寄存器R1的内容向左移动一位然后移动到R0(Rd)。因此,如果R1值是2,它将向左移动一位,并变为4。然后将4移动到R0。

来快速总结一下,看一下后续示例中将涉及的一些常用指令:


文章作者: 改变世界
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 改变世界 !
评论