ARM的字對(duì)齊問(wèn)題總結(jié)_第1頁(yè)
ARM的字對(duì)齊問(wèn)題總結(jié)_第2頁(yè)
ARM的字對(duì)齊問(wèn)題總結(jié)_第3頁(yè)
ARM的字對(duì)齊問(wèn)題總結(jié)_第4頁(yè)
ARM的字對(duì)齊問(wèn)題總結(jié)_第5頁(yè)
已閱讀5頁(yè),還剩15頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

1、 ARM的字對(duì)齊問(wèn)題總結(jié) 一、啥是字對(duì)齊?為啥要字對(duì)齊? 現(xiàn)代計(jì)算機(jī)中內(nèi)存空間都是按照byte劃分的,從理論上講似乎對(duì)任何類型的變量的訪問(wèn)都可以從任何地址開(kāi)始,但實(shí)際情況是在訪問(wèn)特定類型變量的時(shí)候經(jīng)常在特定的內(nèi)存地址訪問(wèn),這就是對(duì)齊。 字節(jié)對(duì)齊的原因大致是如下兩條: 1、平臺(tái)原因(移植原因):不是所有的硬件平臺(tái)都能訪問(wèn)任意地址上的任意數(shù)據(jù)的;某些硬件平臺(tái)只能在某些地址處取某些特定類型的數(shù)據(jù),否則拋出硬件異常。 2、性能原因:數(shù)據(jù)結(jié)構(gòu)(尤其是棧)應(yīng)該盡可能地在自然邊界上對(duì)齊。原因在于,為了訪問(wèn)未對(duì)齊的內(nèi)存,處理器需要作兩次內(nèi)存訪問(wèn);而對(duì)齊的內(nèi)存訪問(wèn)僅需要一次訪問(wèn)。 二、對(duì)齊規(guī)則 每個(gè)特定平臺(tái)上的

2、編譯器都有自己的默認(rèn)“對(duì)齊系數(shù)”(也叫對(duì)齊模數(shù))。程序員可以通過(guò)預(yù)編譯命令#pragma pack(n),n=1,2,4,8,16來(lái)改變這一系數(shù),其中的n就是你要指定的“對(duì)齊系數(shù)”。 規(guī)則: 1. 數(shù)據(jù)成員對(duì)齊規(guī)則:結(jié)構(gòu)(struct)(或聯(lián)合(union)的數(shù)據(jù)成員,第一個(gè)數(shù)據(jù)成員放在offset為0的地方,以后每個(gè)數(shù)據(jù)成員的對(duì)齊按照#pragma pack指定的數(shù)值和這個(gè)數(shù)據(jù)成員自身長(zhǎng)度中,比較小的那個(gè)進(jìn)行。 2. 結(jié)構(gòu)(或聯(lián)合)的整體對(duì)齊規(guī)則:在數(shù)據(jù)成員完成各自對(duì)齊之后,結(jié)構(gòu)(或聯(lián)合)本身也要進(jìn)行對(duì)齊,對(duì)齊將按照#pragma pack指定的數(shù)值和結(jié)構(gòu)(或聯(lián)合)最大數(shù)據(jù)成員長(zhǎng)度中,比較小

3、的那個(gè)進(jìn)行。 3. 結(jié)合1、2可推斷:第一、如果n大于等于該變量所占用的字節(jié)數(shù),那么偏移量必須滿足默認(rèn)的對(duì)齊方式,第二、如果n小于該變量的類型所占用的字節(jié)數(shù),那么偏移量為n的倍數(shù),不用滿足默認(rèn)的對(duì)齊方式。 三、X86對(duì)齊實(shí)驗(yàn) 下面再簡(jiǎn)要回顧解釋一下上述的對(duì)齊規(guī)則,結(jié)合實(shí)例進(jìn)行分析: 1. 數(shù)據(jù)類型自身的對(duì)齊值:對(duì)于char型數(shù)據(jù),其自身對(duì)齊值為1字節(jié),對(duì)于short型為2字節(jié),對(duì)于int,float,double類型,其自身對(duì)齊值為4字節(jié)。 2. 結(jié)構(gòu)體的自身對(duì)齊值:其成員中自身對(duì)齊值最大的那個(gè)值。 3. 指定對(duì)齊值:#pragma pack(n)來(lái)設(shè)定變量以n字節(jié)對(duì)齊方式。n字節(jié)對(duì)齊就是說(shuō)變

4、量存放的起始地址的偏移量有兩種情況,第一、如果n大于等于該變量所占 用的字節(jié)數(shù),那么偏移量必須滿足默認(rèn)的對(duì)齊方式,第二、如果n小于該變量的類型所占用的字節(jié)數(shù),那么偏移量為n的倍數(shù),不用滿足默認(rèn)的對(duì)齊方式。 4. 數(shù)據(jù)成員和結(jié)構(gòu)體的有效對(duì)齊值:數(shù)據(jù)成員(數(shù)據(jù)類型)和數(shù)據(jù)結(jié)構(gòu)的自身對(duì)齊值和指定對(duì)齊值中小的那個(gè)值,數(shù)據(jù)成員對(duì)齊了數(shù)據(jù)結(jié)構(gòu)自然也就對(duì)齊了。 了解上述四個(gè)基本概念,我們開(kāi)始討論具體數(shù)據(jù)結(jié)構(gòu)的成員和其自身的對(duì)齊方式。有效對(duì)齊值N是最終用來(lái)決定數(shù)據(jù)存放地址方式的值。有效對(duì)齊N,就是表示“對(duì)齊在N上”,也就是說(shuō)該數(shù)據(jù)的存放起始地址%N=0。而數(shù)據(jù)結(jié)構(gòu)中的數(shù)據(jù)變量都是按定義的先后順序來(lái)排放的。第一

5、個(gè)數(shù)據(jù)變量的起始地址就是數(shù)據(jù)結(jié)構(gòu)的起始地址。結(jié)構(gòu)體的成員變量要對(duì)齊排放,結(jié)構(gòu)體本身也要根據(jù)自身的有效對(duì)齊值圓整(結(jié)構(gòu)體成員變量占用總長(zhǎng)度需要是對(duì)結(jié)構(gòu)體有效對(duì)齊值的整數(shù)倍)。下面結(jié)合VS2005中編譯環(huán)境的例子進(jìn)行深入了解: 例子B分析: struct B char b; int a; short c; ; 假設(shè)B從地址空間0 x0000開(kāi)始排放。該例中沒(méi)有顯式指定對(duì)齊值N,VS2005默認(rèn)值為4。 成員變量b自身對(duì)齊值是1,比指定或默認(rèn)指定對(duì)齊值4小,故有效對(duì)齊值為1,其存放地址0 x0000符合0 x0000%1=0,滿足字節(jié)對(duì)齊原則。 成員變量a自身對(duì)齊值為4,和指定或默認(rèn)指定對(duì)齊值4相等

6、,故有效對(duì)齊值也為4,為了保證字節(jié)對(duì)齊,成員變量a只能存放在起始地址為0 x0004到0 x0007這四個(gè)連續(xù)的字節(jié)空間中,復(fù)核0 x0004%4=0。 成員變量c自身對(duì)齊值為2,比指定或默認(rèn)指定對(duì)齊值4小,故有效對(duì)齊值為2,可順序存放在0 x0008至0 x0009兩個(gè)字節(jié)空間中,符合0 x0008%2=0。 至此滿足了數(shù)據(jù)成員的字節(jié)對(duì)齊,接著看數(shù)據(jù)結(jié)構(gòu)B的對(duì)齊。數(shù)據(jù)結(jié)構(gòu)B的自身對(duì)齊值為其變量中最大對(duì)齊值(也就是成員變量b)4,故結(jié)構(gòu)體B的有效對(duì)齊值也是4。根據(jù)結(jié)構(gòu)體圓整的要求, 0 x0009到 0 x0000=10字節(jié),(102)40。所以0 x0000A到0 x000B也為結(jié)構(gòu)體B所占

7、用。故B從0 x0000到0 x000B 共有12個(gè)字節(jié),sizeof(struct B)=12。 之所以在變量C補(bǔ)充2字節(jié),是因?yàn)橐獙?shí)現(xiàn)編譯器快速有效的存取結(jié)構(gòu)數(shù)組,試想如果定義B結(jié)構(gòu)數(shù)組,第一個(gè)結(jié)構(gòu)起始地址是0沒(méi)有問(wèn)題,但是第二個(gè)結(jié)構(gòu)呢?按照數(shù)組的定義,數(shù)組中所有元素都是緊挨著的,如果不把結(jié)構(gòu)的大小補(bǔ)充為對(duì)齊值 (4)的整數(shù)倍,那下一個(gè)結(jié)構(gòu)的起始地址將是0 x0000A,這顯然不能滿足結(jié)構(gòu)的地址對(duì)齊了。 例子C分析: /*指定按2字節(jié)對(duì)齊*/ _align(2) struct C char b; int a; short c; ;/*取消指定對(duì)齊,恢復(fù)缺省對(duì)齊*/ 同理,例子C中成員變量b

8、自身對(duì)齊值為1,指定對(duì)齊值為2,故效對(duì)齊值為1,假設(shè)C從0 x0000開(kāi)始,那么b存放在0 x0000,符合0 x0000%1= 0,滿足字節(jié)對(duì)齊原則。 成員變量a自身對(duì)齊值為4,指定對(duì)齊值為2,故有效對(duì)齊值為2,順序存放在0 x0002、0 x0003、0 x0004、0 x0005四個(gè)連續(xù)字節(jié)中,符合0 x0002%2=0,滿足字節(jié)對(duì)齊原則。 成員變量c的自身對(duì)齊值為2,與指定對(duì)齊值相等,故有效對(duì)齊值為2,順序存放在0 x0006、0 x0007中,符合 0 x0006%2=0,滿足字節(jié)對(duì)齊原則。 從0 x0000到0 x00007共八字節(jié)存放的是結(jié)構(gòu)體C的變量。結(jié)構(gòu)體C自身對(duì)齊值為4,比

9、指定對(duì)齊值2大,故C的有效對(duì)齊值為2,因8%2=0,C只占用0 x0000到0 x0007的八個(gè)字節(jié)。所以sizeof(struct C)=8,完全滿足字節(jié)對(duì)齊原則。 除了指定的對(duì)齊值不同能導(dǎo)致數(shù)據(jù)結(jié)構(gòu)的地址存放不同外, 編譯器不同存放結(jié)構(gòu)體方式也可能不同。 四、ARM平臺(tái)的對(duì)齊問(wèn)題 在ARM中,有ARM和Thumb兩種指令。 ARM指令:每執(zhí)行一條指令,PC的值加4個(gè)字節(jié)(32bits).一次訪問(wèn)4字節(jié)內(nèi)容,該字節(jié)的起始地址必須是4字節(jié)對(duì)齊的位置上,即地址的低兩位為bits0b00,也就是說(shuō)地址必須是4的倍數(shù)。 :每執(zhí)行一條指令,PC的值加2個(gè)字節(jié)(16bits).).一次訪問(wèn)2字節(jié)內(nèi)容,該

10、字節(jié)的起始地址必須是2字節(jié)對(duì)齊的位置上,即地址的低兩位為bits0b0,也就是說(shuō)地址必須是2的倍數(shù)。 遵循以上方式叫對(duì)齊(aligned)方式,不遵守這樣方式稱為非對(duì)齊(unaligned)的存儲(chǔ)訪問(wèn)操作。 五、ARM平臺(tái)字節(jié)對(duì)齊關(guān)鍵字 1. _align(num) 用于修改最高級(jí)別對(duì)象的字節(jié)邊界。 A、在匯編中使用LDRD或者STRD時(shí),就用到此命令_align(8)進(jìn)行修飾限制。來(lái)保證數(shù)據(jù)對(duì)象是相應(yīng)對(duì)齊。 B、該修飾對(duì)象的命令最大是8個(gè)字節(jié)限制,可讓2字節(jié)的對(duì)象進(jìn)行4字節(jié) 對(duì)齊,但是不能讓4字節(jié)的對(duì)象2字節(jié)對(duì)齊。 C、 _align是存儲(chǔ)類修改,他只修飾最高級(jí)類型對(duì)象不能用于結(jié)構(gòu)或者函數(shù)對(duì)

11、象。 2. _packed _packed是進(jìn)行一字節(jié)對(duì)齊。 A、不能對(duì)packed的對(duì)象進(jìn)行對(duì)齊; B、所有對(duì)象的讀寫訪問(wèn)都進(jìn)行非對(duì)齊訪問(wèn); C、float及包含float的結(jié)構(gòu)聯(lián)合及未用_packed的對(duì)象將不能字節(jié)對(duì)齊; D、_packed對(duì)局部整形變量無(wú)影響; D、強(qiáng)制由unpacked對(duì)象向packed對(duì)象轉(zhuǎn)化是未定義,整形指針可以合法定 義為packed _packed int* p; /_packed int 則沒(méi)有意義。 3. _unaligned 用于修飾該變量可按照非對(duì)齊訪問(wèn)。 六、如何查找與字節(jié)對(duì)齊方面的問(wèn)題 如果出現(xiàn)對(duì)齊或者賦值問(wèn)題首先查看: 1. 編譯器的big li

12、ttle端設(shè)置; 2. 看這種體系本身是否支持非對(duì)齊訪問(wèn); 3. 如果支持看設(shè)置了對(duì)齊與否,如果沒(méi)有則看訪問(wèn)時(shí)需要加某些特殊的修飾來(lái)標(biāo)志其特殊訪問(wèn)操作。 七、結(jié)論 針對(duì)于32位處理器對(duì)于本地使用的數(shù)據(jù)結(jié)構(gòu),為提高內(nèi)存訪問(wèn)效率,采用四字節(jié)對(duì)齊方式;同時(shí)為了減少內(nèi)存的開(kāi)銷,合理安排結(jié)構(gòu)成員的位置,減少四字節(jié)對(duì)齊導(dǎo)致的成員之間的空隙,降低內(nèi)存開(kāi)銷。 對(duì)于處理器之間的數(shù)據(jù)結(jié)構(gòu),需要保證消息的長(zhǎng)度不因?yàn)樵诓煌幾g平臺(tái)和不同處理器導(dǎo)致消息結(jié)構(gòu)的長(zhǎng)度發(fā)生變化,使用一字節(jié)對(duì)齊方式對(duì)消息結(jié)構(gòu)進(jìn)行緊縮;為保證處理器之間的消息的數(shù)據(jù)結(jié)構(gòu)的內(nèi)存訪問(wèn)效率,采用字節(jié)填充的方式自己對(duì)消息中成員進(jìn)行四字節(jié)對(duì)齊。 數(shù)據(jù)結(jié)構(gòu)的成

13、員位置要兼顧成員之間的關(guān)系、數(shù)據(jù)訪問(wèn)效率和空間利用率。順序安排的原則是:四字節(jié)的放在最前面,兩字節(jié)的緊接最后一個(gè)四字節(jié)成員,一字節(jié)緊接最后一個(gè)兩字節(jié)成員,填充字節(jié)放在最后。舉例如下: typedef struct tag_T_MSG long ParaA; long ParaB; short ParaC; char ParaD; char Pad; /* 填充字節(jié) */ T_MSG; ARM程序由于字節(jié)對(duì)齊引起的問(wèn)題深入分析 首先說(shuō)說(shuō),什么叫對(duì)齊。如果一個(gè)數(shù)據(jù)是從偶地址開(kāi)始的連續(xù)存儲(chǔ),那么它就是半字對(duì)齊,否則就是非半字對(duì)齊;半字對(duì)齊的特征是bit0=0,其他位為任意值。字對(duì)齊的特征是bit1=

14、0,bit0=1,其他位為任意值。如果一個(gè)數(shù)據(jù)是以能被4 整除的地址開(kāi)始的連續(xù)存儲(chǔ),那么它就是字對(duì)齊,否則就是非字對(duì)齊。舉例說(shuō)明四字節(jié)對(duì)齊: 對(duì)內(nèi)存進(jìn)行操作時(shí),被訪問(wèn)的地址必須為4的倍數(shù)。如果分配到的地址的地址不是4的倍數(shù)時(shí),CPU實(shí)際訪問(wèn)的地址還是按照字對(duì)齊的方式來(lái)操作。也就是自動(dòng)屏蔽bit1和bit0. 用ADS的ARM C Complier下Optimization Level可能引起問(wèn)題,其中的一個(gè)問(wèn)題就是字節(jié)對(duì)齊的問(wèn)題。下面講講問(wèn)題的現(xiàn)象及實(shí)質(zhì)。 當(dāng)時(shí)問(wèn)題的現(xiàn)象是:程序使用一公共變量Buf創(chuàng)建隊(duì)列,如果ADS編譯優(yōu)化選項(xiàng)采用Minium則軟件工作正常;源碼不變,如果采用ALL優(yōu)化,則

15、不正常,數(shù)據(jù)紊亂且無(wú)法工作。為了發(fā)現(xiàn)問(wèn)題,我們分別用Minium和ALL編譯,在反匯編條件下單步跟蹤程序,觀察CPU寄存器和內(nèi)存變量的變化情況。發(fā)現(xiàn)在Minium模式下,編譯器把隊(duì)列內(nèi)存塊Uart0TxBuf分配到的地址是0 x400015cc,這個(gè)地址是一個(gè)4字節(jié)對(duì)齊的地址,而在ALL模式下,編譯器把Buf分配的地址是0 x400015c2,這個(gè)地址是一個(gè)非4字節(jié)對(duì)齊的地址。正是由于這個(gè)非4字節(jié)對(duì)齊的地址導(dǎo)致了問(wèn)題的發(fā)生。 問(wèn)題發(fā)生在QueueCreate(void *Buf, uint32 SizeOfBuf, uint8 (* ReadEmpty)(), uint8 (* WriteFu

16、ll)()這個(gè)函數(shù)里,問(wèn)題是如何發(fā)生的, 在了解問(wèn)題發(fā)生的機(jī)理前,先了解QueueCreate這個(gè)函數(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; /* 隊(duì)列中數(shù)據(jù)個(gè)數(shù) */ uint16 MaxData; /* 隊(duì)

17、列中允許存儲(chǔ)的數(shù)據(jù)個(gè)數(shù) */ uint8 (* ReadEmpty)(); /* 讀空處理函數(shù) */ uint8 (* WriteFull)(); /* 寫滿處理函數(shù) */ QUEUE_DATA_TYPE *Buf; /* 存儲(chǔ)數(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)體起始地址放在非對(duì)齊時(shí)會(huì)出現(xiàn)什么情況。 起始地址為0 x40

18、0015c2時(shí)的由編譯器分配得到的地址 實(shí)際操作地址 *Out 0 x400015c20 x400015c5 0 x40015c00 x400015c3 *In 0 x400014c60 x400015c9 x400014c40 x400015c7 *End 0 x400015ca0 x400015cd 0 x400015c80 x400015cb 從表中可以看出,實(shí)際操作的地址按照4字節(jié)對(duì)齊格式得到。例如,當(dāng)執(zhí)行*Out進(jìn)行操作時(shí),自動(dòng)屏蔽bit1和bit0,因此實(shí)際發(fā)生變化的是0 x40015c00 x400015c3,而不是0 x400015c20 x400015c5,由于實(shí)際操作地址和

19、編譯器分配地址互相覆蓋,當(dāng)對(duì)*In操作時(shí),會(huì)導(dǎo)致*Out一起變化,對(duì)*End操作時(shí),*In也跟著變化。正是由于非對(duì)齊的原因?qū)е聞?chuàng)建隊(duì)列和對(duì)列操作完全錯(cuò)誤。 當(dāng)內(nèi)存起始地址為4字節(jié)對(duì)齊地址的情況時(shí),編譯器分配地址和實(shí)際地址一致,因此不存在上述問(wèn)題。 結(jié) 論: 在ARM嵌入式系統(tǒng)中,當(dāng)把一個(gè)內(nèi)存區(qū)域初始化為某個(gè)結(jié)構(gòu)體時(shí),必須注意字節(jié)對(duì)齊的情況。如果該內(nèi)存起始地址為非對(duì)齊地址,不僅得不到預(yù)期的結(jié)果,還可能導(dǎo)致一些很奇怪的讓人無(wú)法理解表面問(wèn)題。在C層面上不太容易觀察到這些問(wèn)題的實(shí)質(zhì),只有深入到匯編一層去分析程序,才可能理解這些現(xiàn)象的深層原因。 編譯器不同在存放結(jié)構(gòu)體方式可能不同,因此對(duì)齊也會(huì)有不同 A

20、RM中字節(jié)對(duì)齊的深入探討 ARM中字節(jié)對(duì)齊的深入探討 閱讀了yos的文章內(nèi)存對(duì)齊問(wèn)題學(xué)習(xí)小結(jié),深有體會(huì),看來(lái)在進(jìn)行指針操作時(shí),必須進(jìn)行強(qiáng)制類型轉(zhuǎn)換,否則可能出現(xiàn)預(yù)想不到的錯(cuò)誤。 在我的一個(gè)項(xiàng)目中,需要進(jìn)行數(shù)據(jù)包解碼,同樣出現(xiàn)數(shù)據(jù)對(duì)齊的問(wèn)題,卻沒(méi)能找到好的解決方法問(wèn)題如下 CPU ARM7 ,編譯環(huán)境 Keil RVCT3.0 #pragma pack(1) typedef struct uint8 u8a3; uint8 u8b4; uint16 u16c; uint32 u32d; uint32 u32e; TSTBLK,* PTSTBLK; 主程序 main uint16 i; PTSTB

21、LK pTST; uint16 u16k; uint32 u32m,u32l; uint8 DBUF200; for(i= 0 ;iu16c); / 2 u32m = pTST-u32d; / 3 u32l = pTST-u32e; / 4 /以下語(yǔ)句是避免 u16k,u32m,u32l被優(yōu)化掉 i = u16k; i = (uint16)u32m; i = (uint16)u32l; 運(yùn)行語(yǔ)句1 后, 結(jié)構(gòu)體中的 u8a = 0 x000 x02 u8a = 0 x030 x06 u16c = 0 x0807 u32d = 0 x0C0B0A09 u32e = 0 x100F0E0D 顯然以

22、上結(jié)果是我們所需要的,正確! 但繼續(xù)運(yùn)行 2,3,4得到 u16k = 0 x0706 u32m = 0 x080B0A09 u32l = 0 x0C0F0E0D 字節(jié)對(duì)齊發(fā)生了問(wèn)題,亂了! 亂得還不輕 u32m 沒(méi)有等于0 x0B0A0908 u32m 沒(méi)有等于0 x0B0A0908 u32m 也沒(méi)有等于0 x0F0E0D0C why? 我試圖用u16k = (uint16)(pTST-u16c); u32m = (uint32)pTST-u32d; 去修改,但無(wú)效! 其實(shí)pTST-u16c本身就是16位的,強(qiáng)制轉(zhuǎn)到16位自然沒(méi)有任何意義。 你說(shuō)的情況對(duì)于ARM CPU確實(shí)存在,但對(duì)于其它體

23、系結(jié)構(gòu)就不會(huì)出現(xiàn) 這是一個(gè)典型的ARM非對(duì)齊訪問(wèn)的問(wèn)題。#pragma pack(1)能保證你的結(jié)構(gòu)體中的數(shù)據(jù)是緊縮對(duì)齊的(在內(nèi)存中是依次排列的)。那么對(duì)于 #pragma pack(1) typedef struct uint8 u8a3; uint8 u8b4; uint16 u16c; uint32 u32d; uint32 u32e; TSTBLK,* PTSTBLK; 假設(shè)該結(jié)構(gòu)體存放的基地址為0,則u8a3位于02字節(jié), u8b4位于36字節(jié),u16c位于78字節(jié),依次類推。那么當(dāng)我們?nèi)ピL問(wèn)u16c時(shí)編譯器會(huì)編譯成一條訪問(wèn)地址為7的半字讀的匯編語(yǔ)言,而地址為7對(duì)于半字讀來(lái)說(shuō)是一個(gè)非

24、對(duì)齊訪問(wèn),CPU就自動(dòng)會(huì)把地址變成把最低位忽略,也是說(shuō)CPU讀的實(shí)際地址為6,于是讀u16c得到的是6 、7兩個(gè)字節(jié)即u16c=0 x0706。對(duì)于字的訪問(wèn)CPU會(huì)忽略低兩位地址,分析方法與前相同。你的兩個(gè)32位數(shù)我不能理解,你怎么可能得到那樣的結(jié)果,是不是寫錯(cuò)了哦?我覺(jué)得你應(yīng)該分別得到0 x0B0A0908 0 x0F0E0D0C才對(duì)。當(dāng)然還涉及一個(gè)字節(jié)序的問(wèn)題。 這一個(gè)問(wèn)題在ARM CPU中會(huì)出現(xiàn),但對(duì)于POWERPC的CPU或X86的CPU你的代碼就不會(huì)出現(xiàn)問(wèn)題,這都是CPU對(duì)非對(duì)齊訪問(wèn)采用的處理方式不同造成,POWERPC X86 會(huì)把非半字的非對(duì)齊訪問(wèn)變成兩個(gè)字節(jié)訪問(wèn),因?yàn)椴粫?huì)出現(xiàn)上

25、面問(wèn)題。MIPS我沒(méi)有去研究過(guò)。 對(duì)于ARM CPU把結(jié)構(gòu)體改為: #pragma pack(1) typedef struct uint8 u8b4; uint32 u32d; uint32 u32e; uint16 u16c; uint8 u8a3; TSTBLK,* PTSTBLK; 整個(gè)結(jié)構(gòu)體仍然只占23個(gè)字節(jié),但應(yīng)該不會(huì)出現(xiàn)前面的問(wèn)題。 _packed 能解決問(wèn)題 謝謝大家,用_packed 可以解決問(wèn)題,但我沒(méi)理解_packed 和#pragma pack(1)的區(qū)別,請(qǐng)問(wèn)誰(shuí)能再解釋得清楚些? 我先前的實(shí)驗(yàn)結(jié)果確實(shí)是 u32m = 0 x080B0A09 u32l = 0 x0C0

26、F0E0D 為什么不是0 x0B0A0908 和0 x0F0E0D0C,原因不詳 我不同意更改結(jié)構(gòu)體,因?yàn)閿?shù)據(jù)結(jié)構(gòu)是規(guī)定死了,不能隨意改 對(duì)于ARM CPU把結(jié)構(gòu)體改為: #pragma pack(1) typedef struct uint8 u8b4; uint32 u32d; uint32 u32e; uint16 u16c; uint8 u8a3; TSTBLK,* PTSTBLK; uboot中,ARM體系下,設(shè)置變量4字節(jié)對(duì)齊 調(diào)試程序遇到由于buffer地址不是4字節(jié)對(duì)齊,所有底層去: u32 *p =(u32 *)buf; 使得數(shù)據(jù)拷貝有誤。所以,去參考了uboot中其他人的做

27、法: boards1845flash.c中的: #define _align_ _attribute_ (aligned (8) static _align_ ulong precmd02 = 0 x00aa00aa, 0 x00aa00aa ; 所以,此處就可以這么做,使一個(gè)字符數(shù)組變量4字節(jié)對(duì)齊的: static _attribute_ (aligned (4) unsigned char data_bufMAX_PAGE_SIZE; 【含義解釋】 ARM 的 RealView中的解釋: 4.4.2. _attribute_(aligned) aligned 類型屬性指定類型的最低對(duì)齊要求

28、。 Note 此類型屬性是 ARM 編譯器支持的 GNU 編譯器擴(kuò)展。 Copyright ? 2007-2009 ARM Limited. All rights reserved. Non-Confidential, Unrestricted Access ARM DUI 0348BC 4.5.3 _attribute_(aligned) aligned 變量屬性指定變量或結(jié)構(gòu)字段的最低對(duì)齊要求(按字節(jié)計(jì)算)。 注意 此變量屬性是 ARM 編譯器支持的 GNU 編譯器擴(kuò)展。 示例 int Variable_Attributes_aligned_0 _attribute_ (aligned (

29、16); short Variable_Attributes_aligned_13 _attribute_ (aligned); 2.1.157 -unaligned_access, -no_unaligned_access 此選項(xiàng)啟用或禁用基于 ARM 體系結(jié)構(gòu)的處理器上的未對(duì)齊數(shù)據(jù)訪問(wèn)。 缺省設(shè)置 對(duì)于支持未對(duì)齊數(shù)據(jù)訪問(wèn)的基于 ARM 體系結(jié)構(gòu)的處理器,缺省為 -unaligned_access。這包括: ? 基于 ARMv6 體系結(jié)構(gòu)的所有處理器 ? 基于 ARMv7-A 和 ARMv7-R 體系結(jié)構(gòu)的處理器。 對(duì)于不支持未對(duì)齊數(shù)據(jù)訪問(wèn)的基于 ARM 體系結(jié)構(gòu)的處理器,缺省為 -no_u

30、naligned_access。這包括: ? 基于 ARMv6 以前版本的體系結(jié)構(gòu)的所有處理器 ? 基于 ARMv7-M 體系結(jié)構(gòu)的處理器。 用法 -unaligned_access 在支持未對(duì)齊數(shù)據(jù)訪問(wèn)的處理器(如 -cpu=ARM1136J-S)上使用 -unaligned_access 可加快對(duì)壓縮結(jié)構(gòu)的訪問(wèn)速度。 若要啟用未對(duì)齊支持,必須執(zhí)行下列操作: ? 在初始化代碼中清除 CP15 寄存器 1 的 A 位(即位 1)。 ? 在初始化代碼中設(shè)置 CP15 寄存器 1 的 U 位(即位 22)。 U 位的初始值由內(nèi)核的 UBITINIT 輸入確定。 RVCT 庫(kù)包含旨在利用未對(duì)齊訪問(wèn)的

31、某些庫(kù)函數(shù)的特殊版本。在啟 用未對(duì)齊訪問(wèn)支持的情況下,RVCT 工具將使用這些庫(kù)函數(shù)從未對(duì) 齊訪問(wèn)中獲益。 -no_unaligned_access 使用 -no_unaligned_access 可在 ARMv6 處理器上禁止生成未對(duì)齊 字和半字訪問(wèn)。 若要在不使用未對(duì)齊訪問(wèn)的情況下在 ARMv6 目標(biāo)上啟用對(duì)四字節(jié) 求模的對(duì)齊檢查,必須執(zhí)行下列操作: ? 在初始化代碼中設(shè)置 CP15 寄存器 1 的 A 位(即位 1)。 ? 在初始化代碼中設(shè)置 CP15 寄存器 1 的 U 位(即位 22)。 U 位的初始值由內(nèi)核的 UBITINIT 輸入確定。 注意 ARM 處理器內(nèi)核不支持未對(duì)齊雙字訪問(wèn),例如對(duì) long long 整數(shù)的 未對(duì)齊訪問(wèn)。雙字訪問(wèn)必須是八字節(jié)或四字節(jié)對(duì)齊的。 編譯器不支持對(duì)八字節(jié)求模的對(duì)齊檢查。也就是說(shuō),編譯器(或 更具體地說(shuō)是 RVCT 工具集)不支持 CP15 寄存器 1 中的配置 U = 0、A = 1。 RVCT 庫(kù)包含旨在利用未對(duì)齊訪問(wèn)的某些庫(kù)函數(shù)的特殊版本。若要 在禁用未對(duì)齊訪問(wèn)支持的情況下禁止使

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論