ARMCC:memcpy 的问题(对齐异常)
Posted
技术标签:
【中文标题】ARMCC:memcpy 的问题(对齐异常)【英文标题】:ARMCC: problems with memcpy (alignment exceptions) 【发布时间】:2014-09-13 00:56:39 【问题描述】:我正在将一些软件从 gcc-toolchain 移植到 armcc-toolchain(处理器保持不变 (Cortex-A9))。在 C 代码中使用 memcpy。 armcc 将调用 memcpy 替换为调用 __aeabi_memcpy。关于 __aeabi_memcpy (How do the ARM Compilers handle memcpy()?) 的常见问题解答如下:
在许多情况下,编译对 memcpy() 的调用时,ARM C 编译器将生成对专门的优化库函数的调用。自 RVCT 2.1 起,这些专用功能成为 ARM 架构的 ABI (AEABI) 的一部分,包括:
__aeabi_memcpy
This function is the same as ANSI C memcpy, except that the return value is void.
但与 gcc 相比,在我的所有情况下,对 memcpy 的调用都可以正常工作,而 armcc 对 memcpy 的调用分别 __aeabi_memcpy 不断产生对齐异常。同时我发现,对 memcpy 的调用可以处理源地址和目标地址不是 4 字节对齐的调用,但前提是它们都不是 4 字节对齐的。例如:
volatile uint32_t len = 10;
uint8_t* src = (uint8_t*)0x06000002; // 2-byte aligned
uint8_t* dst = (uint8_t*)(0x06000002 + 20); // 2-byte aligned
memcpy(dst, src, len);
会起作用。但例如:
volatile uint32_t len = 10;
uint8_t* src = (uint8_t*)0x06000002; // 2-byte aligned
uint8_t* dst = (uint8_t*)(0x06000002 + 22); // 4-byte aligned
memcpy(dst, src, len);
会导致对齐异常。因为我使用的是 uint8_t* 类型的指针,所以我明确告诉编译器地址可以有任何对齐。但显然这个 __aeabi_memcpy 不能处理所有的对齐组合。我该如何解决这个问题(最好不使用用户特定版本的 memcpy 更改现有代码中对 memcpy 的所有调用)?感谢帮助。
【问题讨论】:
你确定你的代码没有产生任何未定义的 b 吗?你能用一个最小的有效例子重现这个错误吗? 嗯,我认为这两个例子是最小的? :D 我用了这两个例子。第一个工作正常,第二个导致对齐异常。 我还查看了 __aeabi_memcpy 的拆卸,也找到了导致此问题的部分。但我不知道为什么它是这样实现的,也不知道如何为我的代码修复它...... 您始终可以编写自己的 memcpy 并使用 char 进行复制。 好吧,如果您不想更改代码,那么唯一的选择是查看 ARM 项目的项目设置中的编译标志,然后更改它们。或者,我猜你可以在每次调用memcpy
之前添加一个特殊的 #pragma
。
【参考方案1】:
如果您不想更改代码,这里有两种选择:
1) 禁用 Cortex-A9 上的未对齐异常。这完全解决了问题,但您可能会受到性能影响。
2) 修补库。您可以在要链接的 lib 文件中重命名符号 __aeabi_memcpy。然后,您可以实现自己的 __aeabi_memcpy 来检测对齐错误,使用专门的例程处理它或跳转到原始的 memcpy 函数。如果您使用的是 linux,您甚至不需要重命名符号。链接器允许您覆盖函数。
这两种解决方案都有些肮脏,但如果您不想更改代码,我能想到的就只有这些了。
哦,你应该提交一份错误报告。您看到的行为绝对是一个错误。 Memcpy 应该适用于任何对齐方式。
【讨论】:
在出现“未对齐”异常的情况下,如果没有异常,您将获得不正确的行为(因为未对齐的访问将读取四个对齐的字节并重新排列它们的顺序)。完全同意这是实现中的一个严重错误。很臭。 我认为禁用未对齐异常只会隐藏问题,不能解决问题。 谢谢。我认为 gnasher 关于禁用未对齐的异常是正确的。禁用未对齐的异常将导致不正确的行为。例如,未对齐的异常是由 LDR 或 STR 指令引起的,该指令试图从没有正确对齐(即 4 字节对齐)的地址加载或存储某些内容。当我禁用此异常时,它们将不再弹出,但 LDR 可能会加载 4 个字节的数据,而不仅仅是 1 个字节,STR 将分别存储 4 个字节而不是 1 个字节,这不是我想要的,即不正确的行为。【参考方案2】:也许这仍然有帮助: ARM 编译器 armcc 应该有一个选项,您可以使用该选项告诉编译器不要进行未对齐的访问,也不要使用会执行此操作的内置库:
--no_unaligned_access
http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0472k/chr1359124947629.html
【讨论】:
以上是关于ARMCC:memcpy 的问题(对齐异常)的主要内容,如果未能解决你的问题,请参考以下文章