在指令集级别防止未对齐访问

Preventing unaligned accesses at the instruction set level

是否存在使用非字节地址来防止未对齐访问的指令集?

据我所知,大多数架构在任何地方都使用字节地址,但会对未对齐的访问进行惩罚或抛出异常。

在指令级别防止这种情况是否有意义,例如bstr 存储字节使用字节地址,dstr 使用字地址存储字,qstr 使用四边形地址存储四边形等等?因此,没有例外也没有惩罚,作为奖励,它甚至可以增加可访问内存的范围space(否则会浪费较低的位)。

根据我能找到的有关 x86、ARM、Alpha、Itanium 等的信息,它们总是使用字节寻址,但要求用户确保某些指令仅用于对齐地址,从而导致运行时 exception/penalty,而不是 "statically" 通过使用与相关类型兼容的地址来避免它。

我错过了什么吗?还是有更深层次的理由喜欢这种方式(例如简化编译器)?

instead of "statically" avoiding it by using addresses compatible with the types in question.

非常容易静态地(在编译时)避免在 int* 上使用非 4 的倍数偏移量进行指针数学运算。编译器对此并不困难;在 C 中,您必须投射到 uintptr_t 并返回,或者使用其他技巧来使 int*.

不对齐

在硬件中检查对齐地址非常便宜(只需检查低 3 位是否为零)。如果您只关心快速 -路径快。 Load/stores 已经必须能够对虚拟内存进行页面错误。

这不是真正需要解决的问题

需要对齐的字节可寻址内存的缺点loads/stores浪费了那些低地址位。 (或者当然,如果您确实遇到未对齐的加载或存储有用的问题,那么效率低下,那么无论出于何种原因,无法执行它们都是一个问题。)

在现实生活中,是的,有时候我们的对齐确实比我们想要的要少,检测程序因此运行缓慢的情况可能很有用。我们在现代 x86 上有性能计数器。 (甚至是对齐检查标志,但这几乎无法使用,因为标准库和编译器假定它未设置。)


有一些字寻址机器,包括一些现代 DSP。但是他们仍然只有一个 "scale" 地址,地址 space 的任何部分都不是字节可寻址的。

Or is there a profound reason to prefer it this way (e.g. simplifying compilers)?

是的,有。如果您想在将数组用于 bool 的数组或 char 的字符串之前有效地将其归零,则可以使用 8 字节或更宽的 SIMD 存储进行归零。 使用相同的地址,您将用于字节访问相同的数据。这只是一个例子。

想要使用更广泛的加载或存储来复制 struct 的多个元素的情况并不少见。说到这里,结构将如何工作? 通常结构的基址有一个地址,并且可以从该地址以固定偏移量访问任何成员。使用您的方案,您是否必须右移地址以撤消 qld 的隐式左移?


此外,像 malloc 这样的内存分配器可以使用相同的地址,而不管其调用者想要如何使用内存。您是否必须将地址(通过移动)缩放回某个标准比例以 free 它?

同一个存储单元有多个地址 "aliasing" 并且往往会导致问题。

或者您认为字节地址-space 与 qword 地址-space 完全不相交?如果是这样,您如何有效地将数据从一个复制到另一个而不能一次存储超过 1 个字节?也许对于每个地址都可用的 SIMD loads/stores-space?

或者内存的底部 4GiB 是字节可寻址的(以及字、双字和 qword),高于 4 到 8GiB 的范围只能作为 16 位或更宽的块寻址?上面的下一个 8GiB 只能用作 32 位块? (dstr 地址范围的上半部分)。等等

如果是这样,您是否为每个大小都有一个单独的 malloc 分配器,所以如果您需要可以按字节访问的内存,它仅限于低 4GiB(32 位 bstr地址 = 32 位的低 29 位 qstr 地址-space?) 因为您有一些内存不能用作字节访问。 qstr 地址 space 可以被认为是隐式左移 3 以创建一个按 8 字节对齐的 35 位字节地址。

这听起来真的很难处理,或者至少不符合软件所习惯的标准模型,而这在C语言中是有体现的。使用分段这样的机制来扩展会更正常您的地址 -space 统一,因此您可以将其中任何一个用于字符串、字节数组等。

我想虚拟内存仍然可以在固定大小的物理页面方面工作,并且 OS 可以使用其中之一支持有效 35 位虚拟地址 space 中的任何虚拟页面4k 页。但这意味着 qstr 的页面边界只有 4096/8 = 512 个 qword 地址大。

(我假设这些示例的寄存器宽度为 32 位。如果您有 64 位寄存器,则不需要任何不便的技巧来扩展地址 space,您可以使用字节地址。)