这是一篇围绕 iOS 来介绍 ARM 结构的文章,用词简单,逻辑清楚,偶见幽默。非开发者也值得一读,权当增长知识。

我在写「NEON on iPhone 入门」的时候,曾以为读者已经比较了解 iOS 设备的处理器知识。然而,看过网上的一些讨论,我才发现,原来这些知识并不普及,我的错。此外,我觉得了解这些东西对 iPhone 编程有益(不仅仅针对喜欢 NEON 的人),即便你用的是 Objective-C,虽然,不了解也无碍工作,但这些知识会让你成为一个更好的 iPhone 程序员。

基础

到目前为止,所有的 iOS 设备都使用 ARM 结构处理器,它和台式机上的 x86 和 PowerPC 有些不同,然而绝对不是「特殊」或「小众」的产品。几乎所有的手机(不只是智能手机)都基于 ARM,例如几乎所有的 iPod,几乎所有的 MP3 播放器,PDA 和 Pocket PC 更不用说了。任天堂从 GBA 开始转入 ARM,它甚至还侵入图形计算器的地盘,出现在一些德仪和惠普的计算器中。如果你还想继续溯本逐源,那么牛顿用的也是 ARM(苹果是 ARM 的早期投资者)。而且上面只说了一些小玩意,还有无数的 ARM 处理器运行在嵌入式系统中。

ARM 处理器因为低功耗和小尺寸而闻名,它的性能在同等功耗的产品中也很出色。这种结构(至少在 iOS 平台)使用小端(Little-endian)排序,就像 x86。它和 MIPS、PowerPC 一样,属于 32 位 RISC 结构。请注意,模拟器并不运行 ARM 代码,软件会被编译成 x86 可以运行的指令。因此接下来的内容适用于目标设备,而非模拟器。

ARMv7,ARM11,Cortex A8 和 A4,天哪!

多年来,ARM 结构演化出几个不同的版本,每一版都增加了新指令,在提升的同时保持了后向兼容的能力。初代 iPhone 使用了 ARMv6 结构的处理器(ARM 第六版的简称),而最新的 iPhone 4 支持 ARMv7。所以,编译代码的时候,依目标版本的指令集不同,生成不同的指令。汇编程序也一样,代码中使用的指令必须兼容特定的版本。最后,生成机器码,对应 ARMv6 或 ARMv7(或者 ARMv5 和 v4,不过 ARMv6 是 iOS 开发的底线,所以这两者就不用考虑了)。目标文件和可执行文件有标注自己对应的版本,可以通过运行 otool -vh foo.o 来查看。

不过呢,「初代 iPhone 4 搭载了 ARMv6 处理器」这种说法是错误的,因为 ARMv6 不是指特定的处理器,而是处理器可以运行的指令集。初代 iPhone 使用了 ARM 11 核心(确切说是 ARM1176JZF-S,不过这不重要,只要记得它是 ARM 11 家族的成员就行了),正如刚才提到的,这款处理器采用 ARMv6 指令集。之后的 iOS 设备仍采用 ARM11,直到 iPhone 3GS 发布,苹果开始尽数转向 Cortex A8 处理器核心(尽管尚不确定,但 iPhone 4 很可能用的就是 A8 )。这个核心采用了 ARMv7 指令集,或这么说,它支持 ARMv7。

我已经说过,不要在程序里植入设备判断代码,然后通过已知信息侦测设备所支持的 ARM 结构。这种代码极不可靠,而且运行在(软件完成后才发布的)新设备上会导致中断。所以请别这么做,否则我发誓,我会跑到你家里废了你。以上知识是为了让你粗略了解,有些设备支持 ARMv7,有些设备支持 ARMv6。至于如何侦测,我马上会谈到。

不过,你可能会想「iPad 和 iPhone 4 用的是 A4,不是 Cortex A8 吧?」不然,A4 其实是一个完整的单片系统(SOC),其中不只有 Cortex A8 内核,还包括了图形硬件、音视频编码加速器和其他数字模块。单片系统和处理器是两个很不相同的概念,处理器在硅片上甚至不占主要空间。

如果不懂得如何利用,即使设备支持 ARMv7 也无济于事。当然应用新的指令集也没有问题,但如果总是这么做,早先的设备就无法运行你写的代码了,我猜,这也许不是你想要的结果。那么,应该如何侦测设备所支持的结构呢?— 只有确定它是否支持 ARMv7 才能好好利用啊。答案是:没必要知道。相反,把代码编译两次,一次针对 ARMv6,另一次针对 ARMv7,接着把这两个可执行文件打包成一坨肥硕无比的二进制文件。好了,运行的时候,设备会自己决定打开哪一个更好。是的,Mach-O 不仅可以用来组合完全不同的 CPU 结构(例如 PowerPC 和 Intel),或者相同结构的 32 位和 64 位版本,它还可以对付同一种结构的 2 个变体,用 Mach-O 的术语来说,这叫 CPU 子类。从程序员的角度看,这么做的结果是:编译时决定一切。针对 ARMv6 编译的代码只运行在 ARMv6 设备上,同理,针对 ARMv7 编译的代码只运行在 ARMv7(或者更好)的设备上。

如果你读过了我写的 NEON 那帖,你也许会记得我推荐过一种在运行时(Runtime)中侦测和选择结构的方法。如果再去看,你会发现我已经把那部分移走了,现在,我不建议那么做,因为虽然这的确有用,但不能确保(或者说,所需技巧太复杂而不能确保不出错)在将来的 ARMv8 处理器上能够稳定运行。文档中是否有相关 API 的状态不重要(不在 iOS 的手册页中),如果你想在 ARMv6 上运行又希望利用 ARM7v,就用我刚才讲过的办法。

补充一点:在 iOS 环境下,ARM 结构不一定能反映处理器的型号。例如,对应 ARMv6 的 iOS 代码需要浮点指令的支持(VFPv2,准确的说),对 ARMv6 而言,虽然这是可选项,不过自从第一代 iPhone 发布以来就已经存在。所以,如果在 iOS 开发(例如编译器 -arch 设置或一个可执行文件的 CPU 子类)中提到了 ARMv6,就表示需要硬件浮点的支持。这对 ARMv7 和 NEON 也一样:虽然 NEON 实际上是 ARMv7-A 配置的一个可选项,但是因为它出现在所有支持 ARMv7 的 iOS 设备中,所以,提到 iOS NEON 即部分提到 ARMv7。

条件执行

ARM 结构一个实用的功能是,大多数指令可以有条件地执行 — 如果条件不满足,则指令无效。这可以缩短过程,让区块(Blocks)部署地更为有效。通常的办法是,如果区块不符合条件则跳过,但是通过把判断指令植入块内,省去了该步骤。

如果这仅仅是编译器用来提高代码效率的手段,我就不会在这里提到它了。虽然,这的确是它的一个功用,但之所以提到是因为,在调试(Debugging)时,它可能会令人吃惊。事实上,有时你会发现,调试器会进入状态为假的条件区块(if block,例如早期的错误回报),或者进入 if-else 的两个分支。这是因为,虽然代码尽数经过处理器,但是一部分没有实际执行,即条件执行。另外,如果你把断点置入这样的条件区块中,即使状态为假,它仍有可能执行。

话虽如此,但是在我有限的测试中,编译器似乎拒绝在调试配置中生成条件执行指令。因此它应该只发生在调试优化后的代码的时候,不幸的是,有时候你没得选择,只能这么做。

Thumb

Thumb 指令集是 ARM 指令集的一个子集,经过压缩,因此指令只有 16bits(所有 ARM 指令的大小都是 32bits,它仍然是 32 位结构,只是占用的空间少了)这不是一个全然不同的结构,而应将其视作常见 ARM 指令和功能的缩写。它的优点,显然是大为缩小代码尺寸,节约内存和缓存,以及代码带宽。虽然更适用于内存紧张的微控制器型应用程序,但是在 iOS 设备中,它仍然有用处,也因为如此,Xcode 默认在 iOS 项目中打开这项功能。虽然代码尺寸因此减少很多,但是不可能达到 50%,因为有时候完成一个 ARM 指令需要对应的两个 Thumb 指令。ARM 和 Thumb 指令不能随意混合,处理器需要针对二者切换不同的模式,而这只能在调用或从函数返回时发生。

当目标平台是 ARMv6 的时候,编译 Thumb 指令面临着很大的权衡取舍。ARMv6 的 Thumb 代码可以访问的寄存器较少,缺乏条件指令,特别是,它不能使用浮点硬件,例如浮点加法、减法、乘法等等。使用浮点 Thumb 代码必须调用系统函数,没错,听起来就像速度很慢的感觉。基于这个原因,针对 ARMv6 时,我建议禁用 Thumb 模式,但倘若你执意如此,请确保先分析代码。如果某些部分速度很慢,至少先试着禁用那部分 Thumb(很容易,在 Xcode 中使用命令行参数, -mno-thumb)。请记住,浮点运算在 iOS 中非常普遍,因为 Quartz 和 Core Animation 使用浮点坐标系统。

当目标变成了 ARMv7 的时候,所有这些缺点就消失了:ARMv7 包含 Thumb-2,它是 Thumb 指令的扩展集,增加了条件执行和可以访问所有 ARM 寄存器以及硬件浮点与 NEON 的 32 位 Thumb 指令。用 Thumb-2 缩减代码的代价几乎没有,所以最好是开着(如果关掉了请重新打开)。在 Xcode 的条件生成选项中,对 ARMv7 打开,对 ARMv6 关闭。

你也许在网上听到人们说,代码需要「互通」(Interworking)才能使用 Thumb,除非你想写汇编代码,否则不必担心,因为 iOS 平台的所有代码都是互通的。当显示汇编的时候,Shark 可能难以判断函数是 ARM 还是 Thumb。如果你看到无效或无意义的指令,最好互相对调一下。

对齐

iOS 支持非对齐访问,然而比起对齐访问,它的速度更慢,建议不要使用。在某些特殊情况下(涉及加载/存储多个指令,如果你有兴趣的话),非对齐访问的速度可能比对齐访问慢上百倍,因为处理器无法处理,而且必须请求操作系统的协助(参考此文,这和 PowerPC 上导致非对齐双精度浮点数变得超慢是同一个现象)。所以,要小心,而且,对齐仍然重要。

除法

这家伙总让每一个人吃惊。打开 ARM 结构手册(如果你还没有,请看「NEON on iPhone 入门」的结构概览那节),找到整数除法指令。去吧,我等你。找不到?正常正常,根本没有的。是的,ARM 结构不支持硬件整数除法,必须通过软件执行。如果你编译下面的代码:

int ThousandDividedBy(int divisor) {     return 1000/divisor; }

在汇编代码中,你会看到编译器插入了一个调用函数的「___divsi3」— 这是一个系统函数,用来执行软件除法(注意,除数不能恒定,否则除法可能会被转换为乘法)。这意味着,在 ARM 上,整数除法实际代表了操作系统的性能。

「不过,」看完手册归来,你也许会说:「你错啦!里面有 ARM 除法指令,甚至还有两个呢!在这里,sdiv 和 udiv!」不好意思给您颇凉水啦,这些指令只可用于 ARMv7-R 和 ARMv7-M 配置(分别指实时和嵌入式环境 — 例如马达的微控制器和手表),iOS 设备用的 ARMv7-A 不支持,很抱歉!

GCC

GCC 生成的 ARM 代码质量之糟已不是秘密。在其他一些基于 ARM 的平台上,专业开发者使用 ARM 自家提供的工具链 — RVDS。不过,RVDS 不支持 OSX 用的 Mach-O 运行时,只支持 ELF 运行时,所以在 iOS 平台上没辙。但至少还有 GCC 的替代品,比如现在可以用 LLVM。虽然我没怎么测试,但是当使用 LLVM 的时候,至少看到了 64 位整数码的显著改进(这一点,GCC 在 ARM 上尤其弱)。假以时日,LLVM 全面超越 GCC 可以指望。

你瞧,现在你是更好的 iOS 开发者了!

[原文链接;作者: Pierre Lebeaupin]

转载于:https://www.cnblogs.com/shenfei2031/archive/2010/11/08/1871990.html

iOS 开发者应该知道的 ARM 结构(转自apple4us)相关推荐

  1. 每一位Android开发者应该知道的Android体系架构和开发库

    Android的体系架构鼓励组件重用,允许开发者发布共享Activity.Service并且访问其他应用程序的数据,还可以根据开发者制定的安全限制进行管理.话虽如此,今天我将分享一些关于Android ...

  2. iOS 开发者必知的 75 个工具(译文)

    如果你去到一位熟练的木匠的工作室,你总是能发现他/她有一堆工具来完成不同的任务. 软件开发同样如此.你可以从软件开发者如何使用工具中看出他水准如何.有经验的开发者精于使用工具.对你目前所使用的工具不断 ...

  3. iOS 开发者必知的 75 个工具

    学个新东西不容易呀,这么多东西要掌握 原文地址:http://benscheirman.com/2013/08/the-ios-developers-toolbelt (需翻墙) 如果你去到一位熟练的 ...

  4. 开发者需要知道的iOS 9 SDK新特性

    2019独角兽企业重金招聘Python工程师标准>>> 一.iPad多任务功能增强 1.全新的多任务界面 在iOS 9中,多任务界面从原来的横向单层排列进化成层叠排列,从而减少滚屏手 ...

  5. 信息图:iOS 7开发者需要知道的事

    如果你想为iOS 设备开发app,你需要知道如何与软件交互,如何设计,你还要知道苹果独特的开发理念和开发工具.真正的能力还需要成功地从其他行业领域借鉴核心概念.最后把所有这些东西糅合进你的信息库中. ...

  6. ?Web开发者需要知道的CSS Tricks

    作为一名Web开发者,CSS是必备技能之一,我一直以为自己对CSS的掌握已经够用了,直到读Lea Verou的<CSS揭秘>时,我发现自己充其量就算个会打CS的选手,书中针对我们常见的网页 ...

  7. 苹果强制使用HTTPS传输后APP开发者必须知道的事

    2017年1月1日起,苹果公司将强制使用HTTPS协议传输.本文通过对HTTPS基础原理和通信过程内容的讲解,介绍APP开发者在这个背景下的应对办法. 几周前,我们在<https大势已来?看腾讯 ...

  8. 苹果强制使用HTTPS传输了怎么办?——关于HTTPS,APP开发者必须知道的事

    WeTest 导读 2017年1月1日起,苹果公司将强制使用HTTPS协议传输.本文通过对HTTPS基础原理和通信过程内容的讲解,介绍APP开发者在这个背景下的应对办法. 几周前,我们在<htt ...

  9. python 3.9特性,开发者应该知道的Python 3.9新特性

    导读:Python 3.9来了,有哪些新特性值得学,值得用? Python 2.9(5.10.2020)已经发布了一段时间,最后一个Alpha版(3.9.0a5)近期发布了测试版.开发者应该看新版有哪 ...

  10. 前端开发者应该知道的 Centos/Dokcer/Nginx/Node/Jenkins 操作( 长文)

    服务器作为开发的一环,并且现在非常多的商业公司部署在生产环境上的服务器都是CentOS系统! 让我们了解了解也在情理之中! 作为前端开发者,我们应该跳出自己的一亩三分地,跳出舒适区.扩大自己的技术广度 ...

最新文章

  1. Python Qt GUI设计:QSpinBox计数器类(基础篇—15)
  2. 全了!从Python入门到精通
  3. [转]arm汇编相关链接
  4. python 判断字母大小写
  5. robot framework环境搭建(转)
  6. Android的第一个程序
  7. WinForm LED循环显示信息,使用定时器Threading.Timer
  8. 努比亚修复工具_努比亚 X6 救砖教程 努比亚 NX601J恢复救砖教程
  9. 计算机辅助设计与制造实例教程答案,计算机辅助设计实例教程= Example Course of Computer Aided Design...
  10. 进化计算(七)——MOEA/D算法详解
  11. 解决【C++】其他类中友元函数不可访问私有数据--顺序问题
  12. 关于Bundle Adjustment(BA)的直观理解
  13. [生存志] 第48节 叔向忧羊舌
  14. linux配置ftp错误530,ubuntu16安装配置ftp服务(和530错误解决)
  15. 关于阿里云服务器可以怎么选择地域
  16. 如何指定网站内搜索关键字(借用已有搜索引擎)
  17. 用计算机能改装成万用表吗,电脑机箱风扇改装成DIY空调扇USB风扇
  18. 刷题总结——regular words(hdu1502 dp+高精度加法+压位)
  19. 2020史上最全的Android面试题集锦
  20. 用计算机打开密码,电脑开机密码怎么设置?

热门文章

  1. LC-3下汇编实现简易版四子棋的游戏
  2. 【linux命令】cp复制命令
  3. 集合的基本运算及文氏图
  4. hive中的TextFile转为SequenceFile
  5. NSIS “Win32 Error,Code:740 ,请求的操作需要提升”错误解决方法
  6. 【linux】按键盘Backspace键终端出现^H
  7. 世界上第一个徒步环球旅行的人
  8. 分享五个绝对称得上妖艳古怪精灵的前端代码效果
  9. MongoDB Bulk write operation error on server duplicate key error问题解决
  10. 【python文字游戏】飞花令