ref:http://kmittal82.wordpress.com/2012/02/17/armthumbthumb-2/

A few months ago I gave a presentation titled “Introduction to the ARM architecture”. One of the most well received sections of that was a bit where I explained the difference between the various types of instruction sets that can be run on the ARM architecture, i.e. ARM (32 bit), Thumb (16 bit) and Thumb-2 (16/32 bit). I will try and explain the difference between the three in this post.

Before we begin, let’s look at a very simple test case which we will build for all three architectures (Thanks for my friend and colleague Stephen Wade for coming up with this test case)

typedef unsigned char uint8;
typedef unsigned short uint16;
/* r0 = x , r1 = a, r2 = b, r3 = c */
uint8 foo(uint8 x, uint8 a, uint16 b, uint16 c)
{
    if (a==2)
    {
        x += (b >> 8);
    }
    else
    {
        x += (c >> 8);
    }
    return x;
}

According to the ARM procedure call standard, the arguments to the function would be passed in registers r0-r3, with the return value passed in r0.

ARM

Each instruction in the ARM instruction set is 32 bits in size. At the same time, the ARM instructions have access to other useful features such as conditional instructions and in-line barrel shifter. Without access to conditional instructions, code needs to be handled by branching, which is more expensive. The in-line barrel shifter gives the instruction the ability to shift bits within the registers as part of the instruction itself, which eliminates the need for having separate instructions for shifting. Using RVCT, I compiled this for ARM state, and dumped the code with fromelf

1
2
3
4
5
0x00000000:    e3510002    ..Q.    CMP      r1,#2
0x00000004:    10800423    #...    ADDNE    r0,r0,r3,LSR #8
0x00000008:    00800422    "...    ADDEQ    r0,r0,r2,LSR #8
0x0000000c:    e20000ff    ....    AND      r0,r0,#0xff
0x00000010:    e12fff1e    ../.    BX       lr

First thing we notice here is that each instruction is 32 bits (or 4 bytes) wide based on the instruction encoding (second column from the left). Given that we have 5 such instructions, we have a code size of 20 bytes

Now, in the first line, r1 is compared to the integer value 2, which is the first thing that our function foo() does. Simple so far. The more interesting thing is the second and third instruction, which demonstrates conditional execution of instructions as well as the in-line barrel shifter.

The second instruction, in effect says “If the result of the previous comparison was a NE (not equal), then shift r3 by 8 bits to the right, add it to r0 and store the result back in r0″. This corresponds to the “else” part of the loop in our function. Not only did we manage to avoid a branch, we were also able to shift the bits and do the addition, all in one simple instruction. The third instruction is exactly the same, but deals with the “if” part of the loop.

The fourth instruction is again interesting. Since the return value of the function is of type unsigned char, only the bottom 8 bits are significant. So, we do an AND of the return value (stored in r0) with #0xff, which effectively zeros the top 24bits (by ANDing with 0), and now our return value is ready in r0.

The fifth and final instruction simply returns back to the caller.

Thumb

In Thumb state, each instruction is 16 bits in size, and very few instructions are conditional. Also, there is no access to the in-line barrel shifter, so separate instructions are needed for shifting bits. What this means in practice is that Thumb code would generally be slower to execute than ARM code (since more Thumb instructions might be needed to do the job than the number of ARM instructions), but it can help save code size. Building our example with “RVCT” and dumping using “fromelf”, we see the following code sequence#

1
2
3
4
5
6
7
8
9
10
_Z3foohhtt
    0x00000000:    2902        .)      CMP      r1,#2
    0x00000002:    d101        ..      BNE      {pc}+0x6 ; 0x8
    0x00000004:    0a11        ..      LSRS     r1,r2,#8
    0x00000006:    e000        ..      B        {pc}+0x4 ; 0xa
    0x00000008:    0a19        ..      LSRS     r1,r3,#8
    0x0000000a:    1808        ..      ADDS     r0,r1,r0
    0x0000000c:    0600        ..      LSLS     r0,r0,#24
    0x0000000e:    0e00        ..      LSRS     r0,r0,#24
    0x00000010:    4770        pG      BX       lr

Immediately, the first thing we notice is that all the instructions are 16 bits in size, as indicated by the instruction encodings (second column from the left). This here gives us a total code size of 9 x 2 = 18 bytes

When we start analysing the generated code, the drawback of Thumb state here is immediately apparent. Thumb only has access to conditional branches, so the generated code is done through branches. The second instruction branches to address 0×8 if the comparison in the first step was not equal (i.e. we enter the “else” part of our C++ code). At address 0×8, we notice the second drawback of the Thumb state, the lack of an in-line barrel shifter. A separate LSRS instruction shifts the bits in r3 by 8, and stores it in r1. Following that, this value is r1 is added to r0. Our return value is nearly ready, but we need to zero the top 24bits. The Thumb instruction set does not have access to AND, so it performs two shifts on r0, first shifting r0 by 24bits to the left (zeroing the bottom 8 bits), then shifting this further by 24 bits to the right (zeroing the top 24 bits). Similar code is generated for the “if” part of the code as well.

Thumb-2

Thumb-2 offers a “best of both worlds” compromise between ARM and Thumb, and aims to deliver the performance of ARM state code with the code density of Thumb state code. Thumb-2 has access to both 16 and 32 bit instructions, and even has support for conditional execution, albeit in the form of “If-then” (IT) constructs. Thumb-2 was first introduced as part of ARMv6-T2, and has subsequently been made the default thumb implementation for ARMv7.

So, lets build our example for Thumb-2 and analyse it as before. Note, I have built this by using the “-Otime” optimization in order to generate the IT constructs.

1
2
3
4
5
6
7
_Z3foohhtt
    0x00000000:    2902        .)      CMP      r1,#2
    0x00000002:    bf14        ..      ITE      NE
    0x00000004:    eb002013    ...     ADDNE    r0,r0,r3,LSR #8
    0x00000008:    eb002012    ...     ADDEQ    r0,r0,r2,LSR #8
    0x0000000c:    b2c0        ..      UXTB     r0,r0
    0x0000000e:    4770        pG      BX       lr

First thing we notice here is there is a mix of 32 bit and 16 bit instructions, as apparent by the instruction encodings (second column from the left). We see here that instead of all instructions being the same width, we have 4 instructions which are 16 bit, and 2 instructions which are 32 bits, giving us a code size of 16 bytes.

As seen, the second instruction is an ITE NE construct. This is not an instruction per se, but more of a heads up to the processor, instructing it that some conditional instructions need to be executed, and the first one of this will be based on the NE condition. What follows in instructions 3 and 4 is identical to what happened in ARM state code. Finally, the UXTB instruction is an instruction which extends (unsigned) the byte to a word, which in this case effectively zeros out the top 24 bits.

Remember

  • ARM instructions are all 32 bits in size, and have access to an in-line barrel shifter, as well as most instructions are conditional. This is best suited for performance sensitive code, where the code size does not matter
  • Thumb instructions are all 16 bits in size, and do not have access to an in-line barrel shifter, and neither are the instructions conditional. This is best suite for situation where code footprint needs to be minimised, albeit at the expense of performance (Having said that, Thumb code might give better performance results depending on the size of the cache and other factors)
  • Thumb-2 instructions offer a “best of both worlds” approach, and it utilizes both 16 and 32 bit instructions. Conditional execution of instructions is possible through IT constructs, although there a limit to the number of conditions which can be conditionally executed within the IT block.

[转]ARM/Thumb/Thumb-2的更多相关文章

  1. ARM 的Thumb状态测试

    作为一个使用ARM的学习者,有必要全面了解你的处理器内核.尽管有些内容可能在实际应用中用不到,但是“了解”还是很必要的.Thumb状态,是ARM的一个特色,但是你知道Thumb状态与ARM状态最大的区 ...

  2. 对于Android NDK编译器ARM和Thumb模式的理解

    编译NDK项目时,编译器无法识别arm汇编,设置LOCAL_ARM_MODE := arm后问题解决, NDK文档上对LOCAL_ARM_MODE的说明如下: LOCAL_ARM_MODE By de ...

  3. ARM处理器的寄存器,ARM与Thumb状态,7中运行模式

     ** ARM处理器的寄存器,ARM与Thumb状态,7中运行模式  分类: 嵌入式 ARM处理器工作模式一共有 7 种 : USR  模式    正常用户模式,程序正常执行模式 FIQ模式(Fast ...

  4. ARM处理器的寄存器,ARM与Thumb状态,7中运行模式 【转】

    转自:http://blog.chinaunix.net/uid-28458801-id-3494646.html ARM处理器工作模式一共有 7 种 : USR  模式    正常用户模式,程序正常 ...

  5. ARM ® and Thumb ®-2 指令系统

    指令表关键词        Rm {, <opsh>} 寄存器移位方式,将寄存器的移位结果作为操作数而Rm值保持不变       <Operand2> 灵活的使用第二个操作数. ...

  6. ARM状态和THUMB状态

    ARM处理器的工作状态 在ARM的体系结构中,可以工作在三种不同的状态,一是ARM状态,二是Thumb状态及Thumb-2状态,三是调试状态. <嵌入式系统开发与应用教程(第2版)>上介绍 ...

  7. 13 ARM指令集与Thumb指令集

    指令格式 ARM基本格式 <opcode>{<cond>}{S}{.W|.N}<Rd>,<Rn>{,<operand2>} opecode: ...

  8. iOS程序破解——ARM汇编基础

    原文在此:http://www.cnblogs.com/mddblog/p/4951650.html 一.Thumb指令与ARM指令 Thumb指令为16位,因此存储代码的密度高,节省存储空间.但是功 ...

  9. 原子操作--ARM架构

    说明:内核版本号为3.10.101 一.ARM架构中的原子操作实现 在原子操作(一)中我们已经提到,各个架构组织为“复仇者”联盟,统一了基本的原子变量操作,这里我们就拿atomic_dec(v)来看看 ...

随机推荐

  1. int有符号和无符号类型内存 -- C

    /* int 有符号 0xffffffff == -1 0xfffffffe == -2 最小 0x80000000 == -21 4748 3648 最大 0x7fffffff == 21 4748 ...

  2. 项目中经常使用的JS方法汇总,非常有用

    // 对Date的扩展,将 Date 转化为指定格式的String   // 月(M).日(d).小时(h).分(m).秒(s).季度(q) 可以用 1-2 个占位符,   // 年(y)可以用 1- ...

  3. 高性能网络server--I/O复 select poll epoll_wait之间的差

    一个.select 方式作为收集,最多只能监控1024描述叙事断裂的文件,内部使用位操作,相应的位置1或设置0,必须是可读.可写.三类除单独的事件,内部查询方法.将全部的套接字从内核到用户空间之间进行 ...

  4. 【高德API】如何利用MapKit开发全英文检索的iOS地图

    原文:[高德API]如何利用MapKit开发全英文检索的iOS地图 制作全英文地图的展示并不困难,但是要制作全英文的数据检索列表,全英文的信息窗口,你就没办法了吧.告诉你,我有妙招!使用iOS自带的M ...

  5. 【Head First Javascript】学习笔记0——自己制作chm参考手册素材

    变量声明:var 常量声明:const 数据格式转换: 1.转换函数 parseInt(A):把字符串A转换成整数:其中A为只包含数字的字符串 parseFloat(A):把字符串A转换成浮点数:其中 ...

  6. [CLR via C#]1.3 加载公共语言运行时

    原文:[CLR via C#]1.3 加载公共语言运行时 1. 你生成的每个程序集可以是EXE,也可以是DLL.最终都是有CLR管理这些程序集中代码的执行. 2. VS2010中,创建新的EXE项目时 ...

  7. Delphi三层网络架构代码实现

    Delphi三层网络架构代码实现 1 .三层网络的概念 三层架构(3-tier architecture) 通常意义上的三层架构就是将整个业务应用划分为: 表现层(UI).业务逻辑层(BLL).数据访 ...

  8. 一个完整的Installshield安装程序实例—艾泽拉斯之海洋女神出品(四) --高级设置二

    原文:一个完整的Installshield安装程序实例-艾泽拉斯之海洋女神出品(四) --高级设置二 上一篇:一个完整的安装程序实例—艾泽拉斯之海洋女神出品(三) --高级设置一4. 根据用户选择的组 ...

  9. 【Android平台安全方案】の #00-请不要在外部存储(SD卡)加密存储的敏感信息

    本文翻译自https://www.securecoding.cert.org/confluence/display/java/DRD00-J.+Do+not+store+sensitive+infor ...

  10. HEAP CORRUPTION DETECTED

    发生主要是由于这个问题给写入超出预分配的空间,注意检查越界情况 版权声明:本文博客原创文章,博客,未经同意,不得转载.