在构建基于gcc的裸机mcu项目时,您需要在启动过程中处理.data和.bss部分的初始化。
bss部分非常简单,因为我只需要将整个部分填充为0。但是.data部分中的变量需要在rom/flash中有它们的初始化数据,并在启动过程中复制。
我如何知道在哪里可以找到具有初始化值的数据?
让我们举一个例子。
假设我在main. c中创建了两个全局变量
unsigned int my_global_variable_one = 1;
unsigned int my_global_variable_two = 2;
然后,我可以在对象文件上使用objdump来查看它们将位于哪个部分,但是我在objdump out put中找不到任何应该放置init数据的位置。
$ arm-none-eabi-objdump --syms main.o | grep my_global_variable
00000000 g O .data 00000004 my_global_variable_one
00000004 g O .data 00000004 my_global_variable_two
然后,我可以查看整个系统的结果elf,在本例中为main. elf。
$ arm-none-eabi-nm -n main.elf | grep my_global_variable
20000000 D my_global_variable_one
20000004 D my_global_variable_two
我在哪里可以找到它们的位置,这样我就可以复制数据了?我需要在我的链接器脚本中输入什么?
它应该是.text或.rodata之类的格式,但我怎么知道?
如何检查my_global_variable_one的初始化数据在哪里?
我可以使用任何binutils命令(如readelf或objdump)找到这些数据的位置吗?
谢谢
这是在stm32(Cortex M3)MCU上,并使用了gcc的CodeBench版本。
1条答案
按热度按时间3okqufwl1#
编译器把所有的代码和一些只读数据放在
.text
部分。也可能有一个.rodata
部分。你可以让你的链接器脚本把它放在一个ROM地址中,如下所示:编译器把所有可写数据的初始值放在
.data
部分,把所有没有初始值的符号放在.bss
部分。.bss
很简单,你只需要把它放在RAM中。.data
希望在运行时在RAM中,但在加载时在ROM中,链接器脚本允许你使用AT
关键字来完成这一任务:这意味着数据段现在有了一个不同的LMA和VMA(加载内存地址/虚拟内存地址)。你的程序将期望在VMA(运行时地址)找到数据,但实际上数据将存在于LMA(你可能需要教你的flasher来做这件事),它就在
.text
段之后。如果你需要知道复制到哪里或者从哪里复制,那么你可以在链接器脚本中创建指针。因此,像这样修改上面的例子:
然后你可以在你的启动代码中做
memcpy (_data_vma, _data_lma, _data_size)
(尽管你可能需要在汇编程序中手工编写)这些符号将作为常量全局变量出现在你的程序中,在链接时解析。所以,在你的汇编程序代码中,你可能会有这样的内容:然后,这个数字将被硬编码到
.text
部分。当然,汇编语法在您的平台上可能会有所不同。有关详细信息,请参阅此处的链接器手册