是否存在使用非字节地址防止未对齐访问的指令集?
据我所知,大多数体系结构在各处都使用字节地址,但是会对未对齐的访问进行惩罚或抛出异常。
在指令级别上防止这种情况是否有意义,例如bstr
用于存储字节使用字节地址,dstr
使用字地址存储字,qstr
使用四地址存储四元组,等等?因此,没有例外也没有惩罚,而且作为奖励,它甚至可以扩大可访问存储空间的范围(否则浪费了较低的位)。
从我能找到的有关x86,ARM,Alpha,Itanium等的信息来看,它们始终使用字节寻址,但是要求用户确保某些指令仅与对齐的地址一起使用,从而导致运行时异常/惩罚,而不是通过使用与所讨论类型兼容的地址来“静态地”避免这种情况。
我错过了什么吗?还是有很深的理由喜欢这种方式(例如简化编译器)?
答案 0 :(得分:2)
通过使用与所讨论类型兼容的地址来“静态地”避免出现这种情况。
很容易以静态方式(在编译时)避免对int*
进行非4倍偏移的指针数学运算。编译器对此并不费劲。在C语言中,您必须强制转换为uintptr_t
,然后再做其他操作,以使int*
对齐。
在硬件中检查对齐的地址非常便宜(只需检查一下低3位是否为零)。如果您只关心快速路径的建立,则潜在的故障也很便宜。无论如何,加载/存储已经必须能够对虚拟内存进行页面故障处理。
具有对齐要求的加载/存储的字节可寻址存储器的 only 缺点是浪费了那些低地址位。 (或者,当然,如果您确实遇到了问题,即未对齐的装载或存储将很有用,那么无论原因为何,都无法做到这一点。)
在现实生活中,有时候我们的对齐方式确实比我们想要的要少,因此检测由于该程序而导致程序运行缓慢的情况会很有用。我们在现代x86上有针对性的性能计数器。 (甚至还有一个对齐检查标志,但这几乎不可用,因为标准库和编译器认为未设置它。)
有一些字可寻址的机器,包括一些现代的DSP。但是它们仍然只有一个“标度”用于地址,地址空间的任何部分都不是字节可寻址的。
还是有很深的理由更喜欢这种方式(例如简化编译器)?
是的,有。如果要在将数组用于bool
或字符串char
之前有效地将数组归零,则8字节甚至更大的SIMD存储区都可能会发生归零。 使用用于对相同数据进行字节访问的相同地址。那只是一个例子。
使用更大的负载或存储在struct
的多个元素周围复制也很常见。说到哪个,结构如何工作?通常,您为该结构的基址有一个地址,并且可以从该地址以固定的偏移量访问任何成员。对于您的方案,您是否需要右移地址以撤消qld
的隐式左移?
此外,像malloc
这样的内存分配器可以使用相同的地址,而不管其调用者希望如何使用该内存。您是否必须将地址缩放(通过移位)回到某个标准比例以free
?
同一存储单元具有多个地址是“混叠”,并且容易引起问题。
或者您是在想象字节地址空间与qword地址空间完全不相交?如果是这样,您如何有效地将数据从一个复制到另一个而又不能一次存储多个字节?也许每个地址空间都可以使用SIMD加载/存储?
还是底部的4GiB存储器是字节可寻址的(以及word,dword和qword),而高于4G的8GiB范围只能寻址为16位或更宽的块?上面的下一个8GiB只能用作32位块吗? (dstr
地址范围的上半部分)。等
如果是这样,您是否为每种大小都有一个单独的malloc
分配器,因此,如果您需要可以以字节为单位访问的内存,则将其限制为低4GiB(32位bstr
地址= 32位qstr
地址空间的低29位?)因为您有一些不可作为字节访问的内存。 qstr
地址空间可以认为是隐式左移3来创建一个8位对齐的35位字节地址。
这听起来确实很难处理,或者至少不适合软件所使用的标准模型,并且已经包含在C之类的语言中。使用诸如分段之类的机制来扩展地址会更正常-space统一,因此您可以将其用于字符串,字节数组等等。
我猜想虚拟内存仍然可以在固定大小的物理页面上工作,并且操作系统可以使用那些4k页面之一来在有效的35位虚拟地址空间中备份任何虚拟页面。但这意味着qstr的页面边界只有4096/8 = 512个qword地址大。
(在这些示例中,我假设寄存器宽度为32位。如果您有64位寄存器,则不需要任何不便技巧来扩展地址空间,只需使用字节地址即可。)>