Assembly 什么是不结盟准入?(ARM/Keil)

Assembly 什么是不结盟准入?(ARM/Keil),assembly,arm,keil,arm7,Assembly,Arm,Keil,Arm7,我正在使用Keil为ARM7编写汇编 我有以下运行时错误: Non-aligned Access: ARM Instruction at 000000F8H, Memory Access at 7F7F7F7FH Data Abort: ARM Instruction at 000000F8H, Memory Access at 7F7F7F7FH 这对我没有什么帮助,因为我不知道什么是“不一致访问”(除了显而易见的,但我真的不理解它的含义),我正在尝试访问(存储)到0x7F7F7F7F,有什

我正在使用Keil为ARM7编写汇编

我有以下运行时错误:

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字节对齐地址将是
0x7F7F7C
0x7F7F7F80

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


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

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

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

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

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

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


进一步阅读:

当我们谈论几十年时,我们谈论的是70年代或80年代等,而不是62年代或94年代。70、80、90是以十为单位排列的数字。10乘以1的幂。世纪是10次方与2100次方对齐的事物。20世纪到14世纪等等,或者把它想象成数字末尾的许多零

对字节寻址也是如此。在上面的例子中,一年是最小的单位,当我们谈论内存地址时,字节是最小的单位,一个位更小是的,但我们不单独寻址位。我们处理字节。与上述年份一样,任何一个年份都可以用地址0x1234、0x21来表示1971年、1436年等。但是,当我们想开始使用8位寻址方案进行16位访问时,就像谈论十年一样,2是1的幂,因此20,2,4,6,8的单元是对齐的地址,用于访问2是1个字节数(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或任何其他计算机会做什么?有些会捕获异常,不让您执行;有些会以您意想不到的方式快速切换数据,有些则让您执行。一些新的arms可以在运行时为不同的响应进行配置,新的arms可以让您拥有类似x86的体验

不幸的是,有太多的x86,而且由于x86产生了许多不好的编程习惯,没有更多地表达惩罚,使用未对齐访问的x86肯定会受到惩罚,惩罚是性能。arm和mips以及其他人更喜欢只杀死你的程序,作为一个非常严厉的惩罚,但这是一个好的惩罚,因为它教会你不要这样做


如果您在该地址有一些内容,那么您可能应该使用较小的传输大小(四个单独的字节传输或两个字节和一个半字)来访问它如果您确实需要将字节组合成32位数字,请将其作为32位数字。

以上所有内容都是正确的,但我不确定您显示的代码是否能满足您的实际需要: 我猜您正确定义了单词对齐的标签,那么为什么要加载十六进制地址作为您要存储的位置呢。 也许您只是想将值x'7F7F7F'存储在内存位置标签上。 在这种情况下,您必须写入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]相同的数据类型。

D'oh。当然