c - Arm Cortex-M4 LDRD 指令导致硬故障

标签 c assembly arm embedded memory-alignment

我注意到在 Cortex-M3 中,LDRD(加载双字)是 listed in the errata ,但我没有发现 Cortex-M4 的类似情况,并且无论如何,执行期间似乎没有发生中断。我正在使用 M4 微 Controller ,并将数据传入/传出主机。处理主机(相同架构)处理的数据很方便 - 例如,如果主机传递一个无符号 16 位整数,我接受它作为 uint16_t ,即使它位于两个字节数组中 data_in:

uint16_t some_data = *(uint16_t *)data_in;

但是,当我尝试使用无符号 64 位整数执行此操作时,我在生成的 LDRD 指令上遇到了硬故障:

uint64_t some_data = *(uint64_t *)data_in;

生成:

9B01        ldr r3, [sp, #4]
330C        adds r3, #12
E9D32300    ldrd r2, r3, [r3, #0]
4902        ldr r1, =SOME_ADDR <some_data>
E9C12306    strd r2, r3, [r1, #24]

我在 E9D32300 ldrd r2, r3, [r3, #0] 上出现硬故障。

所以问题是,除了可能的可移植性问题(这里不是问题)之外,我是否通过指向 uint64_t 的位置并尝试将其读取为 uint64_t 来做一些根本错误的事情?不管怎样,有人在任何地方看到过这条指令的勘误吗?我在官方文档中没有找到它。

此外,为了完整性,这段不太有趣的代码可以正常工作:

uint64_t some_data = ((uint64_t)data_in[7] << 8*7) |
                     ((uint64_t)data_in[6] << 8*6) |
                     ((uint64_t)data_in[5] << 8*5) |
                     ((uint64_t)data_in[4] << 8*4) |
                     ((uint64_t)data_in[3] << 8*3) |
                     ((uint64_t)data_in[2] << 8*2) |
                     ((uint64_t)data_in[1] << 8*1) |
                     ((uint64_t)data_in[0] << 8*0);

最佳答案

在 ARMv7M 架构引用手册中,A3.2.1 节“对齐行为”中写道:

以下数据访问总是会产生对齐错误:

  • 非半字对齐 LDREXH 和 STREXH 。
  • 非字对齐 LDREX 和 STREX 。
  • 非字对齐 LDRD 、 LDMIA 、 LDMDB 、 POP 、 LDC 、 VLDR 、 VLDM 和 VPOP 。
  • 非字对齐 STRD 、 STMIA 、 STMDB 、 PUSH 、 STC 、 VSTR 、 VSTM 和 VPUSH 。

因此,除非您知道 data_in 至少是 32 位对齐的,否则您无法将其转换为 (uint64_t*) 并期望它能够工作。

关于c - Arm Cortex-M4 LDRD 指令导致硬故障,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67334962/

相关文章:

c - 数组 : issues declaring

c - 获取数组的两个地址的差异(使用 & 运算符)

c++ - ZTV、ZTS、ZTI 在 gdb x/nfu "vtable_address"的结果中意味着什么?

linux - 安装 expat XML 解析器以在 Arm 板上使用蓝牙

C 运算符优先级 : Increment and logical operators

c - 标准I/O流——fgets()缓冲类型

ARM Cortex-A8 : How to make use of both NEON and vfpv3

exception - ARM 未定义指令错误

c - 试图将 C 程序翻译成 x86 汇编

macOS 64 位系统调用表