objcopy将删除一个节,除非我在该节中声明了一个静态volatile变量(使用属性)

时间:2019-02-22 12:46:12

标签: gcc linker arm binaryfiles objcopy

我有一个链接描述文件,其中定义了一个包含软件映像校验和的部分。像这样:

...
.my_checksum :
  {
    __checksum_is_here = .;
    KEEP (*(.my_checksum))
    . = ALIGN(4);
    _sw_image_code_end = .;  
  } > IMAGE
...

使用objcopy --update-section将校验和放入该部分。

我使用elf编译器构建了一个arm gcc文件,并且可以看到本节及其中的值:

> arm-none-eabu-objdumph -h my_elf_file.elf
...
0 .text         0001496c  08010000  08010000  00010000  2**4
...
7 .my_checksum     00000004  080250c0  080250c0  000350c0  2**2
...

// Notice that 000350c0 is the file offset and 080250c0 is the LMA.
// The starting LMA is 08010000

我可以检索其值:

> xxd -s 0x000350c0 -l 4 my_elf_file.elf
000350c0: 015e 028e // I have checked this value and it is correct.

现在我通过执行

生成一个bin文件
> arm-none-eabi-objcopy -O binary --gap-fill 0xFF -S my_elf_file.elf my_elf_file.bin

现在,如果我尝试再次使用校验和LMA与第一部分LMA之间的差异(请参见上文)来读取校验和值:

> xxd -s 0x150c0 -l 4 my_elf_file.bin

我在这里获得的结果与在elf文件中获得的结果不同,也就是说,objcopy删除了校验和部分。 (至少我是这样认为的。)

尽管如此,如果我在main.c文件中定义了此内容,

static volatile unsigned int __aux_checksum __attribute__((section(".my_checksum")));
...
int main() {
  ...
  ((void)__aux_checksum); // Avoid compiler/linker optimizations.
  ...
}

现在,如果我使用elfbin文件(使用适当的偏移量)复制与上述相同的步骤,则可以从bin文件({{ 1}}和elf给出相同的结果。

问题

我的第一个问题是:我知道您可以使用bin定义节,但是如果您使用链接器脚本中已经定义的节,此命令是否会更改其行为?将变量放置在该部分中,而不是创建一个新变量?

我的第二个问题是:这是阻止__attribute__((section))删除此特定部分的唯一方法吗?

1 个答案:

答案 0 :(得分:1)

让我们先回答您的第二个问题,

  

这是防止objcopy删除此特定部分的唯一方法吗?

您需要{strong>部分下的gnu LD manual中记录的概念。


  

4.6.8.1。输出节类型

     

每个输出节可以有一个类型。类型是括号中的关键字。定义了以下类型:

NOLOAD
  

应将该部分标记为不可加载,以便在程序运行时不会将其加载到内存中。

DSECT, COPY, INFO, OVERLAY
  

支持这些类型名称以实现向后兼容,并且很少使用。它们都有相同的效果:应将该节标记为不可分配,以便在程序运行时不为该节分配内存。

     

链接器通常根据映射到输出节中的输入节来设置输出节的属性。您可以使用节类型来覆盖它。例如,在下面的脚本示例中,ROM部分的地址为内存位置0,并且在程序运行时无需加载。 ROM部分的内容将照常显示在链接器输出文件中。

SECTIONS {
  ROM 0 (NOLOAD) : { … }
  …
}

那是什么意思?假设您的对象中有调试信息。如果要刻录ROM映像,则可能不希望将调试信息放入对象中。同样,BSS段全为零,无需将其存储到ROM,但是您需要清除RAM(在加载地址处)以为其预留空间。 .data部分的'init value'是从ROM初始化的,但位于RAM中。这些概念是“可加载的”和“可分配的”,并且在ELF文件中具有用于它们的标志。默认情况下,您的.my_checksum没有标志。即,未分配且无法像调试信息一样加载。

  

我知道您可以使用属性((section))定义节,但是如果您使用链接器脚本中已经定义的节,此命令是否会更改其行为以将变量放入该部分,而不是创建一个新的?

从上面

  

链接器通常根据映射到输出节中的输入节来设置输出节的属性。

您的输入节标志被您的输出节继承。因此,您至少已分配了可分配的标志。

我建议您将校验和放在.text.data的末尾。例如,输入部分.rodata(恒定值)通常与输出.text放在一起。除非您希望保留一些不会影响最终图像的记录,否则通常无需发明其他输出部分。您的__checksum_is_here标签足以找到它,您可以在CRC上查看this question