ARM学习(11)数据总线/地址总线访问数据过程理解
笔者来聊聊数据总线/地址总线访问数据过程
例子引入
笔者在实际项目中开发的时候,碰到了一个数据访问对齐的data abort 错误,其实这个错误之前就知道,CortexR5 学习的时候了解到的,(异常模式学习(CortexR5)),但是了解的相对比较浅,这次深入的探究一下。
正常来说,访问u32的数据,地址需要4Byte对齐,如果没有要求pack(1)字节对齐的话,如果出现奇数地址,报一个addr Aligment Failed的错误,相当于夸了两个四字节的地址访问。
问题如下:
typedef struct test_data_abort_struct{
u8 data_1;
u8 data_2;
u16 data_3;
u32 data_4;
u32 data_5;
}test_data_abort_t;
u32 test_data = 0x12345678;
void test_func()
{
u8 *ptr = (u8*)&test_data;
printf("ptr=%p\n",ptr);
ptr++; /*产生奇数地址*/
printf("ptr=%p\n",ptr);
u32 value = *(u32*)ptr; /*读取一个奇数地址的数据 */
printf("value =%d ptr=%p\n",value ,ptr);
test_data_abort_t* test_data_z = (test_data_abort_t*)&ptr;
test_data_z->data_1 ++; /*访问 byte 读写*/
test_data_z->data_2 ++; /*访问 byte 读写*/
test_data_z->data_3 ++; /*访问 two byte 读写 奇数地址*/
test_data_z->data_4 ++; /*访问 four byte 读写 奇数地址*/
test_data_z->data_5 ++; /*访问 four byte 读写 奇数地址*/
print("1=%d 1=%d 1=%d 1=%d 1=%d addr=%p\n",test_data_z->data_1,
test_data_z->data_2,
test_data_z->data_3,
test_data_z->data_4,
test_data_z->data_5);
}
一般情况下,arm 大多数用在嵌入式设备中,对于性能有一些极致的要求,所以一些数据访问对地址对齐要求,比如双字节(word)或者 四字节 (dword)对齐,这样就可以提高数据访问速度。
这一点和x86 架构有很大区别,x86 本身对于地址对齐没有要求,但是看汇编,压栈出栈也是四字节对齐(可能是为了方便吧,感觉并不是提高速度,而是空间上管理方便),有一点相似性。
接着来说回这个问题,按照之前分分析,下面这条语句正常来说回触发异常,但是确实没有触发。
u32 value = *(u32*)ptr; /*读取一个奇数地址的数据 */
真让我很郁闷,这不是说好的奇地址访问异常嘛,为什么没产生异常,没办法还得看手册。
本身这个处理器的架构是CortexR5,所以就找了相关手册,然后发现了其中的秘密,手册说明如下:
Instructions in the ARM architecture are aligned as follows:
- ARM instructions are word-aligned.
- Thumb and ThumbEE instructions arehalfword-aligned.
- Java bytecodes are byte-aligned.
In the ARMv7 architecture, some load and store instructions support unaligned data accesses, as described in
Unaligned data access.
大体的意思就是 arm指令是四字节地址对齐,thumb指令是两字节地址对齐,java的字节编码单字节地址对齐(没有地址要求),但是在armv7的架构里面,一些load 和 store 指令是支持 非对齐数据访问的,正如下面描述的一样,
An ARMv7 implementation must support unaligned data accesses to Normal memory by some load and store
instructions, as Table A3-1 shows. Software can set the SCTLR.A bit to control whether a misaligned access to
Normal memory by one of these instructions causes an Alignment fault Data Abort exception.
根据上面的描述,可以看到有些指令确实是支持了非对齐访问(比如str、ldr等)。
所以我赶紧去查了汇编代码,发现指令确实落在了支持非对齐访问的指令里面,所以没有对齐也是正常的,
上面ldr r4,0x404AF08,可以从下面看到 0x404AF08 dcd 0x4084834,所以r4= 0x4084834,相当于从ldr r4,[r0] , 而r0=r4,0x404AF08
之后 adds r4,r4,#0x1,r4=0x4084835,如下面打印所示(实际板子运行打印数据)。
最关键的地方,ldr r6,[r4],此时r4为奇地址,但是支持访问,所以没有发生异常。
接着来看,系统控制器 system control register,上面的表格中写到,SCTLR.A 该bit 可以控制将严格控制对齐访问,由于默认是0,禁止严格访问的,所以碰到了笔者刚刚的问题,如果笔者修改该bit为1,则正常应该触发 data abort Aligment Fault。
inline u32 __get_sctlr()
{
u32 __sctrl;
__asm
{
mrc p15,0,__sctrl,c1,c0,0
}
return __sctrl;
}
inline void __set_sctlr(u32 __sctrl)
{
__asm
{
mcr p15,0,__sctrl,c1,c0,0
}
}
u32 sctrl = __get_sctlr();
printf("sctrl=%x\n",sctrl);
sctrl |=0x02;
printf("sctrl=%x\n",sctrl);
经过笔者这一顿操作,再次运行程序,可以看到程序触发异常。
再来确认一下发生异常的位置,可以看到pc = 0x404abc0,出错的数据地址 =0x4044835,恰好是刚刚r4+1的地址。
通过看汇编,确实是加载数据的时候出错了,说明之前的验证都是正确的。
共有 0 条评论