基于DWC_ether_qos的以太網(wǎng)驅(qū)動開發(fā)-LWIP的堆(內(nèi)存池)未對齊導(dǎo)致問題的案例分享
時間:2023-09-09 13:12:32
一.前言
內(nèi)存未對齊訪問問題這個已經(jīng)是老生常談的問題了, 由于LWIP的堆管理中也用到了地址(指針)強制轉(zhuǎn)換所以也會遇到這個問題。對于老手比較容易發(fā)現(xiàn),對于新手可能會比較疑惑。所以也單獨分享一個案例吧,權(quán)當一個小的check list的case。
二.問題
Lwipopts.h中MEM_ALIGNMENT可以配置堆對齊大小,有問題時是配置為1
(資料圖片僅供參考)
#define MEM_ALIGNMENT 1U
異常時打印寄存器如下,當然不同平臺異常時如何獲取上下文信息方式不一樣,不在本文討論范圍內(nèi),我這里是RISC-V環(huán)境。
看到打印的mepc是0x20006C88,異常原因是地址未對齊。
所以是在運行0x20006C88時進入了異常,當然這個地方不一定是原始問題所在點,異常可能是跑了很久才出現(xiàn)的。
所以先在這里打個斷點試試
可以看到是pbuf.c的代碼中,所以可以懷疑是內(nèi)存池或者堆的問題。
我們運行發(fā)現(xiàn)斷點并不能觸發(fā),之前就已經(jīng)異常了,所以只能跟代碼逐漸縮小范圍確認問題的。一般采用的方式是,逐步斷點或者打印或者刪除代碼,逐步縮小范圍的方法。
可以借鑒一些二分的思想,加快定位。
這里還是從pbuf開始,先找到相關(guān)代碼上層函數(shù)處,斷點
b pbuf_init_alloced_pbuf
看到異常前是可以停下來的
看到此時p的值是0x28201406
查看如下匯編代碼可知
sw zero,0(a0)即對應(yīng)代碼p->next = NULL;
sw是word操作指令,但是地址a0不是word對齊,所以會產(chǎn)生異常
再si單步確實進入異常
所以問題確認了。
因為堆是分配的一塊區(qū)域,每一塊區(qū)域的開始地址對齊值就是上面設(shè)置的對齊大小,分配區(qū)塊后作為其他模塊使用,比如pbuf使用,前面部分作為管理結(jié)構(gòu)體
struct pbuf 操作,所以實際是將一個區(qū)塊地址強制轉(zhuǎn)為了結(jié)構(gòu)體指針。
此時訪問結(jié)構(gòu)體成員,編譯器是自動按照自然對齊生成匯編指令的,因為編譯器并不知道你的對齊要求,所以如果系統(tǒng)不支持對應(yīng)的指令非對其訪問就有問題,但是有些系統(tǒng)對應(yīng)的匯編指令的行為支持不對齊訪問那么就沒有問題。
當然出于可靠性設(shè)計,建議不要進行強制類型轉(zhuǎn)換,比如MISRA標準里的規(guī)范就是如此。
如果代碼要做到兼容性可靠性非常好就要注意這個問題,此時不能使用強制類型轉(zhuǎn)換,而是使用字節(jié)序手動拼接得到成員的值。
但是出于靈活性考慮,很多協(xié)議棧的設(shè)計都是直接使用強制類型轉(zhuǎn)換的,所以這時用戶就需要注意,比如這里我們可以配置#define MEM_ALIGNMENT 4U
來保證上述分配出來的地址p是4字節(jié)對齊的,所以按照偏移,其成員也是4字節(jié)對齊的,sw指令操作的就是4字節(jié)對齊的成員,就不會有問題。
三.總結(jié)
以上分享一個簡單的案例,目的是提醒下要注意類似問題,尤其有指針強制類型轉(zhuǎn)換的要注意對齊問題。問題不難,也不復(fù)雜,但是可以作為check list的case可以作為檢查項目。
相關(guān)稿件
基于DWC_ether_qos的以太網(wǎng)驅(qū)動開發(fā)-LWIP的堆(內(nèi)存池)未對齊導(dǎo)致問題的案例分享
您好?我被偷拍私密視頻后被人傳播了?我有他偷拍的聊天記錄?但
安徽豆粉云信息科技有限公司_關(guān)于安徽豆粉云信息科技有限公司介紹
周杰倫天津演唱會發(fā)生意外?經(jīng)紀公司凌晨回應(yīng)
公告精選:商品代雞苗售價大漲 民和股份8月銷售收入環(huán)比增加41%
中國8月狂賣192萬輛汽車創(chuàng)同期史高 自主品牌破100萬
馬蒂諾:如果梅西能出戰(zhàn)玻利維亞,我認為他不會提前回到俱樂部
一次開藥1800片?江西通報三起超量開藥類違規(guī)案例
華商記者幫|長安天然氣公司要求商戶整改安裝電磁閥 商戶們覺得其下屬子公司的“一口價”報價有些貴
茶坊鎮(zhèn)東紅村扶貧互助資金協(xié)會(關(guān)于茶坊鎮(zhèn)東紅村扶貧互助資金協(xié)會簡述)