我刚刚发现ARM正在编写代码(Cortex M0),不支持未对齐的内存访问。
现在在我的代码中我使用了很多打包结构,而且我从来没有得到任何警告或硬错误,那么当它不允许未对齐访问时,Cortex如何访问这些结构的成员?
答案 0 :(得分:9)
gcc等编译器了解对齐方式,并会发出正确的指令来解决对齐问题。如果你有一个打包的结构,你会告诉编译器它,所以它提前知道如何进行对齐。
假设您使用的是32位架构,但其struct
包含如下:
struct foo __attribute__((packed)) {
unsigned char bar;
int baz;
}
当访问baz
时,它将在32位边界上执行内存加载,并将所有位移位。
在这种情况下,它可能是地址bar
的32位加载和地址bar
+ 4的32位加载。然后它将应用一系列逻辑运算,如作为移位和逻辑或/和在32位寄存器中以baz
的正确值结束。
查看程序集输出以查看其工作原理。您会注意到,未对齐访问的效率低于这些体系结构上的对齐访问。
答案 1 :(得分:0)
在许多较旧的8位微处理器上,有加载(和存储)寄存器的指令,这些寄存器大于存储器总线的宽度。这种操作将通过从一个地址加载一半寄存器来执行,而另一半从下一个更高地址加载。即使在存储器总线宽于8位宽(例如,16位)的系统上,将存储器视为可寻址的字节集合通常也是有用的。从任何地址加载一个字节将导致处理器读取16位存储器位置的一半而忽略另一半。从偶数地址读取16位值将使处理器读取整个16位存储器位置并使用整个存储器;该值将与读取两个连续字节地址并连接结果相同,但它将在一次操作中读取而不是两次。
在某些此类系统上,如果尝试从奇数地址读取16位值,处理器将使用一个值的一半和另一个值的另一半读取两个连续的地址,就好像已经执行了一样两个单字节读取并组合结果。这称为未对齐的内存访问。在其他系统上,这样的操作将导致总线故障,这通常会触发某种形式的中断,这种中断可能会或可能不会对它做一些有用的事情。支持未对齐访问的硬件相当复杂,设计代码以避免未对齐访问通常不会太困难。因此,这种硬件通常只存在于已经非常复杂的处理器上,或者将运行为处理器设计的代码的处理器,这些处理器将组装来自单字节读取的多字节寄存器(例如,在8088上,每16位)读取需要两个8位内存提取,并且在以后的英特尔处理器上运行了很多8088代码。