第3章“程序的机器级表示”:对齐(alignment)

  许多计算机系统对基本数据类型的可允许地址做出了一些限制,要求某种类型的对象的地址必须是某个值 k k k (通常是2、4 或 8)的倍数。这种 对齐限制 简化了处理器和存储器系统之间接口的硬件设计。例如,假设一个处理器总是从存储器中取出 8 个字节出来,则地址必须是 8 的倍数。如果能保证所有的 double 都将它们的地址对齐成 8 的倍数,那么久可以用一个存储器操作来读或者写值了。否则,可能需要执行两次存储器访问,因为对象可能分放在两个 8 字节存储器块中。

  无论数据是否对齐,IA32 硬件都能正确工作。不过,Intel 还是建议要对齐数据以提高存储器系统的性能。Linux 沿用的对齐策略是 2 字节数据类型(例如 short)的地址必须是 2 的倍数,而较大的数据类型(例如 intint *floatdouble)的地址必须是 4 的倍数。注意,这个要求就意味着一个 short 类型对象的地址的最低位必须等于0。类似地,任何 int 类型的对象或指针的地址的最低两位必须都是0。

Microsoft Windows 的对齐

Microsoft Windows 对对齐的要求更严格——任何 k k k 字节(基本)对象的地址都必须是 k k k 的倍数。特别的,它要求一个 double 的地址应该是 8 的倍数。这种要求提高了存储器性能,代价是浪费了一些空间。Linux 中的设计决策可能对 i386 很好,以前存储器十分缺乏,而存储器总线只有 4 个字节宽。对于现代处理器来说,Microsoft 的对齐策略就是更好的选择了。

命令行选项 -malign-double 会使 Linux 上的 GCC 为 double 类型的数据使用 8 字节的对齐。这会提高存储器性能,但是在与用 4 字节对齐方式下编译的库代码链接时,会导致不兼容。

  确保每种数据类型都是按照指定方式来组织和分配的,即每种类型的对象都满足它的对齐限制,就可保证实施对齐。编译器在汇编代码中放入命令,指明全局数据所需的对齐。例如,3.6.6 小节中跳转表的汇编代码声明的第2行就包含下面这样的命令(directive):

.align 4

  这就保证了它后面的数据(在此,是跳转表的开始)会从以 4 的倍数的地址处开始。因为每个表项长 4 个字节,后面的元素都会遵守 4 字节对齐的限制。

  分配存储器的库例程(例如 malloc)的设计必须使得它们返回的指针能满足最糟糕情况的对齐限制,通常是 4 或者 8。对于有结构的代码,编译器可能需要在域的分配中插入间隙,以保证每个结构元素都满足它的对齐要求,而结构本身对它的起始地址也有一些对齐要求。

  例如,如下的结构声明:

struct S1 {
	int i;
	char c;
	int j;
};

  假设编译器用的是最小的 9 字节分配,画出图来是这样的:
在这里插入图片描述
  它是不可能满足域 i i i (偏移为 0)和 j j j (偏移为 5)的 4 字节对齐要求的。所以,编译器在域 c c c j j j 之间插入一个 3 字节的间隙(在此用 “XXX” 表示):

在这里插入图片描述
  结果, j j j 的偏移量为 8,而整个结构的大小为 12 字节。此外,编译器必须保证任何 struct S1 * 类型的指针 p p p 都满足 4 字节对齐。用前面的符号,让指针 p p p 的值为 x p x_p xp。那么, x p x_p xp 必须是 4 的倍数。这就保证了 p->i(地址 x p x_p xp)和 p->j(地址 x p + 4 x_p + 4 xp+4)都满足它们的 4 字节对齐要求。

  另外,编译器可能需要添加一些填充到结构的末尾,这样结构数组的每个元素都会满足它的对齐要求。例如,看如下这个结构声明:

struct S2 {
	int i;
	int j;
	char c;
};

  如果将这个结构打包成 9 个字节,只要保证结构的起始地址满足 4 字节对齐要求,仍然能够保证域 i i i j j j 的对齐要求。不过,考虑如下声明:

struct S2 d[4];

  分配 9 个字节,是不可能满足 d d d 的每个元素的对齐要求的,这是因为这些元素的地址分别为 x d x_d xd x d + 9 x_d + 9 xd+9 x d + 18 x_d + 18 xd+18 x d + 27 x_d + 27 xd+27

  编译器会为结构 S1 分配 12 个字节,最后 3 个字节是浪费的空间:

在这里插入图片描述
  这样一来, d d d 的元素的地址分别为 x d x_d xd x d + 12 x_d + 12 xd+12 d d + 24 d_d + 24 dd+24 x d + 36 x_d + 36 xd+36。只要 x d x_d xd 是 4 的倍数,所有的对齐限制就都可以满足了。

你可能感兴趣的:(#,深入理解计算机系统,地址对齐)