文章目录
- ARM & Thumb
- ARM和Thumb之间的区别:
- ARM指令简介
ARM & Thumb
ARM处理器有两种主要状态可以运行(ARM和Thumb)(在这里不包括Jazelle)。这些状态与特权级别无关。例如,以SVC模式运行的代码可以是ARM或Thumb。这两种状态之间的主要区别是指令集,其中ARM状态下的指令始终为32位,Thumb状态下的指令为16位(但可以为32位)。知道何时以及如何使用Thumb对于我们的ARM利用开发目的尤其重要。在编写ARM shellcode时,我们需要摆脱NULL字节,而使用16位Thumb指令而不是32位ARM指令会减少使用它们的机会。
ARM版本的调用约定不仅令人困惑,而且并非所有ARM版本都支持相同的Thumb指令集。在某个时候,ARM引入了增强的Thumb指令集(伪名:Thumbv2),该指令集允许32位Thumb指令甚至条件执行,而在此之前的版本中是不可能的。为了在Thumb状态下使用条件执行,引入了“ it”指令。但是,此指令在以后的版本中被删除,并交换了一些本应使事情变得不那么复杂的东西,但是却达到了相反的目的。我不知道在所有不同的ARM版本中ARM / Thumb指令集的所有不同变体,老实说我不在乎。你也不应该 您唯一需要知道的是目标设备的ARM版本及其特定的Thumb支持,以便您可以调整代码。ARM信息中心应帮助您确定ARM版本的详细信息(http://infocenter.arm.com/help/index.jsp)。
如前所述,有不同的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模式的另一个独特功能。它可以用于将多个指令缩小为一个。例如,您可以使用左移1-> Mov R1,R0,LSL,而不是使用两条指令进行乘法运算(将寄存器乘以2并使用MOV将结果存储到另一个寄存器中),而不是在MOV指令中包含乘法#1; R1 = R0 * 2
要切换处理器执行的状态,必须满足以下两个条件之一:
- 我们可以使用分支指令BX(分支和交换)或BLX(分支,链接和交换)并将目标寄存器的最低有效位设置为1。这可以通过在偏移量上加1来实现,例如0x5530 + 1。可能会认为这将导致对齐问题,因为指令是2字节或4字节对齐的。这不是问题,因为处理器将忽略最低有效位。有关更多详细信息,请参见 第6部分:条件执行和分支。
- 我们知道,如果当前程序状态寄存器中的T位置1,则我们处于Thumb模式。
ARM指令简介
这部分的目的是简要介绍ARM的指令集及其一般用法。对于我们而言,至关重要的是要了解最小的汇编语言是如何工作的,它们如何相互连接以及将它们组合起来可以实现什么。
如前所述,汇编语言由指令组成,而指令是主要的构建块。ARM指令通常后跟一个或两个操作数,并且通常使用以下模板:
MNEMONIC {S} {condition} {Rd},Operand1,Operand2
由于ARM指令集的灵活性,并非所有指令都使用模板中提供的所有字段。但是,模板中字段的用途描述如下:
MNEMONIC -指令的简称(助记符)
{S} -可选的后缀。如果指定了S,则根据操作结果更新条件标志
{condition} -执行指令需要满足的条件
{Rd} -用于存储指令结果的寄存器(目标)
Operand1 -第一个操作数。寄存器或立即值
Operand2 -第二个(灵活的)操作数。可以是立即数(数字)或带可选移位的寄存器
虽然MNEMONIC,S,Rd和Operand1字段很简单,但condition和Operand2字段需要更多说明。条件字段与CPSR寄存器的值紧密相关,或者确切地说,与寄存器内特定位的值紧密相关。Operand2之所以称为灵活操作数,是因为我们可以以各种形式使用它-作为立即值(具有有限的一组值),寄存器或带移位的寄存器。例如,我们可以将这些表达式用作Operand2:
#123 -立即值(一组有限的值)。
Rx -寄存器x(如R1,R2,R3 ...)
Rx,ASR n -寄存器x算术右移n位(1 = n = 32)
Rx,LSL n -逻辑x左移n位的寄存器x(0 = n = 31)
Rx,LSR n -寄存器x的逻辑右移n位(1 = n = 32)
Rx,ROR n -向右旋转n位的寄存器x(1 = n = 31)
Rx,RRX -寄存器x向右旋转一位,扩展
作为一个简短的示例,说明了不同种类的指令的外观,让我们看一下以下列表。
ADD R0, R1, R2 -将R1(Operand1)和R2(Operand2以寄存器形式)的内容相加并将结果存储到R0(Rd)中
ADD R0, R1, #2 -将R1(Operand1)和值2(Operand2以立即值形式)的内容相加并将结果存储到R0(Rd)中
MOVLE R0, #5 -仅在满足条件LE(小于或等于)的情况下,将数字5(Operand2,因为编译器将其视为MOVLE R0,R0,#5)移动到R0(Rd)。
MOV R0, R1, LSL #1 -将R1的内容(逻辑左移的寄存器形式的操作数2)左移一位至R0(Rd)。因此,如果R1的值为2,则将其左移一位并变为4。然后将4移至R0。
作为一个简短的摘要,让我们看一下将在以后的示例中使用的最常见的说明。
操作说明 | 描述 | 操作说明 | 描述 |
MOV | 移动数据 | EOR | 按位异或 |
MVN | 移动并取反 | LDR | 加载 |
ADD | 加法 | STR | 储存 |
SUB | 减法 | LDM | 加载多个 |
MUL | 乘法 | STM | 储存多个 |
LSL | 逻辑左移 | PUSH | 推入堆栈 |
LSR | 逻辑右移 | POP | 弹出堆栈 |
ASR | 算术右移 | B | 分支 |
ROR | 右旋 | BL | 分支使用链接 |
CMP | 比较 | BX | 分支与交换 |
AND | 按位与 | BLX | 分支使用链接和交换 |
ORR | 按位或 | SWI / SVC | 系统调用 |