AVR-GCC链接器:“数据” - 截面溢出

时间:2017-10-12 09:30:17

标签: c gcc linker avr

我正在使用Atmel AVR-GCC来编译基于Atmel的Zigbee Bitcloud的项目。在Atmega256rfr2(256k闪存,32k RAM)

添加更多代码后,我接近内存限制(似乎就是这样)。

我发现,如果链接器为“数据部分”添加了太多内容,则会导致程序无法预测的行为。问题是链接器不能帮助我找到这一点。所以我很难找到一个稳定的解决方案。

我正在使用Atmel提供的以下链接器文件:

OUTPUT_FORMAT("elf32-avr")
OUTPUT_ARCH(avr:6)

MEMORY
{
    text   (rx)   : ORIGIN = 0x00000000, LENGTH = 256K
    boot   (rx)   : ORIGIN = 0x0003F000, LENGTH = 4K
    access (rx)   : ORIGIN = 0x0003FFF0, LENGTH = 16
    data   (rw!x) : ORIGIN = 0x00800200, LENGTH = 32K - 500  /* leave 500 bytes for stack */
    eeprom (rw!x) : ORIGIN = 0x00810000, LENGTH = 8K
}

SECTIONS
{  
.text :
  {
    PROVIDE(__text_start = .);

    *(.vectors)
    KEEP(*(.vectors))
    . = ALIGN(0x400);

    /* PDS NV memory section */
    PROVIDE(__d_nv_mem_start = .);
    . = ALIGN(0x4400);
    PROVIDE(__d_nv_mem_end = .);

    /* Non-volatile file system PDS_FF section */
    PROVIDE(__pds_ff_start = .);
    KEEP(*(.pds_ff))
    PROVIDE(__pds_ff_end = .);

    /* Non-volatile file system PDS_FD section */
    PROVIDE(__pds_fd_start = .);
    KEEP(*(.pds_fd))
    PROVIDE(__pds_fd_end = .);

    *(.progmem.gcc*)
    *(.progmem*)
    . = ALIGN(2);

    *(.trampolines*)
    *(.jumptables*)
    *(.lowtext*)

    *(.init0)
    KEEP (*(.init0))
    *(.init1)
    KEEP (*(.init1))
    *(.init2)
    KEEP (*(.init2))
    *(.init3)
    KEEP (*(.init3))
    *(.init4)
    KEEP (*(.init4))
    *(.init5)
    KEEP (*(.init5))
    *(.init6)
    KEEP (*(.init6))
    *(.init7)
    KEEP (*(.init7))
    *(.init8)
    KEEP (*(.init8))

    *(.text.main)
    KEEP (*(.text*main))
    *(.text)
    *(.text.*)

    PROVIDE(__text_end = .);
  } > text

  .data : AT (ADDR(.text) + SIZEOF(.text))
  {
    PROVIDE(__data_start = .);
    *(.data*)
    *(.rodata*)
    *(.gnu.linkonce.d*)
    . = ALIGN(2);
    PROVIDE(__data_end = .);
  } > data

  .bss __data_end :
  {
    PROVIDE(__bss_start = .);
    *(.bss*)
    *(COMMON)
    PROVIDE(__bss_end = .);
  } > data

  .noinit __bss_end :
  {
    *(.noinit*)
    PROVIDE(__heap_start = .);
  } > data

  __stack_start = .;

  __data_load_start = LOADADDR(.data);
  __data_load_end = __data_load_start + SIZEOF(.data);

  .access_section :
  {
    KEEP(*(.access_section*))
    *(.access_section*)
  } > access

  .boot_section :
  {
    *(.boot_section*)
  } > boot

  .eeprom :
  {
    FILL(0xff)
    BYTE(0xff)
    . = . + LENGTH(eeprom)-1;
  } > eeprom

  /DISCARD/ :
  {
    *(.init9)
    *(.fini9)
  }

}

我设法弄清楚代码肯定不再工作的数据量,直到哪个数量我没有明显的故障。 该程序适用于以下尺寸输出:

text       data     bss     dec     hex filename
210260    10914   25427  246601   3c349 (TOTALS)

avr-gcc-size -A:

    section              size      addr
    .data                2722   8389120
    .text              209468         0
    .bss                25426   8391842
    .noinit                 1   8417268
    .access_section         4    262128
    .boot_section         798    258048
    .eeprom              8192   8454144
    .debug_info        538541         0
    .debug_abbrev       46706         0
    .debug_loc          73227         0
    .debug_aranges       5704         0
    .debug_ranges        6032         0
    .debug_line        108276         0
    .debug_str          89073         0
    .comment               92         0
    .debug_frame        14252         0
    Total             1128514

我有明显的故障,大小为:

210260    10918   25427  246605   3c34d (TOTALS)

只增加文本而不是数据,但不会导致任何文本:

210270    10914   25427  246611   3c353 (TOTALS)

有没有人知道,为什么程序在这一点上失败了?如果可能发生这种情况,我怎样才能预测未来的限制或让链接器给我一个警告?

我没有收到任何链接器错误消息或警告。该程序此时崩溃了。

3 个答案:

答案 0 :(得分:1)

Everything in the .data section takes up Flash and RAM. The part in Flash is used to initialize the part in RAM. You're probably running out of RAM. So my suggestion is to mark as much as possible as const. Doing that thing will be moved into the .text segment, where it occupies just Flash and leaves RAM for better things.

答案 1 :(得分:1)

这里有一些严重的误解。

  • should。 200h与500不同,但与512相同。此外,0x00800200, LENGTH = 32K - 500不是32k而是64kib。全部都有很多这样的错误,无论谁设置这个链接器文件都不知道他们在做什么,他们不知道十六进制数。
  • “本程序正在为...的大小输出工作”10914 + 25427 = 36341字节。它怎么能正常工作,你刚才说你的芯片上有32kib的物理RAM。并且您还为堆栈保留512个字节。它工作正常,它可能似乎现在正在工作,纯粹的机会。

如果您认为当您分配的内存超过实际可用内存时,您的程序可以正常工作,那么您无需恢复此程序。记忆不能在空气中分配。同样,除非在该芯片上有一些特殊的引导区ROM,否则不能将大于256k的RW部分加在一起。

您没有收到任何链接器警告的原因可能是因为您告诉链接器您有64kib可用,而物理芯片只有32kib。

答案 2 :(得分:0)

Your bss+data sections (both probably go to data region) exceed your data region for few kB.

Probably due to some random behavior, you write over your stack at some point, which crashes your program.

Linker should warn you if section does not fit the region.

I think only way to be sure no issues will occur is to extend data region (if yor board has more RAM), or decrease size of your initialized + uninitialized data.


Or maybe some of your initialized data goes to eprom region, and only after you add few bytes you overflow data. To be sure use avr-something-size -A yourexecutable, which should show more detail.