對ARM處理器的記憶體對齊問題 譯)

2021-07-13 10:30:56 字數 3372 閱讀 3458

origin: 

介紹可以對齊不對齊的記憶體訪問。對齊的記憶體訪問發生時的資料都位於其自然大小邊界。例如,如果該資料型別的大小是4個位元組,那麼它屬於被4整除的記憶體位址是位於其自然大小邊界。未對齊的記憶體訪問發生在所有其他情況下(在上面的例子中,記憶體位址時,是不能被4整除)。 arm處理器的設計有效地訪問對齊的資料。在arm處理器上試圖訪問未對齊的資料會導致不正確的資料或顯著的效能損失(這些不同的症狀會在稍後討論)。與此相反,大多數cisc型處理器(即x86)的訪問未對齊的資料是無害的。 這份檔案將討論一些比較常見的方式,乙個應用程式可能會執行未對齊的記憶體訪問,並提供一些建議的解決方案,以避免這些問題, 。 

症狀上述問題,適用於所有arm架構。然而,根據mmu(記憶體管理單元)和作業系統支援的可用性,應用程式可能會看到不同的行為在不同的平台上。預設情況下,未對齊的記憶體訪問不會被困住了,會導致不正確的資料。與功能的mmu的平台上,但是,os捕獲非對齊訪問,它在執行時進行糾正。其結果將是正確的資料,但在10-20 cpu週期的成本。

常見原因

上述問題的型別轉換適用於所有arm架構。然而,根據mmu(記憶體管理單元)和作業系統支援的可用性,應用程式可能會看到不同的行為在不同的平台上。預設情況下,未對齊的記憶體訪問不會被困住了,會導致不正確的資料。與功能的mmu的平台上,但是,os捕獲非對齊訪問,它在執行時進行糾正。其結果將是正確的資料,但在10-20 cpu週期的成本。

**:

void my_func(char *a)
這個簡單的例子,可能會導致未對齊的記憶體訪問,因為我們不能保證的char * a是乙個4位元組的邊界上對齊。只要有可能,應避免這種型別的施放。

使用資料緩衝區

未對齊的記憶體訪問的最常見的原因源於不正確地處理資料緩衝區。這些資料緩衝區可能包含任何資料從usb埠讀取,通過網路,或從乙個檔案中。這個資料是很常見的包裝,有沒有插入填充,以確保資料在緩衝區內位於其自然大小邊界。在這個例子中,我們會考慮的情況下,從檔案載入的windows bmp和解析的頭。 的windows bmp檔案包含乙個頭的畫素資料。的標頭是由兩個結構: 

**:

typedef packed struct  header;

typedef packed struct infoheader;

請注意,在的header和infoheader結構的大小,分別為14和40位元組。 讓我們假設我們要確定在執行時的影象的寬度和高度。的**來訪問這些資料可能看起來像這樣: 

**:

#define infoheader_offset (sizeof(header))

#define width_offset (infoheader_offset + offsetof(infoheader, width))

#define height_offset (infoheader_offset + offsetof(infoheader, height))

int imagewidth, imageheight;

void * filebuf;

pme->mfile = ifilemgr_openfile(pme->mfilemgr, "test.bmp", _ofm_read);

if (pme->mfile)

}}

注意的寬度和高度的偏移量。因為他們屬於乙個半字邊界上,以上述方式訪問這些值會導致未對齊的記憶體訪問。下面列出的一些推薦的方法來避免這個問題。

推薦的解決方案

使用memcpy

我們的第乙個選項是,只需執行memcpy從緩衝區中的資料到本地變數:

**:

if (result == fileinfo.dwsize)

其結果是,儲存器被複製位元組逐字節,避免任何疑問對準。 

包裝的編譯器指令

或者,我們可以使用壓縮的編譯器指令允許使用指標,直接將我們需要的資料,同時迫使編譯器來處理對齊問題。在brew環境中,packed被定義如下:

**:

#ifdef __armcc_version

#define packed __packed

#else

#define packed

#endif

包裝形式,通過指定乙個指標,arm編譯器將生成相應的說明來正確地訪問記憶體,無論對齊。修改後的版本,上面的例子中,使用packed指標,如下: 

**:

#define infoheader_offset (sizeof(header))

#define width_offset (infoheader_offset + offsetof(infoheader, width))

#define height_offset (infoheader_offset + offsetof(infoheader, height))packed uint32 * pimagewidth;

packed uint32 * pimageheight;uint32 imagewidth, imageheight;

void * filebuf;

pme->mfile = ifilemgr_openfile(pme->mfilemgr, "test.bmp", _ofm_read);

if (pme->mfile)

}}

雖然程式設計師通常會無法控制標準化的資料格式,如bmp頭在上面的例子中,當你定義自己的資料結構應確保奠定了良好的對齊方式中的資料定義對齊的資料結構。下面的基本示例演示了這樣的原則:

**:

#ifdef __armcc_version

typedef packed struct bad_struct;

typedef struct good_struct;

通過簡單地重新排列中,我們宣告的結構成員,我們可以解決一些對齊的問題。另外請注意,如果未宣告為包裝,bad_struct,編譯器通常會插入填充,每個字段對齊。然而,這通常是不希望的,因為它浪費記憶體和避免幾乎總是可以簡單地通過宣告為了減小尺寸的字段。 

brew模擬器測試

brew模擬器3.1.2及以上版本提供了能夠使資料對齊檢查。brew模擬器啟用此功能時,將顯示乙個對話方塊,通知您的每乙個未對齊的記憶體訪問,並為您提供的選項對這一問題視而不見,或闖入的** ,請參閱brew sdk使用者文件一節揗isaligned資料異常支援更多資訊,此功能。注:由於x86架構的訪問未對齊的資料不會有任何問題,你可以不編譯模擬器的dll使用__packed指令(packed這就是為什麼在win32環境下的空白被定義為)。這意味著,通過使用packed指標的非對齊訪問,解決依舊會觸發在模擬器的對齊檢查。 

arm處理器下的對齊異常1 簡介

什麼是對齊異常呢,為什麼arm處理器下會有對齊異常?這個要先從arm 32位處理器下的兩條指令ldr與str說起。作為a32指令集的兩條最基本指令,str ldr 可以用於暫存器與記憶體之間的資料交換,ldr是將記憶體中的數載入到暫存器,str是將暫存器中的數載入記憶體。a32下ldr與str一次操...

arm處理器模式和arm處理器狀態的區別

arm處理器狀態 arm微處理器的工作狀態一般有兩種,並可在兩種狀態之間切換 第一種為arm狀態,此時處理器執行32位的字對齊的arm指令 第二種為thumb狀態,此時處理器執行16位的 半字對齊的thumb指令。在程式的執行過程中,微處理器可以隨時在兩種工作狀態之間切換,並且,處理器工作狀態的轉變...

解析ARM架構處理器對伺服器變革影響

說起伺服器給人們的印象首先是昂貴 操作複雜需專人維護,而很少會有人知道伺服器的架構平台。之前市場上所應用的大多數伺服器平台主要以x86架構為主,無論是x86結構。arm結構都是一種微處理器體系結構的泛稱,x86的強項在於大規模資料處理,arm的強項在於通訊 功耗控制。目前傳統的x86架構擁有一套完整...