3

众所周知,许多 CPU 架构(ARM、PPC)不能读取奇数地址,但如果强制也会产生异常,还有一些可以,但速度稍慢。(x86)

但是是否有任何 CPU 只能处理完整的 32 位(甚至更大!)字?即它不能寻址 16 位字?也许是amd64?

我正在尝试编写一个可移植但快速的 C malloc 类分配器,并希望正确对齐我的内存访问。目前我的目标是 ARM、i386 和 amd64,我可以查找这些特性,但我认为保持警惕会很好。

我想提出我的问题的具体方法是;

是否有 CPU 从地址 0x2 读取 16 位(假设为了论证,通常 0 附近的地址范围是有效的,我知道有些 CPU 不使用第一页)会产生总线错误,其中 CPU =任何 MIPS、ARM、x86、amd64、68k、88000、SH、OpenRISC、Sparc、PPC、Cell/SPE?

(顺便说一下,我是从 C 程序员的角度来看这整件事。所以我假设 C 编译器给了我所有正常的 C 类型,比如 char、uint32_t 等)

4

3 回答 3

2

一些早期的 IBM Power 处理器只能在项目大小边界上读/写,但会使用陷阱(异常)处理程序处理未对齐的数据。(而且我认为甚至有一个早期版本会说“OK”并默默地给你对齐单词的内容,忽略你地址的低位。)

可以肯定的是,旧的 IBM 7000 系列机器只能在 36 位边界(字长)上读/写一个完整的字,因为没有比这更精细的地址概念了。但我相信他们有读/写低/高半字操作。

HP 2100 系列处理器 IIRC 只有字(16 位)地址,但可以进行字节索引。但是,该索引仅被解释为字节操作的字节索引——否则它是一个单词索引。

但是,就对齐 malloc 而言,您通常应该在缓存行边界上对齐。否则很难防止缓存抖动是 MP 环境。

于 2012-12-13T23:22:48.997 回答
2

Cell 的 SPE 只有 16 字节的四字加载/存储,并且必须在 16 字节边界上对齐。

如果您需要以更精细的粒度进行处理,则必须读取-修改-写入,并使用位掩码仅更新数据的相关部分。

显然,在 C/C++ 中,编译器会对此提供帮助,并且指令集中支持生成和使用掩码。

对于从地址“2”读取 16 位的示例,您必须从地址“0”读取 128 位并屏蔽所需的位。如果您想将 16 位写入地址“2”,则需要先读取所有 128 位,然后更新相应的 16 位,然后将全部写回。

于 2012-12-13T23:24:34.650 回答
0

如果您可以寻址 16 位数量,那么您肯定可以读取 16 位对齐数量。我想您可能假设您将拥有一个字节可寻址的地址空间。您可能不会,因此建议谨慎。可以肯定的是,某些架构(特别是嵌入式架构)可能不是字节可寻址的,甚至不是 16 位可寻址的——尽管我不知道具体的(和当前的)示例。

这真的重要吗?如果您碰巧有一台可字寻址的机器,具有 32 位可寻址字长,那么您实际上永远不可能只寻址 16 位。不过要小心 sizeof。

您询问了 amd64 (x86-64)。它对内存对齐访问没有限制,但您可能会因未对齐访问而丢失周期。请记住,未对齐的访问永远不会是可移植的。

更新:什么是对齐地址?

T 类型的对齐地址是 sizeof(T) 的倍数的任何地址,其中 sizeof(T) 是值占用的可寻址单元的数量。例如,如果您在字节可寻址空间中有 32 位字长,则对齐的地址至少是 4 的每倍数。但是,如果机器可按 16 位单元寻址,那么每个地址都是 4 的倍数2 将是 32 位数量的对齐地址。

如果你读的是 16 位的量,有三种情况:

  1. 字节寻址:奇数地址可能未对齐。架构可以自由地将这些视为对齐,但也没有。
  2. 可寻址单元为 16 位:所有地址都针对 16 位数量对齐。
  3. 可寻址单元更大:您实际上没有 16 位数量。它们默默地变大了。

更新 2:是否有 CPU 从地址 0x2 读取 16 位(假设地址范围有效)会产生总线错误?

永远不可能有这样的 CPU,除非可寻址单元低于 8 位。原因是地址0x2的对齐是2个可寻址单元。如果可寻址单元是 8 位,则它是 16 位对齐的。

此外,16 位的意图排除了可寻址单元大小的奇怪值。如果 16 位值是体系结构的实数,则可寻址单元必须是 16 倍。所以它只能是 1、2、4、8 或 16 位。如果它恰好更高,则对齐很容易满足。

由于寻址少于 8 位的架构不值得麻烦,您几乎可以保证地址 0x2 将是 16 位数量的对齐地址。

于 2012-12-13T22:28:26.933 回答