什么是非对齐访问?(ARM/Keil)兼容

OJF*_*ord 5 assembly arm keil arm7

我正在使用Keil为ARM 7编写Assembly.

我有以下运行时错误:

Non-aligned Access: ARM Instruction at 000000F8H, Memory Access at 7F7F7F7FH
Data Abort: ARM Instruction at 000000F8H, Memory Access at 7F7F7F7FH
Run Code Online (Sandbox Code Playgroud)

这并不能真正帮助我,因为我不知道什么是"非对齐访问"是,(较明显等,但我真的不明白这是什么意思),我正在试图访问(存储)到0x7F7F7F7F什么问题?

搜索我只发现了几个类似的问题,都使用C,并通过一些非常具体的代码解决,并且与此问题无关.

我正在做:

LDR R0, =0x7F7F7F7F
LDR R1, LABEL
STR R1, [R0]
Run Code Online (Sandbox Code Playgroud)

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

Not*_*hat 6

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

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

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

通常,编译器/汇编器负责确保您的变量按照它们的大小正确对齐 - 如果您自己生成地址(根据问题),您应该只考虑这个变量.


old*_*mer 5

当我们谈论几十年时,我们谈论的是 70 年代或 80 年代等。我们不谈论 62 年代或 94 年代。70、80、90 是十位对齐的数字。10 的 1 次方。世纪是事物的 10 次方 2 或 100 次方。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 位数字.