1. 問題
risc 下使用訪存指令讀取或寫入資料單元時,目標位址必須是所訪問之資料單元位元組數的整數倍,這個叫做位址對齊。
計算機主要的架構就分為兩類,複雜指令集計算機(cisc)和精簡指令集計算機(risc)。cisc最有代表性的架構就是x86,risc最有代表性的架構就是arm。不管是什麼架構,對要訪問的一定長度的資料的位址是有要求的,比如要訪問乙個32位的整數,那麼這個資料必須(最好)儲存在以4位元組(32/8=4)對齊的地方。一般來說,risc對對齊要求的更嚴格些,非對齊訪問可能會帶來效能上的損失。這對程式在不同架構間移植非常重要,因為它極有可能導致你的程式崩潰。
從理論上講似乎對任何型別的變數的訪問可以從任何位址開始,但實際情況是在訪問特定型別變數的時候經常在特定的記憶體位址訪問,各個硬體平台對儲存空間的處理上有很大的不同。一些平台對某些特定型別的資料只能從某些特定位址開始訪問。
比 如在 mips 平台上,lh 讀取乙個半字時,儲存器的位址必須是 2 的整數倍; lw 讀取乙個字時,儲存器的位址必須是 4的整數倍; sd 寫入乙個雙字時,儲存器的位址必須是 8 的整數倍。
倘若訪存時,目標位址不對齊,則會引起異常,典型的是系統提示「匯流排錯誤」後,直接殺死程序。
看乙個測試程式(龍芯2e平台):
#include
<
stdio.h
>
#include
<
sys/
sysmips.h
>
unsigned
short
data =;
inline
void
unaligned_access(unsigned
short
*const
row)
intmain()
程式執行後系統提示「非法指令」後退出。
cisc 下(如x86)訪存時,如果目標位址不對齊,cpu 不會陷入異常,因為其內部有處理非對齊訪問的微程式。
2. 解決
高階語言中一般不會遇到這種問題,編譯器常常會處理好資料型別的對齊
。但萬一遇到、抑或在彙編裡遇到,避不開怎麼辦?
可以使用 mips 的指令集裡提供的 lwr/lwl, swr/srl, ldr/ldl, sdr/sdl 指令對非對齊位址進行操作
。關於他們的原理可以用下圖來簡單的示意一下(以ldr/ldl 為例,其他類似):
上**釋的是小端模式下的情況,大端模式的情況則相反:首先 ldl t0, 0(t1),然後再 ldr t0, 7(t1)。
可 以看到無論大端模式還是小端模式,非對齊訪問的解決都是將原來的一條指令(對齊訪問)完成的事分兩步完成,即首先取始位址 addr 到下乙個對齊位址處的部分資料,置入暫存器右部(小端),(大端置入左部(高位)),然後取從該對齊位址到 addr + len - 1 處的部分資料(len 為資料單元長度,半字為2, 雙字為8),置入暫存器左部(小端)。
ldr t0, 0(t1) 取 0x1022~0x1027 到 t0 的右部
ldl t0, 7(t1) 取 0x1028~0x1029 到 t0 的左部
注 意上述指令的字尾 r(right), l(left) 都是相對暫存器而言,load 操作是把取到的部分資料,置入暫存器的 left 或者 right, store 操作是將暫存器中資料的 left 或者 right 部分,寫入目標位址而已。無論大端和小端暫存器的格式都是固定的,即右端為低位,左端為高位。任意第一條 ldr/ldl/lwr/lwl/sdr/sdl/swr/swl 只能訪問記憶體的始位址到下乙個對齊位址處。
非對齊位址訪問問題
arm,dsp,powerpc等不支援非對齊位址訪問,x86支援非對齊位址訪問。為何要位元組對齊?從理論上講似乎對任何型別的變數的訪問可以從任何位址開始,但實際情況是在訪問特定型別變數的時候經常在特定的記憶體位址訪問,各個硬體平台對儲存空間的處理上有很大的不同。一些平台對某些特定型別的資料只能從某些...
MIPS 下非對齊訪問的問題
發表日期 2007 07 23 17 43 1.問題 mips 下使用訪存指令讀取或寫入資料單元時,目標位址必須是所訪問之資料單元位元組數的整數倍,這個叫做位址對齊。比如在 mips 平台上,lh 讀取乙個半字時,儲存器的位址必須是 2 的整數倍 lw 讀取乙個字時,儲存器的位址必須是 4的整數倍 ...
MIPS 下非對齊訪問的問題
mips 下使用訪存指令讀取或寫入資料單元時,目標位址必須是所訪問之資料單元位元組數的整數倍,這個叫做位址對齊。比如在 mips 平台上,lh 讀取乙個半字時,儲存器的位址必須是 2 的整數倍 lw 讀取乙個字時,儲存器的位址必須是 4的整數倍 sd 寫入乙個雙字時,儲存器的位址必須是 8 的整數倍...