avr flash usage after the first 128KB

Go To Last Post
9 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I'm having troubles with C++ objects static constructors
when those are mapped after the 1st 128KB (basically this applies to any code that I wish to run before running the main).
It seems like the compiler is not able to use the "trampoline_jump" for those. When any of these functions reside outside the boundaries of the 128KB, the __do_global_ctors loop calls __tablejump_elpm__ which basically loads R31 and R30 with zeros and happily jumps to that.

Is there a work around?

I'd just need a way to instruct the compiler to put the program code of all these constructors in a separate section that I could just put that before the .text section..
Do you know of anything like this?
R

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

First off all, make sure that the 128KiB flash segment where section .trampolines is located coicides with the value held in EIND, see the GCC documentation for an example how to achive that.

Take care that .trampolines is not shifted out of the section by too-much code or overlaps a 128 KiB segment boundary. You may want to use your own linker script to ensure this, see binutils PR13812 (open).

Make sure that your tools come with a fix of GCC PR45263 (fixed in 4.6.1, for private ports ask your port maintainer) resp. ensure that this problem does not affect your code.

Last if you use a toolchain with PR50820 (fixed in 4.6.1) arrange for a setup with EIND = 0 or use a fixed version.

To go to a GCC problem report (PR), append the respective PR to
http://gcc.gnu.org/

To go to binutils PRs, append the PR to
http://sourceware.org/

avrfreaks does not support Opera. Profile inactive.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Why static constructors? In my 6 years programming the AVR with C++ I've never used them. It seems like a bad idea to me. I new all my classes that aren't put on the stack. Six lines of code will give you a new operator that allocates from the heap. I use 8 lines, but I'm verbose.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Look at what code the compiler generates.

Depending on compiler version, it puts startup code like C-constructors in .text.startup.

If so, you can handle that section in your linker script. and put .text.tartup before .text.

If not, you have to get the mangled name use -ffunction-sections.

I don'u use C++ and don't know if that also applies to C++ constructors, but it's easy enough to check avr-gcc's result.

ad "bad idea":

Constructors in C can be very comfortable and useful, for example to write self-contained modules.

avrfreaks does not support Opera. Profile inactive.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

SprinterSB wrote:

ad "bad idea":

Constructors in C can be very comfortable and useful, for example to write self-contained modules.

Constructors are good. Static classes, with their static constructors are not so good, and I think unnecessary.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

Constructors are good. Static classes, with their static constructors are not so good, and I think unnecessary.

Surely this is exactly the same argument as to which is better (in plain C) between:

// global
int data[10];

and

int * data;

...

data = (int *)malloc(20);

The bonus of using compile time allocation of .data and .bss is that CRT provides setup code for the entire regions in one nice, tight loop. Apart from that it's kind of moot though I guess the compile time allocation also means that before the code runs you know if it fits or not.

Surely it's the same for _ctors in C++? There's nothing inherently wrong with the CRT setting things up is there?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I guess not, but it seems strange to me. If it works, it works. Apparently the OP has problems.

The order that things get constructed at startup can be important. I don't know how I would know the order if they were statics. By using "new", I can control the order.

I can also pass the address of one class to another. For instance I have these in my "executive" class that starts everything up.

      new Push_button(new Port_e_regs, Port_regs::Pin3);


      new Blink(new Port_e_regs, Port_regs::Pin1);


      parse_in_message_p = new Parse_in_message(new Usart_d0);  


      new Export_divided_per_clock(       // divide PER by 10
         new Counter_c1_regs,
         Counter_regs::Div_by_1,
         5,
         new Port_c_regs,
         Counter_regs::Pin_shift_4
         );

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I don't know if it is appropriate or not to use static constructurs, but I know I need to use em.
I investigated the problem in more details and figured out that what makes the difference is that with code that exceeds the 128KB of flash, a series of zeroes appear in the [__ctors_start, __ctors_end] section.
This section is filled with 16bits funciton pointers to all the static constructors (or, more in general, generic functions) that need to be called prior to run the main code.
The pointers are fetched by __do_global_ctors and jumped-to by __tablejump_elmp__.
When a static constructor is located beyond the 1st 128KB of Flash memory, in the __ctors_start section a NULL 16bits pointer appears (0x0000).
Such pointer is then fetched and loaded into the Z register by __tablejump_elpm__ function and then an eijmp tries to jump to that location, and everything screws up.

SOLUTION:
In the end I found this other post:
https://www.avrfreaks.net/index.p...
In there, dl8dtl advices the use of the "relax" option ("-Xlinker --relax" in the LDFLAGS).
When using this option the issue is completely fixed, as ALL static constructors get listed into the trampoline table at the beginning and the jump in __tablejump_elpm__ is now not done towards the function itself but to its trampoline hook.
This completely fixed the problem as now ALL the __ctors_start are filled with correct pointers.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

oh and don't forget to impose that the text section starts at address 0x0; if you try to reserve a section for vectors (like I did) and start text area from somewhere else (say addr K > 0x0), all functions betweeen (128K - K)[B] and 128KB will not get their trampiline... :(

(I should get a star for this) ;)