1情景
售后 : X工,現場出大事了,今天升級的程序跑著跑著就掛了!現在整個產線都等著這個設備恢復,能安排個人過來支援下嗎?
bug菌 : my god !別慌,我問一下負責的A工。
bug菌 : 喂,A工,昨天升級的程序有問題,程序卡死,售后在現場你聯系一下,支援他一波,順便把程序發送給我一份,一起看看!
A工 : 啊,還有這種事,程序沒改什么呀,行,我跟售后聯系一下。
經過一番折騰,發現由于程序測試不到位,導致了一個強制類型轉化引發的進入異常,這里就分享給大家。
2bug演示
這是一個老項目,采用stm32F4芯片為主控,由于硬件限制而客戶又不愿意花大價錢改造,所以程序架構等等都沒有再大動作,由于通信上的傳輸和解析都是字節流,一些小的需求都只是在原來的通信架構上把4個字節拆成2個字節來用,然而這一次實在沒辦法沒改接收數據類型,然后把一個double類型拆成了4個uint16來使用,沒想到出問題了。
所以這里簡單的模擬演示了一下:
A工用一個double類型取地址,然后把地址強制轉為uint64_t類型,以此類型指針取內容,當這段代碼執行完程序就跳到了異常中斷,導致死機。
其實這段代碼對于經驗豐富的人來說,一看就覺得很變扭,但是無論如何也不至于死機呀,畢竟強制類型轉化大部分人拿來都是隨便用。
3bug解讀
當看到A工寫的這一套代碼,bug菌其實隱隱約約就感覺這塊有些問題,但是沒敢確定,畢竟整套代碼也是前人留下的,全是邏輯沒什么精華也沒有過細研究,最后看這段代碼的匯編才知道問題所在。
在之前bug菌也曾比較詳細的出過一篇分析此類問題的文章,可能這一塊并沒有吸引到你,不過還是一句話:"出來混都是要還的!"。
其實問題就出在LDRD這個ARM匯編指令上,LDRD指令表示從指定內存地址取double word,上面圖片代碼中的LDRD R0,R1,[R2,#0x2EC],可以分解為下面兩個ldr步驟 :
在ARM匯編指令集中LDRD和STRD是一對加載和提取指令,一般都需要使用__align(8)修飾來保證數據對象進行8直接對齊,而使用#pragma pack(8)是來指定結構體成員變量相對于第一個變量的地址的偏移量的對齊方式。
__align指示編譯器在 n 字節邊界上對齊變量,是一個存儲類修飾符,當然也可以以讓2字節的對象進行4字節對齊其與8字節對齊是等價的,一定要記得是存儲的起始地址為8的整數倍。
對齊可以在一定程度上提高數據提取的效率,一旦起始地址沒有對齊會導致對齊錯誤,所以上面的double浮點類型的結構體變量沒有8字節地址對齊,當進行強制類型轉化并使用LDRD指令就導致未對齊故障。
3更專業點
當然對于跳轉到硬件異常的故障是非常好排查的,下面這篇文章教你如何迅速的定位故障位置和故障信息 :
對于非對齊指令的執行會導致指令用法上的故障,那么Cortex芯片中相應的故障寄存器標志位會置位。
以上來自于Cortex技術文檔,文檔中也寫得非常的詳細。
當CPU嘗試做一個未對齊的內存訪問,然后就會發生此錯誤。特別是對于未對齊的LDM/STM/LDRD/STRD指令,所以進入異常中斷以后查詢芯片內部故障寄存器也是可以找到問題所在的,對于使用仿真器排查是再簡單不過了,如果是離線排查就需要進行上篇文章那樣打印相關日志來定位問題。
本文來源:公眾號:最后一個bug
審核編輯:湯梓紅
-
STM32
+關注
關注
2272文章
10925瀏覽量
357654 -
代碼
+關注
關注
30文章
4829瀏覽量
69074 -
BUG
+關注
關注
0文章
155瀏覽量
15725
原文標題:stm32一個強制類型轉換死機,讓我付出了慘痛的代價~
文章出處:【微信號:嵌入式情報局,微信公眾號:嵌入式情報局】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論