ARM未对齐的内存访问解决方法

时间:2011-02-25 16:07:17

标签: c memory gcc arm

我必须将源代码移植到运行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编译器插件会有点矫枉过正但是有没有比正则表达式好的东西?您能提出哪些其他建议?不一定所有问题实例都必须修复,因为我仍然可以依赖内核来处理一些罕见的情况。

3 个答案:

答案 0 :(得分:7)

__attribute__((__packed__))在某些情况下可能会有所帮助,但我确实认为这段代码应该早点清理,因为很可能你会花费更多时间解决问题而不是一劳永逸地解决它。

答案 1 :(得分:2)

哇,这是一个不圣洁的混乱。摆弄编译器不会让你到处都是。代码在所有体系结构上都是非法的,但恰好在某些体系结构上工作(例如x86)。我会修复代码本身。

可悲的是,没有办法做到这一点。但是,您可以通过一长串搜索和替换获得很长的路要走,然后手动修复其余部分。我首先删除这些数据类型的声明,所以如果你编译错过的任何代码,那就错了。然后,搜索并替换“*(IEC_DWORD OS_SPTR *)pSP =”“set_dword(pSP,”。制作内联函数“set_dword”)的代码段做正确的事情。继续进行尽可能多的易于更换的片段。仍然需要大量的手工修复。

我能想到的唯一另一种方法就是编译器插件,正如你的建议,并使整个编译单元中的每个指针都有对齐1.然后编译器将字节加载/存储所有内容。它最终可能不仅仅是你想要的代码。这可能不像听起来那么容易实现。

答案 2 :(得分:0)

我们可以假设问题源于ARM是32位机器而Linux盒子以64位模式运行的事实,或者代码可以假设它是在16位机器上运行。

一种方法是查看访问的底层结构。成员“H”和“L”可能是32位类型,可以像64位一样进行访问。

尝试修改L和H的类型以使代码表现得更好。

(不可否认,这是一个空洞,因为代码片段没有透露应用程序的细节,也没有透露底层结构。)