Embedded 当我的CPU没有';不支持未对齐的内存访问?

Embedded 当我的CPU没有';不支持未对齐的内存访问?,embedded,arm,structure,memory-alignment,cortex-m,Embedded,Arm,Structure,Memory Alignment,Cortex M,我刚刚发现我正在编写代码的ARM(Cortex M0)不支持未对齐的内存访问 现在,在我的代码中,我使用了很多压缩结构,我从来没有收到任何警告或硬错误,所以当不允许未对齐的访问时,皮质如何访问这些结构的成员 诸如gcc之类的编译器了解对齐,并将发出正确的指令来解决对齐问题。如果你有一个压缩结构,你会告诉编译器关于它的事情,这样它就会提前知道如何进行对齐 假设您使用的是32位体系结构,但有一个struct,其打包方式如下: struct foo __attribute__((packed)) {

我刚刚发现我正在编写代码的ARM(Cortex M0)不支持未对齐的内存访问


现在,在我的代码中,我使用了很多压缩结构,我从来没有收到任何警告或硬错误,所以当不允许未对齐的访问时,皮质如何访问这些结构的成员

诸如gcc之类的编译器了解对齐,并将发出正确的指令来解决对齐问题。如果你有一个压缩结构,你会告诉编译器关于它的事情,这样它就会提前知道如何进行对齐

假设您使用的是32位体系结构,但有一个
struct
,其打包方式如下:

struct foo __attribute__((packed)) {
   unsigned char bar;
   int baz;
}
当访问
baz
时,它将在32位边界上进行内存加载,并将所有位移位到位

在这种情况下,它可能会导致
地址的32位加载和
+4地址的32位加载。然后,它将应用一系列逻辑操作,如移位和逻辑或/和,以32位寄存器中的正确值
baz
结束


查看程序集输出以了解其工作原理。您会注意到,在这些体系结构上,未对齐的访问比对齐的访问效率低。

在许多旧的8位微处理器上,有加载(和存储)寄存器的指令,这些寄存器的宽度大于内存总线的宽度。这样的操作将通过从一个地址加载寄存器的一半,从下一个更高的地址加载另一半来执行。即使在内存总线宽度大于8位(例如,16位)的系统上,将内存视为可寻址的字节集合通常也是有用的。从任何地址加载字节都会导致处理器读取16位内存位置的一半,而忽略另一半。从偶数地址读取16位值将导致处理器读取整个16位内存位置并使用整个内容;该值将与读取两个连续字节地址并连接结果时的值相同,但它将在一次操作而不是两次操作中读取


在某些这样的系统上,如果试图从奇数地址读取16位值,处理器将使用一个值的一半和另一个值的另一半读取两个连续地址,就像执行了两次单字节读取并合并了结果一样。这称为未对齐内存访问。在其他系统上,这样的操作将导致总线故障,这通常会触发某种形式的中断,而这种中断可能会或可能不会对总线故障做出有用的处理。支持未对齐访问的硬件相当复杂,设计避免未对齐访问的代码通常不太困难。因此,这样的硬件通常只存在于已经非常复杂的处理器上,或者运行代码的处理器上,这些代码是为将单字节读取组装多字节寄存器的处理器设计的(例如,在8088上,每16位读取需要两次8位内存回迁,并且许多8088代码在更高版本的英特尔处理器上运行)。

在任何体系结构上,未对齐通常效率较低。例如,x86使用未对齐访问会受到惩罚(如果访问跨越自然总线/内存边界,例如0x1F处的32位访问)您应该非常小心地使用_u属性_((打包))这是危险的。如果您的代码采用&foo->bar地址并将其传递给另一个函数,会发生什么:未对齐内存访问!结论,您还没有解决您的问题。