ARM,DSP,POWERPC等不支持非對齊地址訪問,X86支持非對齊地址訪問。
爲何要字節對齊?
從理論上講似乎對任何類型的變量的訪問可以從任何地址開始,但實際情況是在訪問特定類型變量的時候經常在特定的內存地址訪問,各個硬件平臺對存儲空間的處理上有很大的不同。一些平臺對某些特定類型的數據只能從某些特定地址開始存取。
TCPIP協議棧一直採用的uip,感覺不是很好,想採用網上的流行的lwip協議,移植中出現了個有趣的問題,找了好半天才找到,是字節對齊問題,用下面這個例子說一下(我用的是KEIL)
在KEIL下測試結構
unsigned long * testzy;
testzy =(unsigned long *)0x0400130e;
* testzy = 0x11223344; //0x0400130C(44 33 22 11) * testzy 真實值變成了 0x00001122
反彙編看
R0=0x11223344;
R1=0x0400130e;
STR R0,[R1] ; 顯然由於地址0x0400130e不是4的倍數,數據向前移動了 (R0=0x00001122,而不是0x44332211)
但在IAR測試下,結果又是正確的。
在ADS測試下,也會有問題
在lwip出現問題的地方,是mem_malloc()分配內存(通過固定數組ram)時候錯誤,
ram起始地址在KEIL下不是4的整數倍,在ADS是(怪異)
所以即使採樣了#define MEM_ALIGNMENT 4 // Must be 4 for ARM system
上面定義只是保證了數組ram存數據保證4的倍數開始??
這樣系統通過mem_malloc分配內存的地址並沒有按四個字節的倍數來分(KEIL測試下),這樣往導致分配好後的地址(該地址不是4的倍數)賦值的時候出錯
ARM內存訪問的對齊問題
按照ARM文檔上的描述,其訪問規則如下:
1. 一次訪問4字節內容,該內容的起始地址必須是4字節對齊的位置上;
2. 一次訪問2字節內容,該內容的起始地址必須是2字節對齊的位置上;
(單字節的沒有這個問題,就不用考慮啦。 )
計算機主要的架構就分爲兩類,複雜指令集計算機(CISC)和精簡指令集計算機(RISC)。CISC最有代表性的架構就是x86,RISC最有代表性的架構就是ARM。不管是什麼架構,對要訪問的一定長度的數據的地址是有要求的,比如要訪問一個32位的整數,那麼這個數據必須(最好)存儲在以4字節(32/8=4)對齊的地方。一般來說,RISC對對齊要求的更嚴格些,非對齊訪問可能會帶來性能上的損失。這對程序在不同架構間移植非常重要,因爲它極有可能導致你的程序崩潰。