结构与数组的对齐规则冲突

iMr*_*lix 2 x86 struct memory-alignment page-tables

正如标题所暗示的,问题是关于Linux 上 x86-64 中聚合类型的对齐

在我们的讲座中,教授介绍了结构(及其元素)与附加幻灯片的对齐方式。因此,我会假设(根据维基百科和其他讲座材料)对于任何聚合类型,对齐是根据其最大成员。不幸的是,在以前的考试问题中似乎并非如此,它说:

“假设每个页表 [4kB,每个 PTE 64b] 都存储在内存中一个“自然对齐”的物理地址(即一个表大小的整数倍的地址),......”

为什么对于页表(它基本上是内存中的 8 字节值的数组),对齐规则不是根据最大的元素,而是根据整个表的大小?

非常感谢澄清!
菲利克斯 讲座幻灯片

Mar*_*oom 7

为什么页表按其大小对齐

对于转换虚拟地址的过程的给定级别,要求当前页表在其大小(以字节为单位)上对齐会加快索引操作。
CPU 不需要执行实际添加来查找下一级页表的基址,它可以缩放索引,然后替换当前级别基址中的最低位。

您可以通过几个例子说服自己确实如此。
x86 也遵循这种对齐方式并非巧合。

例如,对于 x86 CPU 的 4KiB 页的 4 级分页,64 位地址的页目录指针字段是 9 位宽。
该表(PDPTE)中的每个条目都是 64 位,因此页面大小为 4096KiB,最后一个条目的偏移量为 511 * 8 = 4088(十六进制为 0xff8,因此最多只使用 12 位)。
页目录指针表的地址由 PML4 条目给出,这些条目没有指定基址的低 12 位(用于其他目的),仅指定高位。
CPU 可以简单地用 PDPTE 的偏移量替换 PML4 条目中的低 12 位,因为我们已经看到它有 12 位大小。

这在硬件中既快速又便宜(无需携带,易于使用寄存器)。

假设一个国家/地区的邮政编码由两个字段组成:城市代码 (C) 和块代码 (D),加在一起。
另外,假设给定城市最多可以有 100 个块代码,所以 D 是 2 位数字长。
要求城市代码在 100 上对齐(这意味着 C 的最后两位数字为零)使得 C + D 就像用 D 替换 C 的最后两位数字一样。(1200 + 34 = 12|34)。

与聚合对齐的关系

页表不被视为一个集合,即一个 8 字节元素的数组。它被视为一种自己的类型,由 CPU 的 ISA 定义,并且必须满足使用它的 CPU 特定部分的要求。
Page walker 发现将页表按其大小对齐很方便,因此这是必需的。

聚合对齐是编译器用来在内存中分配对象的一组规则,它保证每个元素对齐都得到满足,以便指令可以访问任何元素而不会出现对齐惩罚/错误。
加载和存储的执行单元是 CPU 中与页面遍历器不同的部分,因此需要不同。

您应该使用聚合对齐来了解编译器将如何对齐您的结构,然后检查这是否足以满足您的用例

存在异常

请注意,教授在解释其自然边界上的对齐对页表意味着什么方面走了很长一段路。
存在例外情况,如果您被告知必须在 X 上对齐基准,您可以假设涉及一些硬件技巧/简化并尝试查看哪个,但最后您只需进行对齐并继续。