【问题标题】:arm and thumb instruction set手臂和拇指指令集
【发布时间】:2012-12-05 14:52:46
【问题描述】:

如何区分手臂指令和拇指指令?例如:

add r1, r2, r3 ;add r2 and r3, then store the result in r1 register

上述指令在手臂和拇指指令方面如何工作?

【问题讨论】:

  • 你问他们有什么不同吗?或者如果它们不同?或者他们如何做加法?你的实际问题我不清楚。 :-)

标签: arm


【解决方案1】:

请访问 infocenter.arm.com 并获取相关架构的架构参考手册,或者仅获取 ARMv7 手册(不是 -M,而是 -A 或 -R),其中将包含迄今为止的所有指令编码从 ARMv4 到 ARMv7,包括 thumb 和最成熟的 thumb2 扩展。 (您可能需要多个架构参考手册和/或技术参考手册,因为 arm 手册中的指令编码会受到影响)

在 thumb 指令下查看基于寄存器的 ADD 指令,有一种编码,具有三个寄存器编码 T1,它被列为所有 thumb 变体(ARMv4T 到现在(ARMv4T、ARMv5、ARMv6、ARMv7 和可能的 ARMv8))

位 15 到 9 是 0b0001100 rm 的 3 位、rn 的 3 位和 rd 的 3 位(通常 thumb 指令仅限于 r0-r7 需要 3 位进行编码,thumb2 扩展和一些特殊的 thumb 指令允许更高编号寄存器(四位编码))。

该指令在说明中列为 ADDS rd,rn,rm,S 表示保存标志,它来自于衍生 thumb 指令的父 ARM 指令,对于 ARM 指令,您可以选择是否修改标志, thumb 指令你没有(thumb2 有办法控制它,但它有限制(对于添加指令)。

添加 rd,rn,rm

0001100 rm rn rd

所以 ADDS r1,r2,r3 就是这块比特

0001100 011 010 001 = 0001100011010001 = 0001 1000 1101 0001 = 0x18D1

查看 ARM 模式下的 ADD 指令,你从一个条件字段开始,因为你已经写了你的问题,这是一个 ALWAYS 或 1110 模式(总是执行),也因为你写了你写的问题 add not added so not保存标志,因此编码中的 s 位为零

所以添加 rd,rn,shifter 操作数,我们从位模式 0b111000I01000 开始,然后是四个 rn 位 rm 4 位,移位器操作数 11 位。是的,这是一个我位位置 25 不是一个。 I 是移位器操作数编码的一部分

现在转到手册中描述移位器操作数编码的部分。只是一个寄存器 rm 的编码是第 25 位(I 位)为零,11 到 4 为零,3 到 0 为 rm 所以添加 rd,rn,rm

1110 00 0 01000 转 00000 000 转

1110 00 0 01000 0001 0010 00000 000 0011 = 1110 0000 1000 0001 0010 0000 0000 0011 = 0xE0812003

现在我们可以测试一下,拿这个程序

add r1,r2,r3
.thumb
add r1,r2,r3

称它为 add.s 组装然后反汇编

arm-none-eabi-as add.s -o add.o
arm-none-eabi-objdump -D add.o 

得到

Disassembly of section .text:

00000000 <.text>:
   0:   e0821003    add r1, r2, r3
   4:   18d1        adds    r1, r2, r3

与手编码匹配。

现在,如果您尝试反汇编一大块不知道它们是什么类型的字节,那就另当别论了,这充其量是非常困难的,理想情况下,您希望通过执行和反汇编整个二进制文件模式更改(如果不模拟执行,您可能无法弄清楚)。一条线索是 ARM 指令通常使用 ALways 条件,即指令开头的 0xE,因此如果您看到大量 0xExxxxxxx 形式的 32 位字,则这些字很可能是 arm 指令,而不是数据,而不是 thumb 指令。纯拇指将有一个不太典型的模式,比如 0x6xxx 和 0x7xxx,但也有所有其他起始值的混合。 Thumb2 扩展可以从任一半字边界开始,并且对于 32 位字具有更独特的开始模式,但是因为它们与非 Thumb2 扩展混合并且并不总是在 32 位边界上对齐,所以无论有无 thumb2 扩展,在视觉上都不太容易与数据隔离,只有 ARM 指令易于在视觉上隔离。

【讨论】:

  • +1,很好的答案。我正在尝试不同的东西。我正在用“gcc -mthumb”编译add.s,但它仍然没有创建拇指二进制文件。你知道为什么吗?
  • 请注意我的代码中的 .thumb 告诉汇编器后面的代码是 thumb。 .code 32 告诉汇编器代码是 arm。还有常见的语法内容和其他您可以自己查找的内容。另请注意,我使用 gnu 汇编器而不是 gnu C 编译器来汇编汇编语言。 (as 而不是 gcc)即使 gcc 将其传递给 as,也可能存在预处理,并且体验可能与直接组装不同。
  • 我刚刚注意到elf文件中arm/thumb之间的其他差异。如果你 readelf -s add.o,在 .symtab 中你会得到 $a 或 $t 取决于编码,请参阅 sourceware.org/binutils/docs/as/ARM-Mapping-Symbols.html
【解决方案2】:

在实践中,没有理由将库编译为 arm,除非您有意选择让一切变得更难。

在 arm 和 thumb 模式之间切换需要一些纳秒,它有硬件支持,顺便说一下,比在内核模式和用户模式之间切换要快得多。

如果你问我为什么 Google 的整个库都是 arm,我会告诉你,尽管他们应该保持东西向后兼容和一致,但绝对没有理由。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-06
    • 1970-01-01
    • 2015-07-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多