內(nèi)存未對齊是指cpu要讀取N字節(jié)數(shù)據(jù),但數(shù)據(jù)的起始地址不能被N所整除,導(dǎo)致效率降低,甚至異常的出現(xiàn)。例如當(dāng)cpu讀取一個int類型的變量,而變量地址是0x10005的時候就產(chǎn)生未對齊訪問。
自然對齊:
N字節(jié)的數(shù)據(jù)類型需要放在起始地址為被N整除的地址這稱為自然對齊。并不是所有體系結(jié)構(gòu)的計算機(jī)帶都要求自然對齊,有的可以指定對齊方式。但是為了達(dá)到好的可移植性編寫代碼的時候最好都用自然對齊方式。
未對齊的影響
未對齊的內(nèi)存訪問在不同的體系結(jié)構(gòu)中會有不同的效果:有一些計算機(jī)可以透明的處理未對齊訪問,但效率會降低很多;有一些計算機(jī)會產(chǎn)生異常,然后調(diào)用一個異常處理程序改正錯誤;有一些計算機(jī)產(chǎn)生異常,但是沒有辦法校正錯誤;有一些計算機(jī)則沒有辦法處理未對齊訪問,而直接讀取不正確的內(nèi)存地址,造成難以察覺的代碼漏洞。
編譯器的影響:
一般情況下編譯器可以通過填充(padding)使得數(shù)據(jù)結(jié)構(gòu)滿足對齊要求。例如一下結(jié)構(gòu):
Struct foo{
U16 field1;
U32 field2;
U8 field3;
}
假設(shè)數(shù)據(jù)起始地址是0x10000.編譯器在field1后填充2個字節(jié)使field2保持對齊,最后在field3后填充3個字節(jié)使整個數(shù)據(jù)結(jié)構(gòu)4對齊,全部結(jié)構(gòu)體占用空間為12字節(jié)。
導(dǎo)致未對齊訪問的原因:
既然編譯器能夠自動對齊數(shù)據(jù)結(jié)構(gòu),導(dǎo)致內(nèi)存未對齊訪問的原因是什么?未對齊訪問的
必要條件:指針強(qiáng)制類型轉(zhuǎn)換且小數(shù)據(jù)轉(zhuǎn)大數(shù)據(jù)。例如:
unsigned int compare_ether_addr(const u8 *addr1, const u8 *addr2)
{
const u16 *a = (const u16 *)addr1;
const u16 *b = (const u16 *)addr2;
return ((a[0] ^ b[0]) | (a[1] ^b[1]) | (a[2] ^ b[2])) != 0;
}
Addr1指針?biāo)诘刂房赡苁瞧娴刂烽_頭,強(qiáng)制類型轉(zhuǎn)化給指針a,導(dǎo)致未對齊的內(nèi)存訪問。Mips架構(gòu)的cpu不能很好的處理未對齊訪問,會導(dǎo)致程序出錯退出。X86可以處理未對齊,但是如果未對齊訪問太多效率也會下降很多。不管是Mips,還是X86,都希望所操作地址是對齊的,因?yàn)檫@樣可以最快速地處理數(shù)據(jù)。不過X86平臺可以很容易很快速地處理不對齊的情況,而Mips一旦遇到地址不對齊的變量就會拋出exception,從而調(diào)用一大段后續(xù)處理代碼,繼而消耗大量的時間。
解決方案:應(yīng)該使用memcpy()函數(shù)進(jìn)行代替指針強(qiáng)制類型轉(zhuǎn)換。
Linux內(nèi)核對unalignedacess的處理方法:
可以配置/proc/sys/debug/alignment的參數(shù)以配置內(nèi)核對內(nèi)存未對齊訪問的處理方式,總共有6中可選,"ignored","warn","fixup","fixup+warn","signal","signal+warn",可以配置的值和含義:
0 warn 觸發(fā)內(nèi)核打印消息包含程序名稱、Pid、PC寄存器值,指令,地址,出錯碼。
1 fixup 內(nèi)核嘗試修復(fù)未對齊訪問異常,這會導(dǎo)致性能降低。
2 signal 這個配置會引發(fā)SIGBUS錯誤,程序退出。
請查看內(nèi)核說明(cat /proc/cpu/alignment)以確定選擇那種處理方式所對應(yīng)的數(shù)字。
內(nèi)存未對齊處理示例:
問題描述:
編譯webkit源碼后在Freeman 9150(mips架構(gòu),sh4linux)運(yùn)行出現(xiàn)unaligned access,SIGBUS錯誤,程序退出:
Unaligned userspace access in "QtTestBrowser" pid=1636 pc=0x2a012f6a ins=0x01ce
Unaligned userspace access in "QtTestBrowser" pid=1636 pc=0x29f4ad7a ins=0x5111
Sending SIGBUS to "QtTestBrowser" due to unaligned access (PC 29f4ad7a PR 29f4ac6e)
解決辦法:
1、 在linux終端輸入ulimit –c unlimited開啟core dump功能。
2、 修改/proc/sys/kernel/core_uses_pid,使用pid作為core dump文件的擴(kuò)展名;修改/proc/sys/kernel/core_pattern(例如/corefile/core%p)設(shè)置core文件保存位置和文件格式。
3、 使用gdb查看出錯信息,定位代碼。 gdb ./ QtTestBrowser core.xxxx, 使用bt命令即可看到程序出錯的地方。
4、查看源碼,修改錯誤,注意查看指針轉(zhuǎn)化的情況。用memcpy()代替相關(guān)代碼。聯(lián)系客服