谈谈对齐(下)
3 数据对齐
3.1 CISC和RISC
CPU从指令集的特点上可以分为两类:CISC和RISC。CISC和RISC分别是复杂指令集计算机(Complex Instruction Set Computer)和精简指令集计算机(Reduced Instruction Set Computer)的缩写。
CPU的工作可以看作以下步骤的反复循环:
- step 1: 取指令
- step 2: 取数据
- step 3: 执行指令
- step 4: 输出结果
CISC CPU支持很多寻址模式,因此取数据的时间是不确定的。 RISC CPU的最大特点是简化了指令的寻址模式,除了Load/Store指令外,其它指令都采用寄存器寻址,即从寄存器读写数据。这种设计使取数据的时间相对稳定,可以简化指令流水线的设计。
一般而言,RISC架构可以降低CPU的复杂性以及允许在同样的工艺水平下生产出功能更强大的CPU,但对于编译器的设计有更高的要求。
3.2 对齐数据访问
RISC CPU的Load/Store指令要求数据是对齐的。长度为4的数据应放在4n边界上,长度为2的数据应放在2n边界上。以ARM CPU的Load为例:
LDR R5,[R4]
LDRSH R7,[R6]
LDRB R9,[R8]
LDR、LDRSH、LDRB分别从存储器读取一个字、半字和字节,放到指定寄存器。例如“LDR R5,[R4]”就是从R4指向的存储单元中读一个字(长度为4),放到R5中。 LDR要求数据地址在4n边界上,否则就会发生错误。LDRSH要求数据地址在2n边界上,否则就会发生错误。
发生什么错误呢?这与具体的CPU有关,在ARM7TDMI上,非对齐访问会导致程序跳到数据访问错误的处理向量,即地址0x00000010处。在ARM920T上,LDR指令可能返回错误的数据。
CISC的CPU支持非对齐的数据读取。
3.3 例子
我们来看一个例子:
// 例子1
void test(void)
{
char a[] = {1,2,3,4,5};
int *pi, i;
printf("&a[1]=%p\n", &a[1]);
pi = (int *)&a[1];
i = *pi;
printf("%08X\n", i);
}
关键是这句:
i = *pi;
我们知道地址pi指向的4个字节依次是:0x02,0x03,0x04,0x05。在小尾的CPU上,我们期待的输出是05040302。让我们看看这段代码在不同平台的运行效果。
3.3.1 PC/Windows
输出结果是:
&a[1]=0012FF25
05040302
符合我们的预期,也说明PC的CPU支持非对齐的数据读取。
3.3.2 PC/Linux
输出结果是:
&a[1]=0xbfa0c36c
05040302
值得注意的是gcc编译器将局部变量a放在了1n边界(0xbfa0c36b)上。我们希望pi是一个奇数地址,将测试代码修改为:
// 例子2
void test(void)
{
int a[] = {0x04030201, 0x08070605};
int *pi, i;
pi = (int *)&((char *)&a)[1];
printf("pi=%p\n", pi);
i = *pi;
printf("%08X\n", i);
}
输出结果是:
pi=0xbfe87fe9
05040302
符合我们的预期。数据对齐是CPU的问题,和编译器、操作系统没有关系。
3.3.3 ARM920T/Linux
输出结果是:
&a[1]=0xbec49e55
01040302
考虑到小尾,CPU实际读到的4个字节依次是0x02,0x03,0x04,0x01。这个结果不是我们所预期的,CPU出错了。
3.3.4 ARM7TDMI
程序在执行:
i = *pi;
时直接跳回Data Abort的处理向量,即地址0x00000010。
3.4 对策
在读取紧缩结构或结构的紧缩成员时,编译器会自动产生按字节读取的代码。我们只要在做强制指针转换时细心一些就可以了。我们不应该将指向窄数据的指针强制转换成指向宽数据的指针。在可能发生数据对齐问题的地方,按字节读取数据。
4 结束语
我很欣赏一本叫作《玫瑰的名字》的小说。这是一本侦探小说,但给了我不少编程的启示。威廉教士在迷宫内解不开谜团,在迷宫外却推理出迷宫的真相。我也倾向于在头脑中调试程序,调试器只是不得已而用之。身陷其中,既会改变要测试的对象,也可能被表象迷惑。从外面观察,通过想象推理,有时更容易发现真相,或抓住调试的重点。本文讨论了一些与对齐相关的细节。多了解一些细节,有助于我们在头脑中形成更清晰的程序映像。
分享到:
相关推荐
allegro自动对齐工具,PCB设计布局、元件摆放等对其工具。Allegro小工具简单实用,支持元器件、丝印、管教、过孔等的自动对齐,多种对齐方式可选。
内存对齐,值得一读的内容, 内存对齐,值得一读的内容, 内存对齐,值得一读的内容, 内存对齐,值得一读的内容,
u盘一键4K对齐工具,U盘出现需要初始化、格式化、识别但是报错多半是数据偏移,对齐一下还能继续用。 注意:一键对齐数据会丢失,工具软件只适用于数据不重要或者没有数据的优盘 u盘一键4K对齐工具,U盘出现需要初始...
在ckeditor 4.1两端对齐按钮插件中加入text-justify:inter-ideograph,以支持中文两端对齐显示。
本程序实现人脸对齐功能,它通过提取人脸特征,利用PCA降维,实现人脸对齐效果
本文主要讲了什么是字节对齐,为什么要对齐,已经应该注意的一些问题,下面一起来看看
AutoCad对象对齐,均布对象工具,包括左对齐、居中对齐,右对其,上对其、下对齐等6种对其方式,此外还有指定点对其,指定对象对齐,均布工具有垂直均布、水平均布等8种均布方式,还包括指定间距均布,制定范围均布...
在串行数据传输中,数据接收端需要一些特定的信息来恢复出正确的字边界,以确定串行码流中哪些比特属于原始并行数据里的同一时钟节拍里的数据,这一处理过程称为字对齐(Word Aligner)。一些标准的协议会定义特殊的...
Allegro两种自动对齐方法
CAD文字对齐插件 输入ap点击文件加载 启动命令dq 多种文字对齐方式 多行文字对齐 表格内多行文字对齐 表格内单行文字左对齐 表格内单行文字中对齐
代码注释对齐Visual Studio AddIn 插件
4k对齐软件 547000 -- -- -- -- 0 860 44 计算机技术, 2 硬盘4k对齐 467000 -- -- -- -- 0 1092 45 计算机技术, 3 4k对齐工具 516000 -- -- -- -- 0 427 45 4 无损4k对齐 374000 -- -- -- -- 0 379 16 计算机技术, ...
做这个分区对齐查询,主要是为了方便大家查看电脑分区有没有4K对齐,4K对齐虽说不是什么新技术,但还是有大部分电脑没有对齐的,特别在固态硬盘日益普及的今天,4K对齐就非常有必要了。 另外机械硬盘也要4K对齐,有人测试...
VS2010代码模块对齐线
没有SSD?使用PE一样可以给机械盘4K对齐,大文件提速感觉比较明显。
U盘扇区对齐,一键4K对齐工具 V1.2(U盘扇区对齐.
直接将apk知道bat文件自动对齐 使用命令行 1、在Android SDK的tools文件夹下,找到zipalign.exe文件。 2、把你要优化的apk复制到你解压出来的tools文件夹下。 开始->运行->CMD调出命令行窗口 命令行下输入 你解压的...
css 右对齐css 右对齐css 右对齐css 右对齐css 右对齐css 右对齐css 右对齐css 右对齐css 右对齐css 右对齐css 右对齐css 右对齐css 右对齐css 右对齐css 右对齐css 右对齐css 右对齐
不同的字节对齐下的申请的空间的比较源码! 不错的代码哦!
AStyle_3.1版,keil代码自动对齐,配合快捷键,谁用谁知道。