我必须将源代码移植到运行Linux的ARM平台。不幸的是,我遇到了未对齐的内存访问问题。源使用指针强制转换和大量访问。
下面的代码就像病毒一样遍布代码库。由于gcc -Wcast-align
命令行选项,我可以查明有问题的位置,但是有超过一千个实例要经历。
u = (IEC_BOOL);
(((*(IEC_LINT*)pSP).H < b.H)
|| (((*(IEC_LINT*)pSP).H == b.H) && ((*(IEC_LINT*)pSP).L < b.L) )) ? 1 : 0);
*(IEC_DWORD OS_SPTR *)pSP =
(IEC_DWORD)(*(IEC_DWORD OS_SPTR *)pSP >> u);
*(IEC_DWORD OS_SPTR *)pSP =
(IEC_DWORD)(*(IEC_DWORD OS_SPTR *)pSP << -u);
u = (IEC_BYTE)((*(IEC_DINT*)pSP != b) ? 1 : 0);
*(IEC_DWORD*)pSP = (IEC_DWORD)(*(IEC_DWORD*)pSP & w);
(*(IEC_ULINT*)pSP).H += u.H;
(((*(IEC_ULINT OS_SPTR *)pSP).H == b.H)
&& ((*(IEC_ULINT OS_SPTR *)pSP).L > b.L))) ? 1 : 0);
u = (IEC_BYTE)((*(IEC_REAL*)pSP >= b) ? 1 : 0);
使用echo 2 > /proc/cpu/alignment
使Linux内核修复了问题,但应用程序的性能降低到不再可接受的程度。
我在网上搜索了GCC(v4.4.1)编译器的__unaligned
或__packed
关键字,但截至目前为止还是空的。
我认为很多问题的代码行可以通过一个或多或少复杂的正则表达式/替换进行修复,但是现在,在我做了一段时间之后,我看到,这种方法也会花费大量繁琐的工作。
你们有什么建议如何完成这项工作?我认为一个gcc 4.5编译器插件会有点矫枉过正但是有没有比正则表达式好的东西?您能提出哪些其他建议?不一定所有问题实例都必须修复,因为我仍然可以依赖内核来处理一些罕见的情况。
答案 0 :(得分:7)
__attribute__((__packed__))
在某些情况下可能会有所帮助,但我确实认为这段代码应该早点清理,因为很可能你会花费更多时间解决问题而不是一劳永逸地解决它。
答案 1 :(得分:2)
可悲的是,没有办法做到这一点。但是,您可以通过一长串搜索和替换获得很长的路要走,然后手动修复其余部分。我首先删除这些数据类型的声明,所以如果你编译错过的任何代码,那就错了。然后,搜索并替换“*(IEC_DWORD OS_SPTR *)pSP =”与“set_dword(pSP,”。制作内联函数“set_dword”)的代码段做正确的事情。继续进行尽可能多的易于更换的片段。仍然需要大量的手工修复。
我能想到的唯一另一种方法就是编译器插件,正如你的建议,并使整个编译单元中的每个指针都有对齐1.然后编译器将字节加载/存储所有内容。它最终可能不仅仅是你想要的代码。这可能不像听起来那么容易实现。
答案 2 :(得分:0)
我们可以假设问题源于ARM是32位机器而Linux盒子以64位模式运行的事实,或者代码可以假设它是在16位机器上运行。
一种方法是查看访问的底层结构。成员“H”和“L”可能是32位类型,可以像64位一样进行访问。
尝试修改L和H的类型以使代码表现得更好。
(不可否认,这是一个空洞,因为代码片段没有透露应用程序的细节,也没有透露底层结构。)