6

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

现在在我的代码中,我使用了很多打包结构,而且我从来没有收到任何警告或硬故障,那么当 Cortex 不允许未对齐访问时,它如何访问这些结构的成员呢?

4

2 回答 2

10

gcc 等编译器了解对齐,并会发出正确的指令来解决对齐问题。如果你有一个打包的结构,你会告诉编译器它,所以它提前知道如何进行对齐。

假设您使用的是 32 位架构,但有一个struct像这样打包的:

struct foo __attribute__((packed)) {
   unsigned char bar;
   int baz;
}

当进行访问时baz,它将在 32 位边界上进行内存加载,并将所有位移动到位。

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

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

于 2013-02-03T10:48:12.683 回答
1

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

在某些这样的系统上,如果尝试从奇数地址读取 16 位值,处理器将读取两个连续的地址,使用一个值的一半和另一个值的另一半,就好像一个已经执行了两个单字节读取并组合结果。这称为未对齐的内存访问。在其他系统上,这样的操作会导致总线故障,这通常会触发某种形式的中断,这些中断可能会也可能不会对它做一些有用的事情。支持未对齐访问的硬件相当复杂,设计代码以避免未对齐访问通常并不太困难。因此,这种硬件通常只存在于已经非常复杂的处理器上,

于 2013-02-27T18:07:46.543 回答