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) : { … }
…
}