<meter id="pryje"><nav id="pryje"><delect id="pryje"></delect></nav></meter>
          <label id="pryje"></label>

          新聞中心

          EEPW首頁 > 嵌入式系統(tǒng) > 設計應用 > ARM程序由于字節(jié)對齊引起的問題深入分析

          ARM程序由于字節(jié)對齊引起的問題深入分析

          作者: 時間:2016-11-09 來源:網(wǎng)絡 收藏
          首先說說,什么叫對齊。如果一個數(shù)據(jù)是從偶地址開始的連續(xù)存儲,那么它就是半字對齊,否則就是非半字對齊;半字對齊的特征是bit0=0,其他位為任意 值。字對齊的特征是bit1=0,bit0=1,其他位為任意值。如果一個數(shù)據(jù)是以能被4 整除的地址開始的連續(xù)存儲,那么它就是字對齊,否則就是非字對齊。舉例說明四字節(jié)對齊: 對內(nèi)存進行操作時,被訪問的地址必須為4的倍數(shù)。如果分配到的地址的地址不是4的倍數(shù)時,CPU實際訪問的地址還是按照字對齊的方式來操作。也就是自動屏蔽bit1和bit0.
          用ADS的ARMC Complier下Optimization Level可能引起問題,其中的一個問題就是字節(jié)對齊的問題。下面講講問題的現(xiàn)象及實質(zhì)。
          當時問題的現(xiàn)象是:程序使 用一公共變量Buf創(chuàng)建隊列,如果ADS編譯優(yōu)化選項采用Minium則軟件工作正常;源碼不變,如果采用ALL優(yōu)化,則不正常,數(shù)據(jù)紊亂且無法工作。為 了發(fā)現(xiàn)問題,我們分別用Minium和ALL編譯,在反匯編條件下單步跟蹤程序,觀察CPU寄存器和內(nèi)存變量的變化情況。發(fā)現(xiàn)在Minium模式下,編譯 器把隊列內(nèi)存塊Uart0TxBuf分配到的地址是0x400015cc,這個地址是一個4字節(jié)對齊的地址,而在ALL模式下,編譯器把Buf分配的地址 是0x400015c2,這個地址是一個非4字節(jié)對齊的地址。正是由于這個非4字節(jié)對齊的地址導致了問題的發(fā)生。
          問題發(fā)生在QueueCreate(void *Buf, uint32 SizeOfBuf, uint8 (* ReadEmpty)(), uint8 (* WriteFull)())這個函數(shù)里,問題是如何發(fā)生的,
          在了解問題發(fā)生的機理前,先了解QueueCreate這個函數(shù)的工作原理。QueueCreate工作原理是,首先把buf指向的內(nèi)存初始化為DataQueue格式的結(jié)構(gòu)體。DataQueue的結(jié)構(gòu)體格式如下:
          typedef struct {
          QUEUE_DATA_TYPE *Out; /* 指向數(shù)據(jù)輸出位置 */
          QUEUE_DATA_TYPE *In; /* 指向數(shù)據(jù)輸入位置 */
          QUEUE_DATA_TYPE *End; /* 指向Buf的結(jié)束位置 */
          uint16 NData; /* 隊列中數(shù)據(jù)個數(shù) */
          uint16 MaxData; /* 隊列中允許存儲的數(shù)據(jù)個數(shù) */

          uint8 (* ReadEmpty)(); /* 讀空處理函數(shù) */
          uint8 (* WriteFull)(); /* 寫滿處理函數(shù) */
          QUEUE_DATA_TYPE *Buf; /* 存儲數(shù)據(jù)的空間 */
          } DataQueue;
          從結(jié)構(gòu)體可以看出,結(jié)構(gòu)體字節(jié)類型在內(nèi)存分配為: 4字節(jié)指針變量(*Out)、4字節(jié)指針變量(*In)、4字節(jié)指針變量(*End)、2字節(jié)變量NData、2字節(jié)變量MaxData、4字節(jié)函數(shù)指針 變量ReadEmpty()、4字節(jié)函數(shù)指針變量 WriteFull()。
          觀察結(jié)構(gòu)體起始地址放在非對齊時會出現(xiàn)什么情況。
          起始地址為0x400015c2時的由編譯器分配得到的地址 實際操作地址
          *Out 0x400015c2~0x400015c5 0x40015c0~0x400015c3
          *In 0x400014c6~0x400015c9 0x400014c4~0x400015c7
          *End 0x400015ca~0x400015cd 0x400015c8~0x400015cb
          從表中可以看出,實際操作的地址按照4字節(jié)對齊格式得到。例如,當執(zhí)行*Out進行操作時,自動屏蔽bit1和bit0,因此實際發(fā)生變化的是 0x40015c0~0x400015c3,而不是0x400015c2~0x400015c5,由于實際操作地址和編譯器分配地址互相覆蓋,當對*In 操作時,會導致*Out一起變化,對*End操作時,*In也跟著變化。正是由于非對齊的原因?qū)е聞?chuàng)建隊列和對列操作完全錯誤。
          當內(nèi)存起始地址為4字節(jié)對齊地址的情況時,編譯器分配地址和實際地址一致,因此不存在上述問題。
          結(jié) 論:
          在ARM嵌入式系統(tǒng)中,當把一個內(nèi)存區(qū)域初始化為某個結(jié)構(gòu)體時,必須注意字節(jié)對齊的情況。如果該內(nèi)存起始地址為非對齊地址,不僅得不到預期的結(jié)果,還可能 導致一些很奇怪的讓人無法理解表面問題。在C層面上不太容易觀察到這些問題的實質(zhì),只有深入到匯編一層去分析程序,才可能理解這些現(xiàn)象的深層原因。


          評論


          技術專區(qū)

          關閉
          看屁屁www成人影院,亚洲人妻成人图片,亚洲精品成人午夜在线,日韩在线 欧美成人 (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })();