1. 程式人生 > >ARM Linux中的非對齊記憶體訪問(Alignment trap警告的原因)

ARM Linux中的非對齊記憶體訪問(Alignment trap警告的原因)

ARMv5指令集的CPU(一般是arm9架構)預設不支援非對齊記憶體訪問,ARMv6及以上的CPU預設支援處理大部分的非對齊記憶體地址訪問。對齊指的是起始地址是一個word長度的整數倍,通常是4位元組對齊。
通過設定/proc/cpu/alignment檔案內容可修改核心中對非對齊地址訪問的處理。

[email protected](none):~# cat /proc/cpu/alignment
User:           3905290
System:         0
Skipped:        0
Half:           0
Word:           0
DWord:          2672136
Multi:          1233154
User faults:    2 (fixup)

這個檔案中最後一行"User faults"即是核心中如何處理非對齊的記憶體地址訪問,這個值是一個點陣圖

#define UM_WARN  (1 << 0)
#define UM_FIXUP (1 << 1)
#define UM_SIGNAL (1 << 2)

UM_WARN:只給出“Alignment trap”警告。
UM_FIXUP:嘗試正確處理非對齊的記憶體地址。
UM_SIGNAL:發生非對齊地址訪問時,傳送SIGBUS訊號通知相應程序。
幾種處理方式可以進行組合,例如設定為(UM_WARN | UM_FIXUP),就是在fixup的同時給出警告資訊。如果設定為0則為ignore。

對於ARMv5的CPU,User faults的值預設是0,即忽略非對齊的地址訪問,這時如果程序訪問了非對齊的地址,就會導致程式執行異常。如果程式中不得不存在非對齊的地址訪問,可以設定為fixup:

echo 2 > /proc/cpu/alignment

這樣的話,核心就會做額外的工作以使訪問非對齊記憶體地址可以得到正確的結果。

對於ARMv6及以上的CPU,CPU本身就要求支援對非對齊地址訪問的處理,因此基本不用關心/proc/cpu/alignment裡設定的值,不過對於像LDM, STM, LDRD和STRD這些複合指令進行的非對齊地址訪問,仍需要軟體協助處理,在這些CPU中,/proc/cpu/alignment預設設定為2(fixup)。

具體的處理方式詳見核心程式碼arch/arm/mm/alignment.c:alignment_init(), hook_fault_code(), do_alignment()。

在不支援非對齊記憶體訪問的晶片上,進行強制型別轉換就要注意了,例如下面的例子:

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>

void sigbus_handler(int sno)
{
 printf("signal %d captured\n", sno);
 exit(1);
}

int main(int argc, char *argv[])
{
 char intarray[8] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88};
 
 signal(SIGBUS, sigbus_handler);
 
 printf("int1 = 0x%08x, int2 = 0x%08x, int3 = 0x%08x, int4 = 0x%08x\n", 
   *((int *)(intarray + 1)), *((int *)(intarray + 2)), *((int *)(intarray + 3)), *((int *)(intarray + 4)));

 return 0;
}

在支援非對齊訪問系統上的結果如下(小端系統):

[email protected]:~# ./testalign
int1 = 0x55443322, int2 = 0x66554433, int3 = 0x77665544, int4 = 0x88776655

而在不支援非對齊訪問系統上,對/proc/cpu/alignment設定不同的值表現也不相同:

~ # echo 0 > /proc/cpu/alignment
~ # ./testalign
int1 = 0x11443322, int2 = 0x22114433, int3 = 0x33221144, int4 = 0x88776655
~ #
~ # echo 2 > /proc/cpu/alignment
~ # ./testalign
int1 = 0x55443322, int2 = 0x66554433, int3 = 0x77665544, int4 = 0x88776655
~ #
~ # echo 1 > /proc/cpu/alignment
~ # ./testalign
Alignment trap: testalign (979) PC=0x0000860c Instr=0xe5931000 Address=0xbef6fc99 FSR 0x001
Alignment trap: testalign (979) PC=0x0000860c Instr=0xe5931000 Address=0xbef6fc99 FSR 0x001
int1 = 0x11443322, int2 = 0x22114433, int3 = 0x33221144, int4 = 0x88776655
~ #
~ # echo 4 > /proc/cpu/alignment
~ # ./testalign
signal 7 captured
~ #

當然也可以設定為3,在正確處理非對齊地址訪問的同時給出警告。

我們可以使用char型別來對非對齊的記憶體進行讀寫來避免非對齊地址的處理,或使用memcpy這類函式來避免賦值或強制型別轉換帶來的問題。
看下面的例子:

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <string.h> /* memcpy */

struct pack_info {
 unsigned char sno;
 unsigned int len;
} __attribute__((packed));

void sigbus_handler(int sno)
{
 printf("signal %d captured\n", sno);
 exit(1);
}

int main(int argc, char *argv[])
{
 signal(SIGBUS, sigbus_handler);

 struct pack_info * mem_cos = (struct pack_info *)malloc(sizeof(struct pack_info));
 if (!mem_cos)
  return 1;
 
 unsigned int * cy_len = &mem_cos->len;
 mem_cos->sno = 0x12;
 mem_cos->len = 0x55667788;
 
 /* 1. 給成員變數賦值 */
 mem_cos->len = 0xaabbccdd;
 
 /* 2. 給指標cy_len的值賦值 */
 *cy_len = 0xaabbccdd;
 
 /* 3. 通過memcpy賦值 */
 unsigned int cy_len_i = 0xaabbccdd;
 memcpy(cy_len, &cy_len_i, 4);

 printf("sno = %#x, len = %#x\n", mem_cos->sno, mem_cos->len);
 
 free(mem_cos);

 return 0;
}

由於給struct pack_info加上了__attribute__((packed))屬性,所以它的len成員的地址不是4位元組對齊的。
上面的程式碼用三種方式給len成員賦值,在不支援非對齊訪問系統上,第二種方式就會有問題,不能得到預期的結果。

相關推薦

ARM Linux中的非記憶體訪問Alignment trap警告原因

ARMv5指令集的CPU(一般是arm9架構)預設不支援非對齊記憶體訪問,ARMv6及以上的CPU預設支援處理大部分的非對齊記憶體地址訪問。對齊指的是起始地址是一個word長度的整數倍,通常是4位元組對齊。 通過設定/proc/cpu/alignment檔案內容可修改核心中

關於Cortex M0 核不支援非記憶體訪問的問題

最近把STC15W4K上的程式轉移到NV32F100上遇到了非對齊訪問的問題。 解決辦法是: 編譯器(Keil或IAR)會幫你解決。 但是你得告訴他。 用 __packed 修飾定義的結構體,就是告訴它,這個可能是非對齊訪問,你幫我解決。 (PS:我用的IAR,沒試

arm-linux-androideabi-gcc 預定義巨集編譯器版本4.8

列印方法: touch test.c arm-linux-androideabi-gcc -E -dM -c test.c >> marco_arm.txt #define __DBL_MIN_EXP__ (-1021) #define __HQ_FBIT__

JavaScript實現拖拽元素到網格每次移動固定距離

做了一個gif圖,可以看到,每次元素的移動都是按照最小單位距離移動的。且每次元素都是對齊到網格的。 先根據demo說明一下思路和細節,後面會給出demo程式碼。 1. 確定元素的每次移動的最小單位(demo中為10px和10px),也就是每次水平或垂直的位移量都是10px。鋪上一層網格背景是為了幫助

轉載:OpenCV中的指針alignPtr

art 開始 程序 alloc 個數 sizeof 內存地址 申請 指向 轉載地址:https://www.tuicool.com/articles/q2QrQr 在某些架構上,只有能被指定數(如4,16)整除的內存地址才能夠被訪問,否則程序會crash,或者出現錯誤的結果

C語言結構體(記憶體問題)

C語言結構體對齊也是老生常談的話題了。基本上是面試題的必考題。內容雖然很基礎,但一不小心就會弄錯。寫出一個struct,然後sizeof,你會不會經常對結果感到奇怪?sizeof的結果往往都比你宣告的變數總長度要大,這是怎麼回事呢?     開始學的時候,

RelativeLayout的屬性大全LinearLayout不可用

<!-- android:layout_above 將該控制元件的底部至於給定ID的控制元件之上 android:layout_below 將該控制元件的頂部至於給定ID的控制元件之下

ARM Linux 3.x的裝置樹Device Tree

宋寶華 Barry Song <[email protected]>本文部分案例和文字英文原版來源於 http://devicetree.org/Device_Tree_Usage1.    ARM Device Tree起源Linus Torvalds

ARM Linux 3.x 的裝置樹Device Tree之DTB、DTS

1、ARM Device Tree起源 Linus Torvalds在2011年3月17日的ARM Linux郵件列表宣稱“this whole ARM thing is a f*cking pain in the ass”,引發ARM Linux社群的地震,

賓西法尼亞大學強制標註軟體P2FA介紹以及使用說明

一、綜述 1. 介紹 賓夕法尼亞大學語音標籤強制對齊(Penn Phonetics Lab Forced Aligner , P2FA) 是基於 HTK 的自動語音標註工具包。它包括美式英語的聲學模型,用來強制對齊的 python 檔案以及 readme

ARM linux kernel啟動流程 head.S

1. kernel執行的史前時期和記憶體佈局 在arm平臺下,zImage.bin壓縮映象是由bootloader載入到實體記憶體,然後跳到zImage.bin裡一段程式,它專門於將被壓縮的kernel解壓縮到KERNEL_RAM_PADDR開始的一段記憶體中,接著跳進真

ARM編譯器中的使用__align和__packed

以下是我整理的__align和__packed的使用,希望對大家有用 1.__align(num)  __align __align 關鍵字指示編譯器在 n 位元組邊界上對齊變數。 __align 是一個儲存類修飾符。它不影響函式的型別。 語法 __align(n) 其

unix/linux 位元組

/* * aligned.c * * Created on: 2016-2-24 * Author: xfhu */ #include <stdio.h> /*

Linux 位元組問題

今天寫一個小程式,需要使用msg在兩個不同程式間進行通訊; 兩個程式中msg的文字結構體都是一樣的,直接複製過去的,結果執行的時候出現錯誤:msgrcv: Argument list too long 這個錯誤的原因是 msgrcv 中的引數msglen 小於訊息佇列裡要讀

Linux核心原始碼分析--記憶體管理一、分頁機制

        Linux系統中分為幾大模組:程序排程、記憶體管理、程序通訊、檔案系統、網路模組;各個模組之間都有一定的聯絡,就像蜘蛛網一樣,所以這也是為什麼Linux核心那麼難理解,因為不知道從哪裡開始著手去學習。很多人會跟著系統上電啟動 BIOS-->bootse

Linux中的記憶體管理分段和分頁

前一段時間看了《深入理解Linux核心》對其中的記憶體管理部分花了不少時間,但是還是有很多問題不是很清楚,最近又花了一些時間複習了一下,在這裡記錄下自己的理解和對Linux中記憶體管理的一些看法和認識。 我比較喜歡搞清楚一個技術本身的發展歷程,簡而言之就是這個技術是怎麼發

ARM下的處理

from DUI0067D_ADS1_2_CompLib 3.13 type  qulifiers 有部分摘自ARM編譯器文件對齊部分 對齊的使用: 1.__align(num)    這個用於修改最高級別物件的位元組邊界。在彙編中使用LDRD或者STRD時   

位元組詳解-----(二)ARM下的處理

                                                                                   ARM下的對齊處理 from DUI0067D_ADS1_2_CompLib 3.13 type  qul

地址訪問問題

 ARM,DSP,POWERPC等不支援非對齊地址訪問,X86支援非對齊地址訪問。 為何要位元組對齊?  從理論上講似乎對任何型別的變數的訪問可以從任何地址開始,但實際情況是在訪問特定型別變數的時候經常在特定的記憶體地址訪問,各個硬體平臺對儲存空間的處理上有很大的不同。一

解決make:arm-linux-gcc :command not found有效

錯誤提示: arm-linux-gcc: Command not found 原因: 1)沒有在~/.bashrc 或者/etc/environment中新增交叉編譯工具鏈bin檔案路徑 解決方法: ①使用sudo tar  xjvf xxxxxxxxx.tar.bz