非對齊地址訪問問題
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對對齊要求的更嚴格些,非對齊訪問可能會帶來效能上的損失。這對程式在不同架構間移植非常重要,因為它極有可能導致你的程式崩潰。