嵌入式技术论坛
直播中

张静

7年用户 1440经验值
私信 关注
[问答]

求助!如何才能使memcpy完全使用rt_memcpy?


在移植一个某个程序时,以前平台(arm Cortex-M3)运行得很好的程序,突然到新的平台(arm Cortex-M7)突然出现hard fault 了
FPU active!
usage fault:
SCB_CFSR_UFSR:0x100 UNALIGNED
这种错误,我通过cpu pc寄存器值和map文件定位到了在 memcpy 函数中,猜测应该是复制数据时地址未对齐引起的。 我开始以为 memcpy 就是 rt_memcpy ,所以把 rt_memcpy 函数的4字节对齐复制变成单字节复制,发现问题依然存在。
然后我通过搜索map文件发现,很多软件包并没有使用rt_memcpy ,而是使用编译器提供的 memcpy 。即使 我通过下面这样的代码,想把memcpy重定向到 rt_memcpy依然没有丝毫效果。

void *memset(void *src, int c, size_t n)
{
    return rt_memset(src, c, n);
}

void *memcpy(void *dest, const void *src, size_t n)
{
    return rt_memcpy(dest, src, n);
}
然后我在map文件中发现一些函数,部分map文件内容
    ntp.o(i.ntp_get_time) refers to rt_memcpy_w.o(.text) for __aeabi_memcpy4
    ntp.o(i.ntp_get_time) refers to rt_memclr_w.o(.text) for __aeabi_memclr4
    rt_memcpy_v6.o(.text) refers to rt_memcpy_w.o(.text) for __aeabi_memcpy4
    rt_memmove_v6.o(.text) refers to rt_memcpy_v6.o(.text) for __aeabi_memcpy
    rt_memmove_v6.o(.text) refers to rt_memmove_w.o(.text) for __memmove_aligned
    aeabi_memset.o(.text) refers to rt_memclr.o(.text) for _memset
    rt_memclr.o(.text) refers to rt_memclr_w.o(.text) for _memset_w
    strncpy.o(.text) refers to rt_memclr.o(.text) for __aeabi_memclr
我才发现原来memcpy并不是直接使用调用的,编译器还分了单字节复制和4字节复制的方式 rt_memcpy_v6 rt_memcpy_w aeabi_memcpy aeabi_memcpy4 然后我再次重新定义

void __aeabi_memcpy(void *dest, const void *src, size_t n)
{
    rt_memcpy(dest, src, n);
}

void __aeabi_memcpy4(void *dest, const void *src, size_t n)
{
    rt_memcpy(dest, src, n);
}
再一编译发现问题消失了。
也有查找网上资料说 使用 #pragma pack(1) 将变量设置成单字节对齐,这样使用memcpy时就会调用__aeabi_memcpy4而是使用 __aeabi_memcpy函数
不知道大家有没有更好的办法,能使memcpy完全使用rt_memcpy

回帖(4)

张宇

2022-4-7 09:28:47
千万别乱用memcpy,这玩意是上来就四字节拷贝的,不判断内存对齐,平时没啥事,一旦死机哭都没有地方哭。rt_memcpy 是安全的。 可以用全局宏来进行替换
举报

张超

2022-4-7 09:28:59
没有太好的办法。

为了性能,编译器提供的方案稍微激进了一些,本来是没问题的,只要不任意强转就不会有事。(这本身就是错误的用法)

但是有些代码违规强转,就会引发异常。
比如void*你强转成int *,编译器就认为你是4字节对齐了,就可以使用更高效的对齐拷贝。
如果你转成double,就更不得了,直接就使用多字拷贝了。
毕竟性能有几十倍的差距。

或是外扩的RAM并不支持非对齐访问,或是多字连续访问。也会出现问题。
常见的有MCU级别的外扩SDRAM,很多不支持多字访问。
SPI接口的PSRAM映射的外扩内存也是重灾区。

都不用行不行?程序员觉得可以,BOSS说不行,比如同样的芯片跑UI,别人跑几十帧,你跑几帧,你选择哪个呢?
但问题又客观存在。

如果想稳妥,只能像你这样修改。
或是对目标地址对齐,或是地址范围,做个判断。

我的想法是,

通用的API还是不必全部修改。总归改不完。
然后默认可以把工具链相对激进的memcpy优化给拦截掉。
有性能要求的项目,可以根据源地址和目标地址是否对齐,以及本项目芯片外扩RAM是否支持对齐多字访问。自动调用不同的实现。
举报

王桂英

2022-4-7 09:29:12
感觉是要被你们玩坏了,都觉得rt_memcpy好用,rt_memset好用……

但是啊,在能够不用rt_memcpy的情况下就尽量不要用
举报

王凯

2022-4-7 09:29:33
要想把memcpy替换成rt_memcpy可以尝试下在GCC链接阶段动手脚。
用到GCC的一个链接选项: -Wl,--wrap=xxx
1 举报
  • 廖富贵: 你好,我用的编译器是DS-5 v5.29.1\\sw\\ARMCompiler5.06u6\\bin,cpu是arm-r4,有办法让rt_memcpy_w.o不要参与链接吗? 我想节省点RAM空间,我们这里是单片机程序,我们自己实现了memcpy函数。谢谢

更多回帖

发帖
×
20
完善资料,
赚取积分