7

我正在使用 Keil 为 ARM 7 编写程序集。

我有以下运行时错误:

Non-aligned Access: ARM Instruction at 000000F8H, Memory Access at 7F7F7F7FH
Data Abort: ARM Instruction at 000000F8H, Memory Access at 7F7F7F7FH

这并没有真正帮助我,因为我不知道“非对齐访问”是什么(除了显而易见的,但我并不真正理解它的含义)并且我正在尝试访问(存储)到0x7F7F7F7F,有什么问题?

搜索我只发现了几个类似的问题,都使用 C,并且通过某种方式解决了他们的代码非常具体的问题,并且与这个问题无关。

我正在做:

LDR R0, =0x7F7F7F7F
LDR R1, LABEL
STR R1, [R0]

然后我用不同的标签和偏移量做类似的事情R0,但它首先在这里失败。

4

5 回答 5

8

问题是您用于 32 位(4 字节)内存操作的地址必须与 4 字节边界对齐。这意味着地址必须是 4 的倍数,或者如果您愿意,地址的低两位必须为零。

在这种情况下,最接近的 4 字节对齐地址将是0x7F7F7F7C0x7F7F7F80

同样,LDRH/STRH需要 2 字节对齐,而LDRB/STRB可以在任何地方操作(1 字节对齐 == 未对齐)。

通常,编译器/汇编器负责确保您的变量根据它们的大小正确对齐 - 如果您自己生成地址(根据问题),您应该只遇到这种情况。

于 2014-01-04T20:38:19.690 回答
5

当我们谈论几十年时,我们谈论的是 70 年代或 80 年代等。我们不谈论 62 年代或 94 年代。70、80、90 是十位对齐的数字。10 的 1 次方。世纪是 10 的 2 次方,100s。1900 年代、1400 年代等。或者将其视为数字末尾的许多零。

寻址字节相同。在上面的例子中,一年是最小的单位,当我们谈论内存地址时,一个字节是最小的单位,是的,有点小,但我们不单独寻址位。我们寻址字节。与上述年份一样,任何单独的年份都可以谈论 1971、1436 等。地址 0x1234、0x21 也是如此。但是当我们想开始使用 8 位寻址方案进行 16 位访问时,就像谈论几十年,2 的 1 次幂,所以 2 0,2,4,6,8 的单位是对齐地址,用于访问 2 的幂1 个字节数(一个 16 位数字,2 个字节)。如果我们想要进行 32 位访问,即 4 字节访问或 2 的 2 次方,就像上面的世纪一样,我们需要在地址 0x0、0x4、0x8 等结尾处有两个零(4 是 100 二进制,一个 8 是 1000 二进制 0xC 是 1100 二进制,最后两个零)。

上面的 32 位访问使用以 0x7F 结尾的地址,二进制是 01111111,最后两位是 11,不是零,所以这不是对齐的访问。

当您进行非对齐访问时,arm 或 mips 或任何其他计算机会做什么,有些会捕获异常并且不允许您这样做,有些会以您意想不到的方式调整数据,有些只是让您这样做。有些像较新的 arm 可以在运行时针对不同的响应进行配置,较新的 arm 可以让您拥有类似 x86 的体验。

不幸的是,有太多的 x86 和许多从 x86 中产生的不良编程习惯并没有更多地表达惩罚,x86 肯定会因为使用未对齐访问而受到惩罚,惩罚就是性能。arm 和 mips 和其他人更喜欢杀死你的程序,但有一个例外,这是一种非常严厉的惩罚,但却是一个很好的惩罚,因为它教会你不要那样做。

如果您在该地址有某些东西,那么您可能应该使用较小的传输大小(四个单独的字节传输或两个字节和一个半字)来访问它,如果您真的需要它作为 32 位数字,则将这些字节组合成一个 32 位数字.

于 2014-01-05T00:49:53.860 回答
1

正如您所注意到的,某些平台不允许对内存进行非对齐访问。读取和写入预计在 N 字节边界上对齐。我不知道您的平台,但假设我们需要 4 字节对齐。

您有一个地址 0x7F7F7F7F。0x7F7F7F7F % 4 == 3,即,您有余数,并且此地址未在四字节边界上对齐。许多平台上的非对齐访问会比对齐访问慢(您可能想看看 C 是如何填充结构的),但有些架构根本不允许这样做。

因此,如果您要在固定地址向下传输数据,请确保所述地址从 N 字节边界开始(对于 ARM 7 上的 LDR,N 为 4)。您的编译器将为您合成对齐的访问权限,但如果您对地址进行硬编码(显然),则不会。

从一些快速阅读来看,似乎在 ARM7 上实际上允许未对齐的访问但有一个警告。从下面的链接:

此外,仅允许对标记为正常内存类型的区域进行非对齐访问,并且必须通过设置系统控制协处理器中的 SCTLR.A 位来启用非对齐访问支持。在不允许的情况下尝试执行未对齐的访问将导致对齐错误(数据中止)。

进一步阅读: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.faqs/ ka15414.html

于 2014-01-04T20:38:54.040 回答
0

上面的一切都是正确的,但我不确定你展示的代码会做你真正想要的:我猜你正确定义了字对齐的 LABEL 那么为什么要加载一个十六进制地址作为你想要存储的地方。也许您只想将值 x'7F7F7F7F' 存储在内存位置 LABEL 中。在这种情况下,你必须写 STR R0, [R1]

于 2014-03-03T17:38:05.273 回答
-1

检查数据类型。

例如,假设您已将数组声明为,unsigned int V1[25][25]; 并且将extern其作为extern int (*V1)[22];

假设您正在使用返回 this 的函数,

unsigned long func()
   {`unsigned long k;
      return (V1[0][0]+k);   //you will get an error.'

   }

为了避免这种情况,使用相同的数据extern类型extern unsigned int V1[25][25].

于 2014-03-19T06:30:41.303 回答