標籤:
I’m confused about unaligned memory accesses on ARM.
My understanding was that they’re not allowed — that is,
dereferencing a 32-bit value from a pointer that’s not four-byte aligned will crash.
I’ve run into such crashes before.
But right now I’ve got a situation where the Release build of an app crashes on an unaligned access,
but the Debug build doesn’t!
It’s the exact same place in the code — a CRC32 hash implementation —
and I’ve verified that an odd address is being dereferenced (as a uint32*).
(This is a 32-bit process running on an iPhone 5, by the way.)
The only difference is in the assembly code generated.
In the debug build it’s using ldr, while in the release build it’s using ldrd.
(Apparently the optimizer is smart enough to realize that the next line of code is loading the next 4 bytes after the pointer,
so it decides to combine both lines into a single instruction.)
So I’m guessing that ldr (a 32-bit load) allows unaligned access,
but ldrd (64-bit) doesn’t?
Is there any comprehensive, up-to-date documentation about this?
I’ve found an article from 2010* stating that unaligned accesses are supported but are slower because they trigger an OS trap (as on PPC);
but it doesn’t say anything about ldrd.
There’s a StackOverflow Q&A about a crash with ldrd**, where the answer states that "ldrd needs the address to be 8-byte aligned”.
But if that’s so, then I think the compiler optimization (-Ofast level) in my app was incorrect, because the value it’s dereferencing is a uint32_t*,
so there’s no expectation that it‘s 8-byte aligned.
I believe ARM requires 8-byte loads (ldrd, or doubles into the FPU, etc) require 8-byte alignment and will crash otherwise.
4-byte loads do not require alignment but will be slower if the pointer is not 4-byte aligned.
It will not crash though.
對於arm中的雙位元組或者4位元組資料的訪問,不能直接通過資料類型的強制轉換來實現,必須通過單位元組的方式:
使用單位元組賦值,或者memcpy等函數,不過這樣做的時候,首先要先確定資料是大端還是小端模式。
非對齊的資料訪問操作
對於Load/Store操作,如果是非對齊的資料訪問操作,系統定義了下面3種可能的結果.
執行的結果不可預知.
忽略字單元地址的低兩位,即訪問地址為(address _and 0xffffffc)的字單元;忽略半字單元地址的最低位的值,即訪問地址位(address _and 0xffffffe)的半字單元.
忽略字單元地址值種的低兩位的值;忽略半字單元地址的最低位的值.有儲存體統實現這種”忽略”.也就是說,這時該地址值原封不動的送到儲存系統.
當發生非對齊的資料訪問時,到底採用上述3種處理方法種的哪一種,是有各指令指定的.
ARM 非對齊的資料訪問操作