最近碰到一個問題,有個程序是跑在ARM cortex M4上。 之前用-O0編譯的時候運行一切正常, 但用-O3編譯就會有unaligned的UsageFault。但因爲空間的問題又必須用-O3編譯。
問題的原因
跟蹤調試了一些,出問題的是下面的代碼:
uint32_t *txb = (uint32_t*)buf;
while (len) {
uint32_t data = *txb++;//UsageFault
reg_write(addr, data);
...
}
而這裏的buf本來是一個uint8的指針,並且因爲上層傳輸協議的原因,地址並不是4字節對齊的。在用-O0編譯的時候,彙編代碼如下:
LDR r0,[r11],#04
STR r0,[sp.#0x10]
其中LDR/STR 這一系列的指令是可以用unaligned的地址的,只是速度會變慢。
如果用-O3編譯,彙編代碼就變成這樣:
LDM r0!,{r2}
STR r2,{r8,0x60}
編譯器認爲LDM指令更加高效,替換了LDR指令。 但LDM/STM/LDRD/STRD這幾個指令不支持unaligned的訪問,所以一定會有UsageFault。
問題的預防
我們可以設置UNALIGN_TRP, 這樣即使使用LDR指令,如果有unaligned的訪問也會有UsageFault。這用就可以發現代碼中的非對齊的問題。
SCB->CCR |= SCB_CCR_UNALIGN_TRP_Msk;