电子说
我之前写过关于编写代码和设计数据结构以优化嵌入式系统中的代码大小、性能和功率时可以采取的步骤。这种压缩软件以适应的需求在早期计算机上很常见,但现在在具有千兆字节内存的普通 64 位系统上几乎被遗忘了。嵌入式系统将我们带回到未来,需要恢复这些技能以平衡代码功能与高度受限的内存容量。
资料来源:CEVA
很多可能的优化将取决于您对代码的仔细设计和调整。但是构建工具——尤其是编译器和链接器——也可以提供帮助。在本博客中,我将讨论可用于 CEVA 工具箱中这些步骤的选项。在所有情况下,我都将专注于优化代码大小,因为这将是您的主要约束。
编译器选项
当您设计和调试代码时,您几乎肯定会使用-g选项运行,要求生成调试信息。使用此选项运行可防止编译器执行任何可能以使调试复杂化的方式扭曲代码的优化。当您认真考虑优化代码大小时,您将不得不删除该选项。
下一个考虑因素是编译器如何选择优化。默认情况下,它将通过多种方法优化性能。一种方法将通过为循环的每次迭代复制代码来展开(有限大小)for循环。这避免了在每次迭代时设置和测试循环索引的开销,但显然会消耗更多内存。使用-Oz选项将阻止展开,更喜欢较小且稍慢的实现。
编译器可以用来优化性能的另一个选项是内联某些函数(特别是小函数)。这可以消除将参数推入和弹出堆栈以及跳入和跳出被调用函数的开销。但是,如果多次调用该函数,它将再次增加代码大小。使用-INLINE=no选项来禁止这种自动内联。
另一种优化在传统平台上似乎不值得付出努力,但可以对 DSP 上的代码大小产生重要影响。这是为了禁用(视情况而定)编译器对指针别名的保护。这种保护的目的是确保在选择在VLIW机器上并平行一组指令(例如DSP)时,编译器将确保这些说明中的任何指针参考在两个或更多的情况下都无法进入比赛条件其中指向同一位数据。这会限制某些指令可以并行运行的程度。您可以使用选项-alias=restrict强制解释不会发生此类情况,这应该允许推断出更多的并行性。当然,您应该仔细检查并完全回归,以确保这种解释是安全的。
链接器
链接器还可以执行与大小相关的优化。其中之一是删除未引用的函数。这需要一些小心。一些函数可以通过数据指针甚至直接跳转到硬编码地址来调用。而中断服务函数通常通过传统的调用协议来访问。因此这个选项必须考虑多种可能性。它将被自动调用,并且可以使用-keepUnrefFuncs选项禁用。
另一个链接器优化可以进一步减小代码的大小,其中某些符号未被汇编器解析,以便在链接时进行寻址。由于它们开始未解析,因此汇编器必须假定最大可能的大小来寻址目标处理器,当最终在链接器中解析时,这实际上可能是浪费的。如果不采取特殊措施,许多此类符号可能会解析为非常小的地址,但仍会占用最大可能的地址字长。缩小这些位置可以显着缩小总代码大小。这是另一个微妙的任务。在缩小任何给定地址时,必须调整代码中任何位置对该符号后面位置的直接引用。还必须考虑数据对齐要求(有时是特定于处理器的)。每次减少都必须考虑最佳最小编码,不仅对节省空间的影响,而且对其余代码的影响。幸运的是,这些优化是默认执行的。
结合最佳编码实践,谨慎使用这些编译器和链接器选项可以帮助进一步缩小代码和数据大小,以最具成本效益的方式适应您的嵌入式系统。这反过来又增加了您作为经验丰富的嵌入式系统程序员的价值,这始终是一个理想的目标!
审核编辑 黄昊宇
全部0条评论
快来发表一下你的评论吧 !