我正在使用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
的偏移执行类似的操作,但它首先在此处失败。
答案 0 :(得分:6)
问题是您用于32位(4字节)内存操作的地址必须与4字节边界对齐。这意味着地址必须是4的倍数,或者如果您愿意,地址的最后两位必须为零。
在这种情况下,最接近的4字节对齐地址为0x7F7F7F7C
或0x7F7F7F80
。
同样,LDRH
/ STRH
需要2字节对齐,而LDRB
/ STRB
可以在任何地方运行(1字节对齐==未对齐)。
一般情况下,编译器/汇编器负责确保您的变量按照它们的大小正确对齐 - 如果您自己生成地址(根据问题),您应该只考虑这个。
答案 1 :(得分:3)
当我们谈论几十年时,我们会谈论70年代或80年代等。我们不谈论62年代或94年代。 70,80,90是在十位上对齐的数字。 10世纪的权力1.几十年代的事物在10对2的力量,100s。 20世纪50年代,等等。或者把它想象成数字末尾的那么多零。
相同的寻址字节。单个年份是上面示例中的最小单位,当我们讨论内存地址时,字节是最小的单位,有点小是,但我们不单独地寻址位。我们解决字节。像上面几年一样,任何一年都可以谈论1971年,1436年等。与地址0x1234,0x21相同。但是当我们想要开始使用8位寻址方案进行16位访问时,就像谈论几十年一样,2对于功率1,所以2 0,2,4,6,8的单位是ALIGNED地址,用于访问2的功率1个字节数(一个16位数,2个字节)。如果我们想要进行4位访问的32位访问或2次访问2,如上面的几个世纪,我们需要在地址0x0,0x4,0x8等结尾处有两个零(等于4是100二进制) ,8是1000二进制0xC是1100二进制,最后是两个零)。等等64位访问是8字节或2到3个字节的幂,所以对齐的地址最后有3个零,最后没有3个零是未对齐的。
上面的32位访问使用以0x7F结尾的地址,二进制为01111111,后两位为11,不是零,因此不是对齐访问。
当你做一个未对齐的访问时,arm或mips或任何其他计算机做什么,有些陷阱异常并且不让你做一些以你想象的方式调整数据,有些只是让你这样做。有些像新手臂可以在运行时配置不同的响应,更新的手臂可以让你拥有x86之类的体验。
不幸的是,有太多的x86和许多糟糕的编程习惯已经从x86中产生了更多的惩罚,但是对于使用未对齐访问,x86肯定会受到惩罚,惩罚就是性能。胳膊和mips和其他人更喜欢杀死你的程序,除了一个非常严厉的惩罚,但是一个好的,因为它告诉你不要这样做。
如果你在那个地址有东西,那么你应该使用较小的传输大小(四个单独的字节传输或两个字节和一个半字)来访问它,如果你真的需要它,那么将字节组合成一个32位数字32位数字。
答案 2 :(得分:1)
正如您所注意到的,某些平台不允许对内存进行未对齐访问。期望读和写在N字节边界上对齐。我不知道你的平台,但我们假设我们需要4字节对齐。
您的地址为0x7F7F7F7F。 0x7F7F7F7F%4 == 3,即你有一个余数,这个地址没有在四字节边界上对齐。许多平台上的未对齐访问将比对齐访问慢(您可能想要了解C pad结构的方式),但有些架构根本不允许它。
因此,如果您要将数据压缩到固定地址,请确保所述地址始于N字节边界(对于ARM 7上的LDR,N为4)。您的编译器将为您合成对齐访问,但如果您对地址进行硬编码(显然),则不会。
从一些快速阅读中,似乎在ARM7上实际上允许未对齐的访问 ,但有一点需要注意。从以下链接:
此外,未对齐访问仅允许标记为正常内存类型的区域,并且必须通过设置系统控制协处理器中的SCTLR.A位来启用未对齐访问支持。尝试在不允许的情况下执行未对齐访问将导致对齐错误(数据中止)。
进一步阅读:http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.faqs/ka15414.html
答案 3 :(得分:0)
以上所有内容都是正确的,但我不确定您展示的代码是否符合您的要求: 我猜你正确定义了LABEL,它是单词对齐的,所以为什么要加载一个十六进制地址作为你想要存储的地方。 也许你只想将值x'7F7F7F7F'存储在内存位置LABEL。 在这种情况下,您必须编写STR R0,[R1]
答案 4 :(得分:-1)
检查数据类型。
例如假设您已将数组声明为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].