[英]Unaligned access causes error on ARM Cortex-M4
我有一個 object,它的地址不是 4 字節對齊的。 當存在保存 2 個寄存器的 STR 指令時,這會導致 cpu 出現 HardFault 錯誤。
這是生成的代碼:
00000000 <_ZN8BaseAreaC1EPcmm>:
0: b510 push {r4, lr}
2: 4604 mov r4, r0
4: 6042 str r2, [r0, #4]
6: e9c4 3102 strd r3, r1, [r4, #8]
a: 2001 movs r0, #1
c: 7420 strb r0, [r4, #16]
e: b921 cbnz r1, 1a <_ZN8BaseAreaC1EPcmm+0x1a>
這些是在“4: 6042...”行時的寄存器
R0 08738B82 R8 0
R1 08738BAE R9 0
R2 0 R10 082723E0
R3 2FCC R11 0
R4 08738B82 R12 0
R5 20007630 R13 2000CB38
如所見,STR 指令的目標寄存器未按 4 字節對齊。 指令STR r2, [r0, #4]
執行良好。 但它會在下一個STRD r3, r1, [r4, #8]
上發生硬故障。 如果我手動將寄存器 R4 更改為08738B80
,它不會出現硬故障。
這是生成上述 asm 的 C++ 代碼:
BaseArea::BaseArea(char * const pAddress, unsigned long startOffset, unsigned long endOffset) :
m_pAddress(pAddress), m_start(startOffset), m_end(endOffset), m_eAreaType(BASE_AREA) {
m_start
是 class 中的第一個變量,與this
具有相同的地址( 0x08738B82
), m_end
在0x08738B86
之后。
如何使 object 在 4 字節上對齊? 有人對此有其他解決方案嗎?
在基於ARM的系統上,您經常無法處理未與4字節邊界對齊的32位字(正如您的錯誤告訴您的那樣)。 在x86上,您可以訪問非對齊數據,但性能會受到很大影響。 如果ARM部件支持未對齊訪問(例如,單字正常負載),則存在性能損失, 並且應該存在可配置的異常陷阱。
ARM上的邊界錯誤示例( 此處 ),TLDR:存儲指向unsigned char
的指針,然后嘗試將其轉換為double *
(雙指針)。
要解決您的問題,您需要請求一個4字節對齊的內存塊並復制非對齊字節+用垃圾字節填充它以確保它是4字節對齊的(因此手動執行數據結構對齊)。 然后,您可以將該對象從其新地址解釋為4字節對齊。
來自TurboJ的評論中,顯式錯誤:
默認情況下,Cortex-M3和M4允許未對齊訪問。 但是他們不允許使用STRD指令進行無法訪問,因此就是錯誤。
你也可以發現它有助於看看這對ARM迫使數據結構對齊。
以下情況至少適用於ARM體系結構(在cortex M0上驗證):
使用加載和存儲指令時,我們訪問的內存必須能夠被我們嘗試從內存訪問/到內存的字節數整除,否則我們將獲得硬故障異常。
例如:
LDR r0, = 0x1001
LDR r1, [r0]
上面代碼中的第二行將給出硬錯誤,因為它試圖讀取4個字節,但內存地址不能被4整除
如果我們將上面代碼中的第二行更改為以下內容
LDRB r1, [r0];
//從地址加載1個字節
上面的行不會產生硬故障,因為我們試圖訪問1個字節(可以從任何內存位置訪問1個字節)
另請注意以下示例;
LDR r0,= 0x1002
LDRH r1,[r0]; //Load half word from 0x1002
上述行不會產生硬故障,因為內存訪問是2個字節,地址可以被2整除。
正如您所發現的,Cortex-M4 支持 4 字節未對齊訪問,但不支持 8 字節未對齊訪問。 后者在 UFSR.UNALIGNED 位的文檔中有解釋:
UNALIGNED - 表示發生了未對齊的訪問操作。 未對齊的多字訪問,例如訪問非 8 字節對齊的
uint64_t
,將始終生成此錯誤。 除了 Cortex-M0 MCU 之外,4 字節以下的未對齊訪問是否產生故障也是可配置的。
8 字節訪問可以是 STR 指令(如您的示例所示)或只是訪問uint64_t
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.