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

objcopy is removing a section unless I declare a static volatile variable in that section (using attribute)

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

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

使用 objcopy --update-section.

将校验和放入该部分

我使用 arm gcc 编译器构建了一个 elf 文件,我可以在其中看到此部分及其值:

> 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文件中得到的不一样,就是checksum部分已经被objcopy去掉了。 (至少我是这么认为的)。

不过,如果我在 main.c 文件中定义它:

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

现在,如果我使用 elfbin 文件(使用适当的偏移量)复制与上述相同的步骤,我可以从 bin 文件中检索校验和( elfbin 给出相同的结果)。

问题

我的第一个问题是:我知道您可以使用 __attribute__((section)) 定义一个部分,但是如果您使用链接描述文件中已经定义的部分,这样做命令更改其行为以将变量放置在部分中,而不是创建一个新的?

我的第二个问题是:这是防止objcopy删除这个特定部分的唯一方法吗?

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

Is this the only way for preventing objcopy of removing this particular section?

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


4.6.8.1. Output Section Type

Each output section may have a type. The type is a keyword in parentheses. The following types are defined:

NOLOAD

The section should be marked as not loadable, so that it will not be loaded into memory when the program is run.

DSECT, COPY, INFO, OVERLAY

These type names are supported for backward compatibility, and are rarely used. They all have the same effect: the section should be marked as not allocatable, so that no memory is allocated for the section when the program is run.

The linker normally sets the attributes of an output section based on the input sections which map into it. You can override this by using the section type. For example, in the script sample below, the ROM section is addressed at memory location 0 and does not need to be loaded when the program is run. The contents of the ROM section will appear in the linker output file as usual.

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

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

I know that you can define a section using attribute((section)), but if you use a section already defined within the linker script, does this command changes its behaviour for placing the variable within the section, instead of creating a new one?

从上面,

The linker normally sets the attributes of an output section based on the input sections which map into it.

您的输入部分标志被您的输出部分继承。所以你至少把 allocatable 作为一个标志。

我建议您将校验和放在 .text.data 的末尾。例如,输入部分 .rodata(常量值)通常与输出 .text 放在一起。通常不需要发明另一个输出部分,除非你想要一些不会得到最终图像的簿记。您的 __checksum_is_here 标签足以找到它,您可以在 CRC 上查看 this question