结构初始化列表是零位的,而不是初始化为值

时间:2020-07-12 17:35:37

标签: c++ optimization linker arm embedded

我会说我在C ++中很不错,但是对于链接程序脚本我还是很陌生,我不确定自己做错了什么。 首先,这是我的链接描述文件:

ENTRY(ISR_Reset)
MEMORY {
   FLASH   (rx)    : ORIGIN = 0x80000,     LENGTH = 128K
   RAM     (rwx)   : ORIGIN = 0x20000000   LENGTH = 36K
}
SECTIONS {
   .text : {
      *(.vector_table)
      *(.text.startup)
      *(.text)
      *(.rodata)
   } > FLASH

   __data_flash_source__ = ALIGN(4);
   .data : AT(__data_flash_source__) {
       __data_section_start__ = .;
       *(.data)
       *(.init_array)
       __data_section_end__ = .;
       __ram_end__ = ORIGIN(RAM) + LENGTH(RAM);
   } > RAM

   .bss : {
       *(.bss)
   } > RAM
}

我将数据从闪存复制到__data_section_start____data_section_end__之间的RAM中,然后将其余RAM归零。 我正在使用以下命令来编译我的代码: arm-none-eabi-g++.exe .\src\start.s .\src\main.cpp -o .\bin\main -nostdlib -ffreestanding -fno-exceptions -nostartfiles -T .\src\sam3u2e.ld -mthumb -pedantic -Wall -std=c++17 -ggdb -Ofast

如果删除-Ofast标志,并且不进行任何优化,则会出现以下链接器错误: section .text._ZN4_PMCC2Ev LMA [0008019c,000801bf] overlaps section .data LMA [0008019c,0008019f] 但是,如果确实包含它,则可以正常编译,但是当我尝试初始化结构时,如下所示:

struct Example {
   unsigned int const ID;
   unsigned int volatile & some_register;
   Example(unsigned int const id, unsigned int const register_address) : ID(id),
                                                                         some_register(*((unsigned int volatile *)register_address)) {}
} instance(0x12345678, 0xDEADBEEF);

我在反汇编中注意到instance.some_register的地址紧随main()函数之后存储在FLASH中,但是似乎没有代码被任何代码引用,即使像这样写所以:

instance.some_register = 1234;

然而,instance.ID是从RAM加载的,但是地址的地址比.data的大小大,这意味着它永远不会从FLASH复制到RAM。但是,如果我将.bss的位置从> RAM更改为> FLASH,它将尝试从FLASH加载instance.ID,我不理解,因为ID应该在.rodata

此外,我注意到,即使我没有在代码中完全引用该结构,也没有将其定义为该地址仍位于FLASH中,但我想知道是否有可能告诉链接器不包含代码对于未在任何地方引用的初始化结构?

编辑:链接器部分:

linker sections

如您所见,.data节(被复制到RAM中)只有4个字节。 但是程序集尝试从RAM加载instance.IDinstance.some_register的地址---高于0x20000004,这使我感到困惑,因为这些值无论如何都应该是只读的,因此存储在闪存中? / p>

编辑2:我可能不太清楚我想要代码做什么。我将尝试再次解释。我想定义一组不同的结构,每个结构都有不同的变量。每个变量都引用一个设备寄存器(通过将变量的指针设置为相应寄存器的地址)。因此,当用户写入这些寄存器时,例如:peripheral.some_register = 123;,该值将写入实际的物理寄存器。

在经过编译(优化)的代码中,我实际上并不希望这些结构存在,因此CPU不需要处理初始化数据,而是将其视为指向不同外设寄存器的指针的集合。由于它是只读数据,因此也可以位于FLASH中,因此不需要消耗任何RAM。

我猜这意味着我一定不要使用构造函数,因为那将意味着即使数据再次是只读的,CPU也需要初始化它们。 用户也无需创建自己的结构实例,以防万一。

我最初想使用构造函数,因为有些外设每个都有50个以上的寄存器,每个外设的偏移量相同,但是基址不同,所以我希望通过无需复制粘贴相同的内容来节省一些工作每个寄存器的地址,并在其中添加一个数字。

1 个答案:

答案 0 :(得分:0)

因此,这里发生了一些事情。让我尝试以我对链接程序脚本的了解也很有限。

  1. 您看到的与符号.text._ZN4_PMCC2Ev有关的错误通常是由于链接脚本中缺少条目的问题所致。在这种情况下,您没有.text。*的位置,因此建议您尝试添加*(.text.*)
  2. 我不确定您的意思是“似乎没有被引用”,但是instance.some_register并不是符号。通常,它将作为程序计数器的偏移量加载。但是,这取决于instance的分配方式。
  3. 也许我遗漏了一些东西,但是虽然instance.ID不变,但instance不是。因此,我不希望它位于.rodata中。