众所周知,许多CPU架构(ARM,PPC)无法读取奇数地址,但如果强制也会产生异常,而其他人可以,但这样做会稍慢。 (86)
但是有没有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等。)
答案 0 :(得分:2)
一些早期的IBM Power处理器只能读取/写入项目大小的边界,但会使用陷阱(异常)处理程序处理未对齐的数据。 (我认为甚至有一个早期版本会说“OK”并默默地给你对齐单词的内容,忽略你地址的低位。)
非常确定旧的IBM 7000系列盒子只能在36位边界(字大小)上读/写一个完整的字,因为没有比这更精细的地址概念。但我相信他们有读/写低/高半字操作。
HP 2100系列处理器IIRC只有字(16位)地址,但可以进行字节索引。但是,索引只被解释为字节操作的字节索引 - 否则它是一个单词索引。
但是,在对齐malloc时,通常应该在缓存行边界上对齐。否则,很难防止缓存抖动是MP环境。
答案 1 :(得分:2)
Cell的SPE只有16字节的四字加载/存储,并且必须在16字节边界上对齐。
如果需要以更精细的粒度进行寻址,则必须读取 - 修改 - 写入,并使用位掩码仅更新数据的相关部分。
显然,在C / C ++中,编译器会对此有所帮助,并且在指令集中支持生成和使用掩码。
对于从地址“2”读取16位的示例,您必须从地址“0”读取128位并屏蔽掉您需要的位。如果你想写16位来寻址'2',你需要首先读取所有128位,然后更新相应的16位,然后写回整个批次。
答案 2 :(得分:0)
如果您可以处理16位数量,那么您绝对可以读取16位对齐量。我想你可能假设你将有一个字节可寻址的地址空间。你可能没有,所以请注意。绝对可以想象一些架构(特定嵌入式架构)可能不是字节甚至是16位可寻址 - 尽管我不知道具体(和当前)的例子。
这真的重要吗?如果你碰巧有一个可以字寻址的机器,具有32位可寻址的字大小,那么你无论如何也永远不能实际只处理16位。但是要注意sizeof。
你问过amd64(x86-64)。它对内存对齐访问没有限制,但您可能会因未对齐访问而丢失周期。请记住,未对齐的访问永远不会是可移植的。
更新:什么是对齐的地址?
类型T的对齐地址是sizeof(T)的倍数的任何地址,其中sizeof(T)是该值占用的可寻址单元的数量。例如,如果在字节可寻址空间中有32位字大小,则对齐的地址至少是4的每个倍数。但是,如果机器可以以16位为单位进行寻址,那么每个地址都是2将是32位数量的对齐地址。
如果您正在阅读16位数量,则有三种情况:
更新2:是否有CPU从地址0x2读取16位(假设地址范围有效)会产生总线错误?
除非可寻址单元低于8位,否则不可能有这样的CPU。原因是地址0x2的对齐是2个可寻址单元。如果可寻址单元是8位,那么它是16位对齐的。
此外,可寻址单元大小的奇怪值被排除在16位的意图之外。如果16位值是架构的实际数量,则可寻址单元必须是16的因子。因此它只能是1,2,4,8或16位。如果它恰好更高,那么对齐很简单。
由于一个地址小于8位的架构不值得给您带来麻烦,因此您可以保证地址0x2将成为16位数量的对齐地址。