2012-02-15 29 views
7

在构建基于gcc的裸机项目时,需要在启动过程中关注.data和.bss部分的初始化。如何知道.data部分需要从哪里获取init数据? (gcc链接器)

.bss部分非常简单,因为我只是将整个部分填充为0. 但.data部分中的变量需要在ROM中启动其初始化数据并在启动过程中进行复制。

如何知道可以找到具有初始化值的数据?

举个例子吧。

比方说,我创建main.c中两个全局变量

unsigned int my_global_variable_one = 1; 
unsigned int my_global_variable_two = 2; 

那么我可以用objdump的在目标文件中,他们会在哪个部门, 看到,但我无法找到任何东西在objdump out中放置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 

然后我可以看看整个系统的结果小精灵,在这种情况下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的init数据在哪里?

我可以找到这个数据与像readelf或objdump这样的任何binutils命令的位置吗?

/感谢


这是对STM32(皮质M3)MCU,和gcc的Codebench完成版本被使用。

回答

9

编译器将所有代码和一些只读数据放入.text部分。可能还有一个.rodata部分。你可以有你的链接脚本把在一个ROM的地址是这样的:

. = <rom-base-address>; 
.rodata : { *(.rodata) } 
<other read-only sections go here> 
.text : { *(.text) } 

编译器把写数据的所有初始值在.data部分,所有的符号没有在初始值.bss.bss很简单,只需将它放在RAM中即可。该.data希望成为在运行时内存,但在ROM在加载时,和链接脚本可以让你做到这一点与AT关键字:

. = <ram-base-address>; 
.bss : { *(.bss) } 
.data : AT (ADDR (.text) + SIZEOF (.text)) 
     { *(.data) } 

这意味着数据部分现在有一个不同的LMA和VMA(加载内存地址/虚拟内存地址)。你的程序会希望在VMA(运行时地址)找到数据,但数据实际上存在于LMA中(你可能必须教你的闪光器做这件事),这正好在.text部分之后。

如果你需要弄清楚在哪里复制,那么你可以在链接描述文件中创建指针。因此,修改这样上面的例子:

.data : AT (ADDR (.text) + SIZEOF (.text)) 
     { _data_lma = LOADADDR(.data); _data_vma = .; 
      *(.data); 
      _data_size = SIZEOF (.data);} 

然后你可以在你的启动代码做memcpy (_data_vma, _data_lma, _data_size)(尽管你可能需要手工代码汇编?)那些符号会出现在您的程序作为常数在链接时解析的全局变量。所以,在你的汇编代码,你可能会碰到这样的:

_data_lma_k: 
    .long _data_lma 

然后数量将硬编码到.text部分。当然,汇编语法在你的平台上可能会有所不同。

欲了解更多信息,请参阅链接器手动here

+0

嗯,我注意到,数据.text段后追加的,但你帮我得到足够接近:) – Johan 2012-02-15 19:07:00

相关问题