为什么在尝试将两个(RAM)变量(只是它们的初始化值不同)放入同一部分时会出现编译器错误?
C来源:
int __attribute__((section(".in_my_data"))) _foo = 1;
int __attribute__((section(".in_my_data"))) _bar = 0;
(相关)GCC编译器输出:
mcve/main.c:75:45: error: _bar causes a section type conflict
链接描述文件在SECTIONS
定义中包含以下行,但(致命)错误来自编译器,而不是链接器。
.my_data : { *(.in_my_data) } > data
更改C源以允许编译器使用两个部分允许编译通过,但是如果两个输入节被映射到相同的输出节,则链接器会生成错误。
C来源:
int __attribute__((section(".in_my_data_nonzero"))) _foo = 1;
int __attribute__((section(".in_my_data_zero"))) _bar = 0;
链接描述文件:
.my_data : { *(.in_my_data*) } > data
(相关)链接器输出:
Link Error: attributes for input section '.in_my_data_nonzero' conflict
with output section '.my_data'
交换C源代码行的顺序只会改变哪个部分(第二个出现在C源代码中)是错误的。
GCC编译器要求对一个初始化为零的变量的部分要求哪个属性不适用于初始化为非零的变量,反之亦然?
编译器是否尝试将初始化的变量放在.bss
部分中,而不是初始化数据的.data
部分?或者是否有另一部分数据初始化为零?
类似的问题似乎涵盖了内存类型(ROM与RAM)之间冲突的问题:
...或将初始化的const
数据放入NOLOAD输出部分:
......或者对于原因仍然是一个谜,可能是相关的:
据我所知,上述所有内容似乎都没有我可以在这个问题上申请的答案。
答案 0 :(得分:7)
警告:此答案可能仅适用于Microchip XC16编译器。
编译器将属性分配给C变量,以便按如下方式将它们分配给特定部分(有关XC16的具体信息,请参阅下面的注1 )。
int a = 1;
- 已分配给.data
。int b = 0;
- 已分配给.bss
。int c;
- 已分配给.bss
。第一个和最后一个是有意义的:.data
用于初始化数据,.bss
用于未初始化数据。但是,ANSI C启动时.bss
数据也设置为零(参见注2 )。
看起来编译器包含 初始化的变量,但其值等于.bss
部分中的所有位0以及所有未初始化的位一点都不。
根据wikipedia:
实现还可以为BSS部分分配静态分配的变量和常量,这些变量和常量使用仅由零值位组成的值进行初始化。
GCC有一个选项-fno-zero-initialized-in-bss
,可用于强制所有初始化为零的变量进入.data
部分,如this answer中所述。这可以基于每个源文件应用,但不能应用于单个变量。
如果有__attribute__((**doload**))
可用于强制编译器在.data
而不是.bss
中放置零初始化变量,那就太好了。
注1:XC16编译器可能会使用.ndata
和.nbss
来指示地址0x8000以下的近数据。
注意2:使用__attribute__((noload))
标记变量会导致变量从.bss
部分中排除。 XC16生成一个特定的输出节,每个变量标记为(GUID?)唯一名称。
答案 1 :(得分:4)
默认情况下,GCC将对象类放在不同的部分,可执行代码转到.text,初始化数据到.data,静态数据到.bss,还有一些比较模糊的。
如果您尝试强制不同类的两个对象属于同一节,GCC将引发此节错误。
解决方案是将它们放在不同的部分,最后告诉链接器最终在同一部分中合并这些对象,例如:
.boot : { // target ELF section will contain....
*(.boot) // executable code
*(.boot_rodata) // constant data
*(.boot_bss) // static data
} > BOOT // to finally be place in this area