什么是不结盟访问?(ARM/Keil)



我正在使用Keil为ARM7编写Assembly。

我有以下运行时错误:

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的偏移量做了类似的事情,但它首先在这里失败了。

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

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

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

一般来说,编译器/汇编程序会确保变量的大小正确对齐——只有当你自己生成地址时(根据问题),你才应该遇到这种情况。

当我们谈论几十年时,我们谈论的是70年代或80年代等。我们不谈论62年代或94年代。70、80、90是以十为单位排列的数字。10的幂1。几个世纪以来,事情都是围绕着2,100的力量。20世纪、14世纪等等。或者把它想象成数字末尾的那么多个零。

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

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

当你进行未对齐的访问时,arm、mips或任何其他计算机会做什么?有些会捕获异常而不让你这样做,有些会以你意想不到的方式快速处理数据,有些只是让你这样去做。还有一些,比如新的arm,可以在运行时配置不同的响应,新的arm可以让你获得类似x86的体验。

不幸的是,有太多的x86,以及x86产生的许多不良编程习惯没有更多地表达惩罚,x86使用未对齐的访问肯定会受到惩罚,惩罚是性能。arm和mips以及其他人更喜欢在例外情况下终止你的程序,这是一个非常严厉的惩罚,但也是一个好的惩罚,因为它教会你不要这样做。

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

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

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

因此,如果您要将数据转储到固定地址,请确保所述地址从N字节边界开始(其中,对于ARM7上的LDR,N为4)。编译器会为您合成对齐的访问,但如果您对地址进行硬编码(显然),则不会。

从一些快速阅读中可以看出,ARM7上似乎允许未对齐的访问,但有一点需要注意。从下面的链接:

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

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

上面的一切都是正确的,但我不确定您显示的代码是否能达到您真正想要的效果:我想你定义的LABEL是正确的,它是单词对齐的,所以为什么要加载一个十六进制地址作为你想要存储的地方。也许您只是想将值x‘7F7F7F7F’存储在LABEL的存储位置。在这种情况下,您将不得不写入STR R0,[R1]

检查数据类型。

例如,假设您已将一个数组声明为unsigned int V1[25][25];你有extern它作为extern int (*V1)[22];

假设您使用的函数将其返回为

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

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

相关内容

  • 没有找到相关文章

最新更新