2011-02-25 24 views
9

我必須將源代碼移植到運行Linux的ARM平臺。不幸的是,我遇到了未對齊的內存訪問問題。源使用指針強制轉換和訪問。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編譯器插件會過度殺傷,但是比正則表達式更好嗎?你可以提出什麼其他建議?不一定所有的問題都需要修正,因爲我仍然可以依賴內核來處理少數情況。

+11

我很想開玩笑說,這應該被轉移到TheDailyWTF.com。 – Crashworks 2011-02-25 23:23:35

+2

繼續我們對現代語言學的研究,這裏我們有一個嵌入式程序員常用的C語言樣本。大致翻譯成英文,上述文字的意思是「F *** YOU!」,儘管沒有一種自然語言能夠真實地表達對一切神聖的蔑視,蔑視一切神聖的東西,並且普遍無視這裏傳達的讀者的人性。 – Dmitri 2015-12-10 23:13:26

回答

7

__attribute__((__packed__))這可能有助於某些情況下,但我真的認爲這個代碼應該早於後來清理,因爲它很可能會花費更多時間來解決問題,而不是解決一次問題。併爲所有。

+1

我認爲這是一個可行的解決方法,但是首先編寫代碼的人應該被解僱。順便說一句,代碼可能也需要'-fno-strict-aliasing'或'__attribute __((may_alias))'在所有這些指針上,如果它被破壞... – 2011-02-25 19:07:19

+0

它不會幫助IEC_DWORD *的情況,因爲這基本上是typedef uint32_t,POD類型。一個指針被轉換爲此時,它被推斷爲有4個字節對齊。當代碼被破壞時,很有可能爲編譯目標的模擬器編寫代碼:) – 2011-02-26 01:06:42

+0

'__attribute __((__ packed __))'已經用於結構成員,但是由於代碼轉換爲POD類型而不是結構這是無用的。但我會嘗試一個測試程序,看看我能否使用它。 – trenki 2011-02-28 09:42:27

0

我們可以假設問題源於ARM是32位機器,而Linux機器以64位模式運行,或者代碼可能假設在16位機器上運行。

一種方法是查看訪問的底層結構。成員「H」和「L」可能是32位類型,可以像訪問64位那樣訪問。

嘗試修改L和H的類型以使代碼表現更好。

(誠然,這是一個刺進稀薄的空氣,作爲代碼段沒有揭示該應用程序的細節,也沒有底層的結構。)

2

哇,邪惡混亂。擺弄編譯器不會讓你感覺到任何地方。該代碼在所有體系結構中都是非法的,但恰巧在某些(例如x86)上運行。我會修復代碼本身。

可悲的是沒有很好的辦法做到這一點。但是,您可能會用很長的搜索和替換列表取得很長的路要走,然後手動修復其餘部分。我將首先刪除這些數據類型的聲明,所以如果你編譯了任何你錯過的代碼,它會出錯。然後,搜索並替換代碼片段,例如「*(IEC_DWORD OS_SPTR *)pSP =」」set_dword(pSP,「。使內聯函數」set_dword「做正確的事情。繼續執行你可以想象得到很容易替代的片段,仍然會有大量的數據需要手工修復。

我可以想到的唯一的另一種方式是按照你的建議編譯器插件,整個編譯單元具有對齊1。然後編譯器將字節加載/存儲所有內容。它可能會最終做到這一點,而不僅僅是你想要的代碼。這可能不像聽起來那麼容易實現。