Gcc objcopy正在删除一个节,除非我在该节中声明一个静态易失性变量(使用属性)

Gcc objcopy正在删除一个节,除非我在该节中声明一个静态易失性变量(使用属性),gcc,linker,arm,binaryfiles,objcopy,Gcc,Linker,Arm,Binaryfiles,Objcopy,我有一个链接器脚本,其中定义了一个用于包含软件映像校验和的部分。比如: ... .my_checksum : { __checksum_is_here = .; KEEP (*(.my_checksum)) . = ALIGN(4); _sw_image_code_end = .; } > IMAGE ... 使用objcopy--update section将校验和放入该部分 我使用arm gcc编译器构建了一个elf文件,我可以看到该部分及

我有一个链接器脚本,其中定义了一个用于包含软件映像校验和的部分。比如:

...
.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.
现在我通过执行

> arm-none-eabi-objcopy -O binary --gap-fill 0xFF -S my_elf_file.elf my_elf_file.bin
现在,如果我再次尝试读取校验和值,使用校验和LMA和第一部分LMA之间的差值(见上文):

我在这里得到的结果与在elf文件中得到的结果不同,也就是说,校验和部分已被objcopy删除。(至少我是这么想的)

尽管如此,如果我在
main.c
文件中定义此项:

static volatile unsigned int __aux_checksum __attribute__((section(".my_checksum")));
...
int main() {
  ...
  ((void)__aux_checksum); // Avoid compiler/linker optimizations.
  ...
}
现在,如果我使用
elf
bin
文件(使用适当的偏移量)重复上述相同的步骤,我可以从
bin
文件中检索校验和(
elf
bin
给出相同的结果)

问题 我的第一个问题是:我知道您可以使用
\uuuuu attribute\uuuuu((section))
定义节,但是如果您使用链接器脚本中已经定义的节,该命令是否会改变其在节中放置变量的行为,而不是创建新的变量


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

让我们先回答第二个问题

这是防止删除此特定节的对象复制的唯一方法吗

您需要一个概念,如部分中所述


4.6.8.1。输出段类型

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

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

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

链接器通常根据映射到输出节的输入节设置输出节的属性。可以通过使用剖面类型来替代此选项。例如,在下面的脚本示例中,ROM部分位于内存位置0,在程序运行时不需要加载。ROM部分的内容将像往常一样出现在链接器输出文件中


那是什么意思?假设对象中有调试信息。如果您正在刻录ROM映像,则可能不希望将调试信息放入对象中。同样,BSS段全部为零,不需要将其存储到ROM中,但您需要清除RAM(在加载地址处)为其让路。
.data
部分的“init值”是从ROM初始化的,但驻留在RAM中。这些概念是“可加载”和“可分配”的,它们在ELF文件中有相应的标志。默认情况下,
.my_checksum
不获取任何标志。例如,未分配和无法加载调试信息

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

综上所述,

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

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


我建议您将校验和放在
.text
.data
的末尾。例如,输入扇区
.rodata
(常量值)通常与输出
.text
一起放入。通常不需要再创建一个输出部分,除非您需要一些无法获得最终图像的簿记。您的
\uuuu校验和\u在这里
标签足以找到它,您可以在CRC上查看。

还有一些概念,如向量表,它们是硬件固有的,您需要软件地址,但实际上并不加载它们;但你仍然可以称之为已分配。分配影响LD分配地址的方式。您可以使用常量转换为指针,但链接器文件是集中包含所有系统地址信息的好地方。另一点是,
objcopy
只复制“可加载”部分,除非您特别指定它们。例如,默认情况下,它不会复制
.bss
static volatile unsigned int __aux_checksum __attribute__((section(".my_checksum")));
...
int main() {
  ...
  ((void)__aux_checksum); // Avoid compiler/linker optimizations.
  ...
}
NOLOAD
DSECT, COPY, INFO, OVERLAY
SECTIONS {
  ROM 0 (NOLOAD) : { … }
  …
}