裸机嵌入式 C++:将闪存写入 ram 时未定义对 memcpy 和 memset 的引用
Posted
技术标签:
【中文标题】裸机嵌入式 C++:将闪存写入 ram 时未定义对 memcpy 和 memset 的引用【英文标题】:bare metal embedded c++: undefined reference to memcpy and memset while writing flash to ram 【发布时间】:2022-01-02 08:57:05 【问题描述】:正如标题所暗示的那样,我收到一个与未定义 memcpy 和 memset 相关的错误,即使我没有直接使用它(尽管鉴于此错误的性质,我猜它用于链接器和编译过程)
长话短说:我正在将最初存储在 FLASH 中的 .data 和 .bss 部分写入 SRAM 内存,我正在使用指针进行此类操作,如下所示:
#ifdef __cplusplus
extern "C"
#endif
#include <stdint.h>
#include <string.h>
int main(void);
void Reset_Handler(void);
void Default_Handler(void);
#ifdef __cplusplus
#endif
extern uint32_t _etext;
extern uint32_t _sdata;
extern uint32_t _edata;
extern uint32_t _sbss;
extern uint32_t _ebss;
void Reset_Handler(void)
//copy .data section to SRAM
uint32_t size = (uint32_t)&_edata - (uint32_t)&_sdata;
uint8_t *pDst = (uint8_t*)&_sdata; //sram
uint8_t *pSrc = (uint8_t*)&_etext; //source point comes from flash memory that is end of flash
for(uint32_t i =0 ; i < size ; i++)
*pDst++ = *pSrc++; //"MEMCPY NOT DEFINED" ERROR TRIGGERS HERE
//copy .bss section to SRAM
size = (uint32_t)&_ebss - (uint32_t)&_sbss;
pDst = (uint8_t*)&_sbss; //sram
for(uint32_t i =0 ; i < size ; i++)
*pDst++ = 0; //"MEMSET NOT DEFINED" ERROR TRIGGERS HERE
main();
我正在使用 arm 嵌入式 g++ 编译器来构建 .o 文件,然后使用 -nostdlib 选项链接到 .elf ,因为这是嵌入式应用程序,因此不需要/负担得起的标准库。
该过程失败,因为似乎存在对“memcpy”和“memset”函数的隐式调用。我试图包含
这是 make 文件调用和终端输出:
arm-none-eabi-g++ -c -mcpu=cortex-m4 -mthumb -std=c++11 -O2 -g -fno-exceptions stm32_startup.cpp -o stm32_startup.o
arm-none-eabi-g++ -nostdlib -T stm32_ls.ld -Wl,-Map=final.map main.o GPIO_PORT.o stm32_startup.o config.o -o final.elf
/usr/bin/../lib/gcc/arm-none-eabi/10.3.1/../../../../arm-none-eabi/bin/ld: stm32_startup.o: in function `Reset_Handler':
/home/inumaki/Development/stm32/Workspace/stm32_startup.cpp:155: undefined reference to `memcpy'
/usr/bin/../lib/gcc/arm-none-eabi/10.3.1/../../../../arm-none-eabi/bin/ld: /home/inumaki/Development/stm32/Workspace/stm32_startup.cpp:165: undefined reference to `memset'
collect2: error: ld returned 1 exit status
make: *** [Makefile:35: final.elf] Error 1
inumaki@dev-Inumaki:~/Development/stm32/Workspace$ make
arm-none-eabi-g++ -c -mcpu=cortex-m4 -mthumb -std=c++11 -O2 -g -fno-exceptions stm32_startup.cpp -o stm32_startup.o
arm-none-eabi-g++ -nostdlib -T stm32_ls.ld -Wl,-Map=final.map main.o GPIO_PORT.o stm32_startup.o config.o -o final.elf
/usr/bin/../lib/gcc/arm-none-eabi/10.3.1/../../../../arm-none-eabi/bin/ld: stm32_startup.o: in function `Reset_Handler':
/home/inumaki/Development/stm32/Workspace/stm32_startup.cpp:155: undefined reference to `memcpy'
/usr/bin/../lib/gcc/arm-none-eabi/10.3.1/../../../../arm-none-eabi/bin/ld: /home/inumaki/Development/stm32/Workspace/stm32_startup.cpp:165: undefined reference to `memset'
collect2: error: ld returned 1 exit status
make: *** [Makefile:35: final.elf] Error 1
如我所见,唯一的出路是在删除#include
提前致谢。
编辑:
通过删除 -nostdlib,即允许链接器链接标准库,我得到这个错误也与未定义的函数有关。在我看来,它与汇编程序启动文件有关,即使我有一个 .cpp 启动文件。
inumaki@dev-Inumaki:~/Development/stm32/Workspace$ make
arm-none-eabi-g++ -c -mcpu=cortex-m4 -mthumb -std=c++11 -O2 -g -fno-exceptions main.cpp -o main.o
arm-none-eabi-g++ -c -mcpu=cortex-m4 -mthumb -std=c++11 -O2 -g -fno-exceptions GPIO_PORT.cpp -o GPIO_PORT.o
arm-none-eabi-g++ -c -mcpu=cortex-m4 -mthumb -std=c++11 -O2 -g -fno-exceptions stm32_startup.cpp -o stm32_startup.o
arm-none-eabi-g++ -c -mcpu=cortex-m4 -mthumb -std=c++11 -O2 -g -fno-exceptions config.cpp -o config.o
arm-none-eabi-g++ -T stm32_ls.ld -Wl,-Map=final.map main.o GPIO_PORT.o stm32_startup.o config.o -o final.elf
/usr/bin/../lib/gcc/arm-none-eabi/10.3.1/../../../../arm-none-eabi/bin/ld: /usr/bin/../lib/gcc/arm-none-eabi/10.3.1/../../../../arm-none-eabi/lib/crt0.o: in function `_mainCRTStartup':
(.text+0x128): undefined reference to `__bss_start__'
/usr/bin/../lib/gcc/arm-none-eabi/10.3.1/../../../../arm-none-eabi/bin/ld: (.text+0x12c): undefined reference to `__bss_end__'
/usr/bin/../lib/gcc/arm-none-eabi/10.3.1/../../../../arm-none-eabi/bin/ld: /usr/bin/../lib/gcc/arm-none-eabi/10.3.1/../../../../arm-none-eabi/lib/libc.a(lib_a-exit.o): in function `exit':
exit.c:(.text.exit+0x2c): undefined reference to `_exit'
collect2: error: ld returned 1 exit status
make: *** [Makefile:35: final.elf] Error 1
【问题讨论】:
虽然我不知道 memcpy 和 memset 是做什么的。你look them up了吗? 我想知道编译器是不是太聪明了,识别出代码描述的行为,并试图用对memcpy
和memset
的调用替换你的循环,但不知道它们在你的实现中不存在.
@PaulSanders 是的,我有点看过他们。我知道他们做什么,但不知道他们是怎么做的。我真正的意思是,如果需要,我不知道如何进行优化。
请注意,-nostdlib 指的是 glibc,而不是 c++ std 库。 gllibc 包括 memcpy、strcpy 等,对于嵌入式应用程序/小型 MCU 来说绝对不会太“昂贵”。
【参考方案1】:
我能够通过将您的代码复制到Compiler Explorer 来重现您的问题。解决方案是在编译该文件时将-ffreestanding
选项添加到GCC。这个网站上有more info about -ffreestanding
。
或者,您可以尝试删除您在链接期间使用的-nostdlib
选项,允许 GCC 在其标准库中进行链接,前提是它已正确配置以允许这样做。我建议您至少尝试这样做,看看它给您的应用程序增加了多少膨胀。这样做可能没问题,因为 GCC 应该只包含您实际调用的库函数。
【讨论】:
我猜用-ffunction-sections
和-Wl,-gc-sections
构建也可能有助于减少内存使用?【参考方案2】:
添加-fno-tree-loop-distribute-patterns
以防止gcc 识别memset
、memcpy
等模式并为其生成外部函数调用。这通常是您想要的独立执行环境。请注意,-ffreestanding
不一定 一定会抑制这些函数调用的生成。
或者,您可以链接到您自己的 memcpy
、memset
实现,正如您所指出的那样 - 但当您让一切正常时,这可能是需要考虑的事情。
【讨论】:
我试过这个没有成功,我得到了完全相同的错误。以上是关于裸机嵌入式 C++:将闪存写入 ram 时未定义对 memcpy 和 memset 的引用的主要内容,如果未能解决你的问题,请参考以下文章