【问题标题】:GCC error "<variable> causes a section type conflict"GCC 错误“<variable> 导致节类型冲突”
【发布时间】:2015-05-06 12:37:06
【问题描述】:

为什么在尝试将两个仅在初始化值不同的 (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 输出部分:

...或者对于原因仍然是个谜,可能与此有关:

据我所知,上述任何一个问题似乎都没有我可以应用于此问题的答案。

【问题讨论】:

  • 可能是愚蠢的问题,但您是否尝试过切换这两行?
  • 其他(非 SO)论坛上有类似的帖子,几乎都与尝试将 RAM 变量放入 ROM 中有关。
  • @Eregrith 是的。结果相同。我还尝试了多个具有零值和非零值的变量。编译器开始工作的第一个(当然),与第一个具有相同(零或非零)值的所有其他值一样。 IE。如果我在最后添加int __attribute__((section(".in_my_data"))) _baz = 1;_baz 很好,但如果_baz=0; 那么_baz 也会失败。
  • 如果第一个是int __attribute__((section(".in_my_data"))) _foo = 0; 是否都失败了?
  • @Eregrith 如果_foo = 0; 那么_bar = 0; 可以,但_baz = 1; 失败。看来编译器已经决定 crt_startup 将负责初始化 = 0; 变量,并希望将它们放在与 = non-zero; 变量不同的部分中。

标签: c gcc xc16


【解决方案1】:

默认情况下,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

【讨论】:

    【解决方案2】:

    警告:此答案可能仅适用于 Microchip XC16 编译器。

    研究

    编译器将属性分配给 C 变量,以便将它们分配给特定的部分,如下所示(有关 XC16 的特定信息,请参阅下面的 注 1)。

    • int a = 1; - 分配给.data
    • int b = 0; - 分配给 .bss
    • int c; - 分配给 .bss

    第一个和最后一个有意义:.data 用于初始化数据,.bss 用于未初始化数据。然而,.bss 数据也被 ANSI C 启动设置为零(参见 注 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?)唯一名称。

    【讨论】:

      猜你喜欢
      • 2019-10-30
      • 1970-01-01
      • 2017-07-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-02-07
      • 2013-03-25
      • 2018-04-16
      相关资源
      最近更新 更多