最近調試 uboot 遇到一個很頑固的錯誤,遇到我是一臉懵啊,花了一天的時間去解決。
fs_open() 100,p=45fb0a2d len=1436 H
fs_open() 108
data abort
pc : [<45f9b688>] lr : [<45fa4d29>]
reloc pc : [<4a024688>] lr : [<4a02dd29>]
sp : 41f63b38 ip : 00000006 fp : 00006401
r10: 45ffc678 r9 : 41f67ee0 r8 : 45ffc018
r7 : 80000000 r6 : 45fb0a2d r5 : 0000059c r4 : 00000000
r3 : 000002ce r2 : 45fb0a2b r1 : 01c20c00 r0 : 45fb0fc7
Flags: Nzcv IRQs off FIQs off Mode SVC_32
Resetting CPU ...
resetting ...
首先感謝 BeanHuo 的博客,提供瞭解決思路 ----博文鏈接:關於uboot下data abort的問題
結合我實際的log ,可以看出在 0x4a024688 位置除了錯,接下來用 objdump -S u-boot 來找到對應的彙編指令
4a024684: 4620 mov r0, r4
4a024686: bd70 pop {r4, r5, r6, pc}
acc += *sdata;
4a024688: f832 1f02 ldrh.w r1, [r2, #2]!
4a02468c: 440c add r4, r1
4a02468e: b2a4 uxth r4, r4
if(acc < *sdata) {
4a024690: 42a1 cmp r1, r4
++acc;
4a024692: bf84 itt hi
4a024694: 3401 addhi r4, #1
4a024696: b2a4 uxthhi r4, r4
4a024698: e7df b.n 4a02465a
...
發現出錯的彙編指令 對應的代碼函數如下,在執行 acc += *sdata 的時候出了錯誤。
u16_t
uip_chksum(u16_t *sdata, u16_t len)
{
u16_t acc = 0;
for(acc = 0; len > 1; len -= 2) {
acc += *sdata;
if(acc < *sdata) {
/* Overflow, so we add the carry to acc (i.e., increase by
one). */
++acc;
}
++sdata;
}
/* add up any odd byte */
if(len == 1) {
acc += htons(((u16_t)(*(u8_t *)sdata)) << 8);
if(acc < htons(((u16_t)(*(u8_t *)sdata)) << 8)) {
++acc;
}
}
return acc;
}
爲什麼在執行 acc += *sdata 的時候出了錯誤。sdata 指針位置這哪裏?
方法1,可以加打印看。
方法2,根據彙編推算。
這裏直接看彙編:
acc += *sdata;
4a024688: f832 1f02 ldrh.w r1, [r2, #2]!
4a02468c: 440c add r4, r1
4a02468e: b2a4 uxth r4, r4
這裏需要知道 r2 的值, r2 的值根據出錯時的打印可以看到
pc : [<45f9b688>] lr : [<45fa4d29>]
reloc pc : [<4a024688>] lr : [<4a02dd29>]
sp : 41f63b38 ip : 00000006 fp : 00006401
r10: 45ffc678 r9 : 41f67ee0 r8 : 45ffc018
r7 : 80000000 r6 : 45fb0a2d r5 : 0000059c r4 : 00000000
r3 : 000002ce r2 : 45fb0a2b r1 : 01c20c00 r0 : 45fb0fc7
r2 = 45fb0a2b
[r2, #2] 得到 45fb0a2d
需要找到 45fb0a2d 對應的 位置, 先根據 pc , reloc pc 得到 offset
offset = reloc pc - pc = 4a024688 - 45f9b688 = 4089000
45fb0a2d - offset = 45fb0a2d - 4089000 = 4a039a2d
在 u-boot.map 文集中找到 4a039a2d 對應的位置
6110: .rodata.data_flashing_html
6111- 0x000000004a039a2d 0x59d httpd/built-in.o
6112: .rodata.data_index_html
這是一個 const char 數組。
爲什麼會導致 data abort ??????
百思不得解,
百思不得解,
百思不得解,
終於在重新翻看文章時,注意到這麼一段話
其實在出錯時,uboot已經告訴我們如何去找出問題所在,如上面的問題,我們可以通過查看doc/README.arm-unaligned-accesses來找到出錯的位置。
arm-unaligned-accesses ? 非對齊地址訪問 ?
查找相關資料後,找到一篇有幫助的文章:內存不對齊訪問(unaligned access)及彙編下宕機
文中指出,開啓內存地址對齊錯誤的檢查功能時,進行對齊地址訪問會導致宕機,data abort
uboot的cpu內核初始化階段,啓動了內存地址對齊錯誤的檢查功能;然後用ldr加載和str存儲內存地址不對齊的空間會發生什麼事情?
參考ARM架構手冊中如下表,可知將因指令的地址對齊錯誤導致數據中止異常。如果你用如下指令將SCTLR.A置爲0,將不會產生異常,實現了不對齊訪問,較早的ARM架構不支持這種功能,ARMv7上可以支持。
再看這次的 45fb0a2d ,地址爲奇數,剛好就是非對齊地址,難怪總是出錯!!!
如何解決?
正好的我的是 ARMv7 , 是可以支持不對齊訪問的,只要在Start.s 中將 Align 檢測功能去掉。
重新編譯運行,一切正常!
再次感謝以上兩位博主的文章!