0

I am using the Atmel AVR-GCC for compiling a project based on Atmel's Zigbee Bitcloud. On the Atmega256rfr2( 256k Flash, 32k RAM)

After adding more code, I am approaching the limit of the memory (seems like it).

I figured out, that if the linker added too much to the "data-section", it leads to unpredictable behaviour of the program. The problem is the linker does not help me to find this point. So I am struggling to find a stable solution.

I am using the following linker file provided by 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)
  }

}

I managed to figure out at which amount of data the code is definitely not working any more and until which amount I do not have an obvious malfunction. The program is working for a size output of:

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

I have obvious malfunction at a size of:

210260    10918   25427  246605   3c34d (TOTALS)

Increasing only the text, but not the data, does not lead to any though:

210270    10914   25427  246611   3c353 (TOTALS)

Does anyone has an idea, why the program fails at this point? And how can I predict the limit in the future or make the linker give me a warning, when this might happen?

I do not get any linker error message or Warning. The program just crashes at this point.

LasseSte
  • 9
  • 3
  • Can you be a bit more specific: Are you getting a message from the linker that stuff doesn't fit (you should) or is your program just stopping to work? Are you using dynamic memory allocation? – tofro Oct 12 '17 at 10:10
  • is 500 bytes enough for the stack, have you verified the stack is not hitting the data? – old_timer Oct 12 '17 at 11:52
  • @tofro The linker does not give any error. The Program is just behave strangely. Some library Function I do not have the source code stop to work. – LasseSte Oct 12 '17 at 12:28
  • In case the linker doesn't complain, you most probably have rather a *dynamic* than a *static* allocation problem. Check your stack usage for weird stuff like recursion and make sure you check all return values of dynamic allocation (`malloc` et al) in your program. – tofro Oct 12 '17 at 12:31
  • tofro: size tool does not show dynamically allocated data. And there seems to be no space left for heap anyway. – dbrank0 Oct 12 '17 at 12:34
  • The Program is not using any heap (no malloc,calloc,realloc). Though the Stack might be a Problem. How can I monitor the Stack usage? The Program is using a lot of Interrupt based function calls. – LasseSte Oct 12 '17 at 13:09
  • Trial and error? Increase stack size. What is your initial SP value BTW? – dbrank0 Oct 12 '17 at 13:40
  • @dbrank0 initial SP value is 0x7000 – LasseSte Oct 13 '17 at 17:20
  • 1
    I see that this initial SP is stupid and probably source of the Problem. I changed it to 0x0800 and set the data section to be 0x0800 to 0x7FFF. For now it is working. The Linker now also throws error if a reduce the size of data below 29k. – LasseSte Oct 13 '17 at 18:07

3 Answers3

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.

datenwolf
  • 159,371
  • 13
  • 185
  • 298
  • 1
    A const variable will still occupy SRAM. Const can not be used to declare data to be in Program Space. – Rev Oct 12 '17 at 09:59
  • 2
    @Rev1.0 it would have been useful to comment *what* actually puts data into program space when `const` doesn't - the `PROGMEM` attribute. – tofro Oct 12 '17 at 10:09
  • @Rev1.0: A `static const` is usually optimized-out by the compiler into immediate operands: no SRAM usage. A C++ `const` is implicitly `static`. @tofro: For arrays, I would use `__flash const` rather `PROGMEM` in plain C. – Edgar Bonet Oct 12 '17 at 10:50
  • @EdgarBonet: It MAY indeed be optimized, but it is by no means a reliable way to save SRAM / predict storage behavior. And since its compiler dependent it wouldn't be portable behavior. I just did some reading and as someone pointed out "I want to emphasize that the reason to use or not use const really ought to be for program correctness and for clarity for other developers more so than for compiler optimizations". I tend to agree. – Rev Oct 12 '17 at 14:13
1

There's some serious misconceptions going on here.

  • 0x00800200, LENGTH = 32K - 500. 200h is not the same as 500, but the same as 512. Also, 0x00810000 - 0x00800000 is not 32k but 64kib. There are lots of such errors all over, whoever setup this linker file didn't quite know what they were doing and they didn't know hexadecimal numbers.
  • "The Program is working for a size output of..." 10914 + 25427 = 36341 bytes. How can it work fine, you just said that you have 32kib of physical RAM available on the chip. And you also reserve 512 bytes for the stack. It does not work fine, it might seem to work for now, by pure chance.

If you think that your program can work fine when you allocate more memory than what is physically available, there is no hope for you to ever recover this program. Memory cannot be allocated in thin air. Similarly, you cannot have RW sections that are larger than 256k added together unless there's some special boot area ROM on this chip.

The reason why you don't get any linker warnings might be because you have told the linker that you have 64kib available, while the physical chip only got 32kib.

Lundin
  • 195,001
  • 40
  • 254
  • 396
  • What you are wrtiing seems reasonable. Well it is working fine for me, I did not see any unexpected behavior, but that indeed may be by chance. How can I modify the Linker file to be accurate? Just change the adress? – LasseSte Oct 12 '17 at 13:32
  • I just added the avr-size -A output. As you see the general output adds up .eeprom and .data to "data". So .bss and .data is still smaller then 32K. So the linker is not giving a warning correctly. That does not solve my Problem though. – LasseSte Oct 12 '17 at 16:50
  • 1
    @LasseSte Your whole MEMORY section declaration is still nonsense. There is no relation between the hex addresses and LENGTH. – Lundin Oct 13 '17 at 06:27
  • There actually were a lot of problems in this section as well as in the linker options in the makefile. I corrected those and for the moment I do not face anymore Problems. Thank you for pointing this out. – LasseSte Oct 13 '17 at 18:10
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.

dbrank0
  • 9,026
  • 2
  • 37
  • 55
  • "our bss+data sections (both probably go to data region) exceed your data region " No they don't, because he told the linker that the data region is 64kib. But there's just 32kib of physical memory. – Lundin Oct 12 '17 at 11:54
  • Did he? Where? As I understand it linker script is telling linker data region is located at 0x00800200 and is 32268 bytes long. Then there is approximately 32kb of nothing. And then eprom. Guessing data sections probably go to data region, but can only guess, as that part of linker script is missing. – dbrank0 Oct 12 '17 at 12:27
  • That's the only explanation of the missing linker errors that I can think of. Alternatively, the tool chain could be pure crap, which is also a possibility. – Lundin Oct 12 '17 at 13:34
  • I added the complete linker file used. I am not used to work with linker files, until now I always just took the linker file provided by the manufacturer and it worked fine. – LasseSte Oct 12 '17 at 13:56