就在这周,我在写串口命令的时候,遇到了一个很奇怪的现象,百思不得其解,刚开始以为是自己粗心,对于地址的偏移计算错误,但是经过自己长时间排查,甚至向同事请教,让他们帮我看一下代码逻辑,都没有发现什么异常。一度让我怀疑人生。后面经过我仔细的摸索,终于找出了其中的原因,有种恍然大明白的感觉。所以在这里总结一下,避免其他人也入坑。
我代码的逻辑就不贴图了,知识点其实如下(操作系统为小端):
int main ()
{
char *ptr = "12345678";
int *len =(int*) (ptr + 2);
printf("*len = 0x%08x\n",*len);
}
请问输出多少?
正常情况下,我们的分析思路应该如下:
假设字符串常量"12345678"的首地址是0X1000,那么它的内存地址分布应该是这样的
addr | value | value | value | value |
---|---|---|---|---|
0X1004 | 0X35 | 0x36 | 0x37 | 0x38 |
0X1000 | 0X31 | 0X32 | 0X33 | 0X34 |
则len
指向0x33这个地址,因为len
是int型指针,占四个字节,所以输出0x36353433
。的确,正常情况下应该是这个结果,但是在我这个环境中就不是这样的结果,这就需要引入我们今天的知识点非地址对齐访问。
在进入主题前,我想介绍一下内存字节对齐。相信大家对内存对齐应该都知道,比如我们定义结构体时,会考究成员的顺序,否则造成内存空洞。例如:
struct A{
char a;
int b;
short c;
}
struct B{
char a;
short b;
int c;
}
我们应该都知道A结构体占用的字节应该是12,而B结构体应该是8.至于原因,我想大家应该都是知道的。至于编译器为什么还会进行这种处理,其实的目的有两个:
我们的这个情况就是属于第二种了,并没有得到正确的值。
计算机主要的架构就分为两类,复杂指令集计算机(CISC)和精简指令集计算机(RISC)。CISC最有代表性的架构就是x86,RISC最有代表性的架构就是ARM。不管是什么架构,对要访问的一定长度的数据的地址是有要求的,比如要访问一个32位的整数,那么这个数据必须(最好)存储在以4字节(32/8=4)对齐的地方。一般来说,RISC对对齐要求的更严格些,非对齐访问可能会带来性能上的损失。这对程序在不同架构间移植非常重要,因为它极有可能导致你的程序崩溃。
其中X86平台一般是支持非对齐地址访问,ARM是不支持的。而我们的H10平台就是cpu就是ARM。
ARM内存访问的对齐问题:
按照ARM文档上的描述,其访问规则如下:
因此在访问short型和int型数据是需要注意地址对齐问题。
知道了ARM平台的问题,我们该怎么处理呢?经过查找资料,如下:
ARMv5指令集的CPU(一般是arm9架构)默认不支持非对齐内存访问,ARMv6及以上的CPU默认支持处理大部分的非对齐内存地址访问。对齐指的是起始地址是一个word长度的整数倍,通常是4字节对齐。
通过设置/proc/cpu/alignment文件内容可修改内核中对非对齐地址访问的处理。
root@(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
这样的话,内核就会做额外的工作以使访问非对齐内存地址可以得到正确的结果
参考博客:
https://blog.csdn.net/jasonchen_gbd/article/details/51535018
https://blog.csdn.net/zyboy2000/article/details/4293450