arm的工作狀態(tài)
第一種是arm狀態(tài),處理器執(zhí)行32位的字對齊的arm指令
本文引用地址:http://m.butianyuan.cn/article/201611/319255.htm第二種是thumb狀態(tài),此時處理器執(zhí)行16位的半字對齊thumb指令
隨時切換,不影響處理器工作模式和相應(yīng)寄存器內(nèi)容
-----------------------------------------------------
以下內(nèi)容摘自http://www.cnblogs.com/yin-jingyu/archive/2011/10/14/2211252.html
一、啥是字對齊?為啥要字對齊?
字節(jié)對齊的原因大致是如下兩條:
1、平臺原因(移植原因):不是所有的硬件平臺都能訪問任意地址上的任意數(shù)據(jù)的;某些硬件平臺只能在某些地址處取某些特定類型的數(shù)據(jù),否則拋出硬件異常。
2、性能原因:數(shù)據(jù)結(jié)構(gòu)(尤其是棧)應(yīng)該盡可能地在自然邊界上對齊。原因在于,為了訪問未對齊的內(nèi)存,處理器需要作兩次內(nèi)存訪問;而對齊的內(nèi)存訪問僅需要一次訪問。
二、對齊規(guī)則
規(guī)則:
1. 數(shù)據(jù)成員對齊規(guī)則:結(jié)構(gòu)(struct)(或聯(lián)合(union))的數(shù)據(jù)成員,第一個數(shù)據(jù)成員放在offset為0的地方,以后每個數(shù)據(jù)成員的對齊按照#pragma pack指定的數(shù)值和這個數(shù)據(jù)成員自身長度中,比較小的那個進行。
2. 結(jié)構(gòu)(或聯(lián)合)的整體對齊規(guī)則:在數(shù)據(jù)成員完成各自對齊之后,結(jié)構(gòu)(或聯(lián)合)本身也要進行對齊,對齊將按照#pragma pack指定的數(shù)值和結(jié)構(gòu)(或聯(lián)合)最大數(shù)據(jù)成員長度中,比較小的那個進行。
3. 結(jié)合1、2可推斷:第一、如果n大于等于該變量所占用的字節(jié)數(shù),那么偏移量必須滿足默認的對齊方式,第二、如果n小于該變量的類型所占用的字節(jié)數(shù),那么偏移量為n的倍數(shù),不用滿足默認的對齊方式。
三、X86對齊實驗
1. 數(shù)據(jù)類型自身的對齊值:對于char型數(shù)據(jù),其自身對齊值為1字節(jié),對于short型為2字節(jié),對于int,float,double類型,其自身對齊值為4字節(jié)。
2. 結(jié)構(gòu)體的自身對齊值:其成員中自身對齊值最大的那個值。
3. 指定對齊值:#pragma
4. 數(shù)據(jù)成員和結(jié)構(gòu)體的有效對齊值:數(shù)據(jù)成員(數(shù)據(jù)類型)和數(shù)據(jù)結(jié)構(gòu)的自身對齊值和指定對齊值中小的那個值,數(shù)據(jù)成員對齊了數(shù)據(jù)結(jié)構(gòu)自然也就對齊了。
了解上述四個基本概念,我們開始討論具體數(shù)據(jù)結(jié)構(gòu)的成員和其自身的對齊方式。有效對齊值N是最終用來決定數(shù)據(jù)存放地址方式的值。有效對齊N,就是表示“對齊在N上”,也就是說該數(shù)據(jù)的"存放起始地址%N=0"。而數(shù)據(jù)結(jié)構(gòu)中的數(shù)據(jù)變量都是按定義的先后順序來排放的。第一個數(shù)據(jù)變量的起始地址就是數(shù)據(jù)結(jié)構(gòu)的起始地址。結(jié)構(gòu)體的成員變量要對齊排放,結(jié)構(gòu)體本身也要根據(jù)自身的有效對齊值圓整(結(jié)構(gòu)體成員變量占用總長度需要是對結(jié)構(gòu)體有效對齊值的整數(shù)倍)。下面結(jié)合VS2005中編譯環(huán)境的例子進行深入了解:
例子B分析:
struct B
{
char b;
int a;
short c;
};
假設(shè)B從地址空間0x0000開始排放。該例中沒有顯式指定對齊值N,VS2005默認值為4。
成員變量b自身對齊值是1,比指定或默認指定對齊值4小,故有效對齊值為1,其存放地址0x0000符合0x0000%1=0,滿足字節(jié)對齊原則。
成員變量a自身對齊值為4,和指定或默認指定對齊值4相等,故有效對齊值也為4,為了保證字節(jié)對齊,成員變量a只能存放在起始地址為0x0004到0x0007這四個連續(xù)的字節(jié)空間中,復核0x0004%4=0。
成員變量c自身對齊值為2,比指定或默認指定對齊值4小,故有效對齊值為2,可順序存放在0x0008至0x0009兩個字節(jié)空間中,符合0x0008%2=0。
至此滿足了數(shù)據(jù)成員的字節(jié)對齊,接著看數(shù)據(jù)結(jié)構(gòu)B的對齊。數(shù)據(jù)結(jié)構(gòu)B的自身對齊值為其變量中最大對齊值(也就是成員變量b)4,故結(jié)構(gòu)體B的有效對齊值也是4。根據(jù)結(jié)構(gòu)體圓整的要求, 0x0009到0x0000=10字節(jié),(10+2)%4=0。所以0x0000A到0x000B也為結(jié)構(gòu)體B所占用。故B從0x0000到0x000B 共有12個字節(jié),sizeof(struct B)=12。
之所以在變量C補充2字節(jié),是因為要實現(xiàn)編譯器快速有效的存取結(jié)構(gòu)數(shù)組,試想如果定義B結(jié)構(gòu)數(shù)組,第一個結(jié)構(gòu)起始地址是0沒有問題,但是第二個結(jié)構(gòu)呢?按照數(shù)組的定義,數(shù)組中所有元素都是緊挨著的,如果不把結(jié)構(gòu)的大小補充為對齊值(4)的整數(shù)倍,那下一個結(jié)構(gòu)的起始地址將是0x0000A,這顯然不能滿足結(jié)構(gòu)的地址對齊了。
例子C分析:
__align(2) struct C
{
char b;
int a;
short c;
};
四、ARM平臺的對齊問題
在ARM中,有ARM和Thumb兩種指令。
ARM指令:每執(zhí)行一條指令,PC的值加4個字節(jié)(32bits).一次訪問4字節(jié)內(nèi)容,該字節(jié)的起始地址必須是4字節(jié)對齊的位置上,即地址的低兩位為bits[0b00],也就是說地址必須是4的倍數(shù)。
Thumb指令:每執(zhí)行一條指令,PC的值加2個字節(jié)(16bits).).一次訪問2字節(jié)內(nèi)容,該字節(jié)的起始地址必須是2字節(jié)對齊的位置上,即地址的低兩位為bits[0b0],也就是說地址必須是2的倍數(shù)。
五、ARM平臺字節(jié)對齊關(guān)鍵字
1. __align(num)
A、在匯編中使用LDRD或者STRD時,就用到此命令__align(8)進行修飾限制。來保證數(shù)據(jù)對象是相應(yīng)對齊。
B、該修飾對象的命令最大是8個字節(jié)限制,可讓2字節(jié)的對象進行4字節(jié)
C、 __align是存儲類修改,他只修飾最高級類型對象不能用于結(jié)構(gòu)或者函數(shù)對象。
2. __packed
__packed是進行一字節(jié)對齊。
A、不能對packed的對象進行對齊;
B、所有對象的讀寫訪問都進行非對齊訪問;
C、float及包含float的結(jié)構(gòu)聯(lián)合及未用__packed的對象將不能字節(jié)對齊;
D、__packed對局部整形變量無影響;
D、強制由unpacked對象向packed對象轉(zhuǎn)化是未定義,整形指針可以合法定
義為packed __packed int* p; //__packed int 則沒有意義。
3. __unaligned
六、如何查找與字節(jié)對齊方面的問題
如果出現(xiàn)對齊或者賦值問題首先查看:
1. 編譯器的big little端設(shè)置;
2. 看這種體系本身是否支持非對齊訪問;
3. 如果支持看設(shè)置了對齊與否,如果沒有則看訪問時需要加某些特殊的修飾來標志其特殊訪問操作。
七、結(jié)論
typedef struct tag_T_MSG{
long ParaA;
long ParaB;
short ParaC;
char ParaD;
char Pad;
} T_MSG;
評論