c - Arm Cortex-M4 LDRD 指令导致硬故障
问题描述
我注意到在 Cortex-M3 中,LDRD
(load double word)列在 errata中,但我没有发现 Cortex-M4 类似,并且无论如何,执行期间似乎没有发生中断。我正在使用 M4 微控制器,并向/从主机传递数据。使用主机(相同架构)处理它的形状的数据很方便 - 例如,如果主机传递一个无符号的 16 位整数,我接受它作为 a 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*)
并期望它能够工作。
推荐阅读
- amazon-web-services - AWS CodeDeploy 错误 - 部署失败,因为此位置已存在指定文件
- c++ - 试图从二进制文件中向后读取
- typescript - 如何在打字稿中使用泛型扩展一个类?
- r - tags$style 应用于 R 中的所有 Leaflet Maps 闪亮
- c++ - 如何将目录中的头文件包含到 cmake 中
- javascript - JavaScript 数组的二维卷积
- datetime - Grafana - 在 X 轴上显示 NON DataTime 日期/时间字段
- javascript - 如何使用 jquery 在特定个人资料上打开 facebook 应用程序
- php - OsTicket 插件问题
- typescript - 如何获得 TypesScript 嵌套类型推断以停止给出虚假类型错误