Osheep

时光不回头,当下最重要。

iOS - 了解ARM架构

在网上看到一篇关于ARM的介绍(比较老了),比较基础,容易理解。遂做了下翻译,加深下自己对ARM的了解。虽然开发中不太接触,但是觉得了解下还是比较有意义的。当然如果是做逆向,那就另当别论了: )

原文

概述

发布至今的iOS设备中的处理器都是基于ARM架构的。你会发现,这个架构和一些用于桌面设备的x86或者是PowerPC架构有些不一样。然而,这并不是什么特别的架构,且应用广泛:几乎所有移动电话(不只是智能电话)都是基于ARM架构的;几乎所有的iPods,以及MP3,PDA和PocketPC设备通常都是基于ARM的;任天堂自GBA以来的便携设备也是基于ARM的。还有目前正在使用的部分TI和HP型号的图形识别计算器也在使用它;(事实上,苹果是ARM较早的投资方)。这还只是一小部分,还有无数的ARM处理器用在嵌入式设备上。

ARM处理器因小尺寸、低功耗、性能强的特点而闻名。ARM架构是小端(little-endian)即低位字节排在内存的低地址端(至少在iOS平台是这样),和x86一样。它和MIPS、PowerPC等一样用的都是RISC,并且很长时间都是32位,但是后来有了叫做ARM64的64位扩展。

特别要注意一点,模拟器不会执行ARM代码,因为用模拟器的时候编译的是x86的代码,是用于在mac上本地执行的。

ARM的版本

ARMv7, ARM11, Cortex A8 and A4
随着时间的推移ARM架构推出了一系列不同的版本,每个版本都添加了一些新指令和改进,同时向后兼容前一个版本。第一台iPhone包含了一个实现了ARMv6的处理器,后来的设备包含了支持ARMv7的处理器。所以当你编译代码时,根据你指定目标架构版本,编译器会生成架构版本相对应的指令。汇编程序也是一样,编译器会检查所使用的指令是否包含在所指定的架构版本中。最终,你会获得针对指定架构生成的目标代码。目标文件和可执行文件实际上会被标记上他们所针对的架构,可以使用如下命令来检查目标文件所使用的架构版本。

$ otool -vh foo.o

不要把ARMv6\ARMv7 和 ARM6\ARM7搞混了,后者是老的ARM处理器型号,而前者是架构版本。

处理器核心和芯片系统(Soc)

然而,我们并不能说iPhone有一个”ARMv6的处理器”,因为ARMv6并不是指一个特定的处理器,只是说处理器能够运行这个架构的指令集,而并没有做任何特定的实现。用于最早的iPhone的处理器核心是通过ARM11实现的。正如之前所提到的,这个处理器实现了ARMv6。随后的设备使用过ARM11,直到iPhone 3GS为止,它使用的是Cortex A8处理器核心。再后来iOS的设备开始使用更加神秘的,由苹果自己的相关部门研发设计的处理器。如果你想知道某台设备使用了哪个处理器,可以参考iOS Support Matrix

你可能会说iPad和iPhone4都是A4的处理器,而不是Cortex A8!恩。。A4实际上是指芯片上的整个应用系统(每个芯片都有一个芯片系统),它包含的不单单是CortexA8核心,同样也包含图形硬件,以及视频和音频解码器加速器,和其他的数字模块。芯片系统和处理器核心是有很大区别的,处理器核心不会占用晶片的绝大部分空间。

那么你该怎么检测设备所支持的架构版本,以便于你可以利用ARMv7的特性(如果有的话),亦或者你想防止你的代码运行在老设备上。BUT,你不需要这么做。因为你的代码编译了两次,一次是针对ARMv6的,一次是针对ARMv7的,两个可执行文件会一起放到一个fat binary文件中(fat binary是一个包含多种类型处理器指令集的文件),并且在运行的时候设备会自己选择他所支持的那部分执行。是的,Mach-O fat binary不只是为了区分不同的处理器架构(比如,PowerPC和Intel,生成的是一个通用的二进制文件),或者一个架构下的32位和64位,而且还有同个架构下的两个变体(CPU的子类型,从Mach-O层面看)。从一个程序员的角度看,这每件事都是在编译时决定的。

条件执行

ARM架构的一个有趣的特性是,大多数指令都是条件执行的,如果条件为假,指令就没有效果。这就能允许简短的if代码块实现得更有效,通常的方法是当if条件为假则跳到代码块之后,但是现在代码块中的指令已经被条件化了,节省一个分支。

如果使代码更高效只是由于编译器的一个特性我就不会提及这个,而我现在提及它是因为在调试时这可能会让你觉得奇怪。事实上,有时候当你知道if代码块条件为假,但你仍然看到debugger进去了,或者if-else两个代码块都进了!这是因为处理器虽然经过了代码块里的代码,但是实际上不会执行,原因就是代码块被条件化了,判断的是代码块本身。

ARM64消除了条件执行(只有几个简单的指令仍然可以条件执行)

Thumb

Thumb指令集是ARM指令集的一个子集,指令被压缩到了16位(所有ARM指令都是32位的,Thumb仍旧是32位的架构,只是指令所占用的空间小了)。这并不是一个不同的架构,而应该看作是大多数常用ARM指令和功能的一个简写。优势很明显,能减少代码的占用空间,节省内存,缓存以及代码带宽。这对一些微控制器类型的应用是非常有用的。在iOS设备中也同样有用,在Xcode中默认是启用Thumb指令的。代码尺寸减小这点不错,但是并没有达到缩小50%的效果,因为有时候一个ARM指令需要两条Thumb指令来完成。ARM和Thumb指令不能混合,处理器在从执行一个到另一个指令时需要切换模式,这只会在调用函数和函数返回时发生。

ARMv7包含Thumb-2,一个Thumb指令集的扩展,添加了支持条件化执行和32位的Thumb指令,这就能允许访问所以ARM寄存器。这相当于无损耗得缩小了代码的大小,但是在ARMv6上Thumb的表现会有些缺点,所以在Xcode的build settings中使用条件来设置在ARMv7下启用(现在应该没有这种问题)。ARM64是一个新的指令集,所有指令还是32位的。

对齐

关于对齐,只有一点要说的,在iOS平台上支持不对齐的访问,但是肯定比对齐的访问要慢,慢很多。要想具体了解的,可以参考这篇

以上就是对ARM架构大体的介绍,希望对你有帮助。

点赞