我对ARM编程很新。我注意到有几种架构,如ARMv4,ARMv5,ARMv6等。这些架构有什么区别?他们有不同的指令集或行为吗?
最重要的是,如果我为ARMv6编译一些C代码,它会在ARMv5上运行吗?在ARMv6上运行的ARMv5代码怎么样?或者,如果我编写内核汇编代码,我是否只需要担心差异?
答案 0 :(得分:35)
ARM世界有点混乱。
对于C程序员来说,事情很简单:所有ARM架构都提供常规的32位平面寻址编程模型。只要您使用C源代码,您可能会看到的唯一区别是有关字节序和性能的信息。大多数ARM处理器(甚至旧型号)都可以是big-endian和little-endian;然后由逻辑板和操作系统做出选择。好的C代码是 endian neutral :它编译并正常工作,无论平台字节顺序如何(字节序中立性对可靠性和可维护性有好处,但对性能也有好处:非中性代码是访问相同的代码数据通过不同大小的指针,这会严重破坏编译器用来优化代码的严格别名规则。)
如果你考虑二进制兼容性(即重用已经编译过一次的代码),情况就完全不同了:
给定处理器可以实现多个指令集。只知道ARM代码的最新处理器是StrongARM,这是一个已经相当陈旧(15年)的ARMv4代表。 ARM7TDMI(ARMv4T架构)同时了解ARM和Thumb,几乎所有后续ARM系统(Cortex-M除外)都是如此。 ARM和Thumb代码可以在同一个应用程序中混合在一起,只要在约定更改的地方插入适当的粘合剂;这称为 thumb interworking ,可以由C编译器自动处理。
Cortex-M0只知道Thumb指令。它知道一些扩展,因为在“普通”ARM处理器中,操作系统必须使用ARM代码(用于处理中断);因此,Cortex-M0知道几个Thumb-for-OS的东西。这与应用程序代码无关。
其他Cortex-M只知道Thumb-2。 Thumb-2 主要向后兼容Thumb,至少在汇编级别。
因此,如果使用编译器开关编译某些代码,告知这是针对ARMv6的,那么编译器可能会使用ARMv6中的少数指令而不是ARMv5。这是在几乎所有平台上遇到的常见情况:例如,如果您使用-march=core2
标志在PC上使用GCC编译C代码,则生成的二进制文件可能无法在较旧的Pentium处理器上运行。 / p>
调用约定是一组规则,它们指定函数如何交换参数和返回值。处理器只知道它的寄存器,并且没有堆栈的概念。调用约定告诉参数进入哪些寄存器,以及它们是如何编码的(例如,如果有char
参数,它进入寄存器的低8位,但调用者应该清除/符号扩展高24位,还是没有?)。它描述了堆栈结构和对齐。它规范了对齐条件和结构域的填充。
ARM有两种主要约定,称为ATPCS(旧)和AAPCS(新)。它们在浮点值方面有很大不同。对于整数参数,它们大多数相同(但AAPCS需要更严格的堆栈对齐)。当然,约定取决于指令集和Thumb交互的存在。
在某些情况下,可能会有一些符合ATPCS和AAPCS的二进制代码,但这不可靠,并且没有不匹配的警告。所以底线是:你不能在使用不同调用约定的系统之间实现真正的二进制兼容性。
ARM体系结构可以使用可选元素进行扩展,这些元素将自己的指令添加到核心指令集。 FPU是一个可选的协处理器(在实践中很少遇到)。另一个协处理器是NEON,这是一些较新的ARM处理器上的SIMD指令集。
使用协处理器的代码不会在不具有协处理器功能的处理器上运行,除非操作系统捕获相应的操作码并在软件中模拟协处理器(这或多或少是使用浮点参数时发生的情况) ATPCS调用约定,它是慢)。
总而言之,如果你有C代码,那么重新编译它。不要尝试重用为其他架构或系统编译的代码。
答案 1 :(得分:5)
想想这个ARM与ARM之类的东西,比如wintel计算机和intel mac。假设你在两台计算机上都拥有相同的intel芯片(系列),那么你的C代码的一部分可以编译一次并在两个处理器上运行就好了。您的程序变化的位置和原因与英特尔处理器无关,但与其周围的芯片和主板以及本案例中的操作系统有关。
对于ARM与ARM,大多数差异不是核心,而是围绕核心的供应商特定逻辑。所以这是一个加载的问题,如果你的C代码是一些应用程序调用标准的api调用,那么它应该在arm或intel或powerpc或其他任何东西上编译。如果您的应用程序与片上或板载外设进行通信,那么无论处理器类型是什么,一块板,一块芯片都会有所不同,因此必须为该芯片或主板编写C代码。如果为ARMv6编译二进制文件,它可以并且将在ARMv4上具有未定义的指令并将导致异常。如果为ARMv4编译,ARMv6应该运行得很好。
充其量,如果您在此应用程序领域,那么您可能会看到的只是性能差异。其中一些与您在编译器选项中的选择有关。有时你可以帮助你的代码。我建议尽可能避免分裂和浮点。我不喜欢乘法,但如果推动,将采取乘法而不是除数。 x86已经让我们破坏了未对齐的访问,如果你现在开始使用对齐的I / O,当你进入其他更喜欢对齐访问的芯片时,它会为你节省时间,或者你会得到各种各样的操作系统和bootloaders配置ARM进行响应,这些都不是你在x86上习惯的。同样保持这种习惯,你的x86代码运行得更快。
获取ARM ARM的副本(谷歌:ARM架构参考手册,你可以免费下载很多地方,我不知道当前的转速是什么,转换我或者其他什么)。浏览ARM指令集,看到所有内核都支持大多数指令,有些指针随时间增加,如divide和byteswap等。你会发现内核之间没有什么可担心的。
从系统角度思考,wintel与intel mac。 ARM不制造芯片,制造和许可核心。在他们的芯片中使用ARM的大多数供应商都有自己的特殊酱。所以它就像wintel与mac在中间使用相同的处理器,但在涉及处理器接触和必须使用的所有东西时完全不同。它并不止于ARM内核,ARM销售外围设备,浮点单元,缓存等。例如,如果有任何ARMv4是相同的那么少。如果您的代码触及差异,那么如果您不知道,那么您将遇到问题。
除了ARM ARM之外,对于芯片的臂部分,还有TRM(技术参考手册)。但如果你使用它的组件得到错误的trm可能会让你头疼。 TRM可能有寄存器描述和ARM ARM没有的其他东西,但是如果你住在应用程序空间中,你可能不需要它们,也不需要ARM ARM。如果没有别的,ARM ARM很适合教育目的。了解您可能不想分割或使用未对齐访问的原因。
答案 2 :(得分:4)
最大的不同来自:
答案 3 :(得分:3)
如果差异对您来说非常重要,那么您应该能够从ARM的公开文档中找到它。
但是用更高级别的语言写作的整个观点(即使它只是像C一样“高”)是不担心它。您所做的就是重新编译。即使在内核中,也没有那么多真正需要在汇编中编写;当你必须在汇编中写一些东西时(即不仅仅是为了获得最大的性能),它通常不仅仅是因为CPU的选择(例如直接在内存映射的地方?)。
答案 4 :(得分:2)
通常在架构之间移植时要检查的区域的快速和脏的列表: