Classes and noinit

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

This is an fyi rather than a question.

 

I recently had an issue with noinit objects. In retrospect it was obvious.... so obvious that I recall running into it years ago and forgetting.

 

When instantiating a cpp object, the noinit attribute can be specified. For example

ErrorLog errorLog __attribute__ ((section (".noinit")));

This all worked just fine. My error log persisted through restarts and was helpful in solving all sorts of issues... and then it stopped.

 

The issue was that I had run cppCheck and been through and resolved many of the warnings that it flagged. One of the warnings was the lack of initialisation in the constructor for the class.

 

Now obviously if the constructor initialises all of the attributes, noinit has no effect.

 

It is obvious now.... but it wasn't at the time.

 

Hopefully I don't forget this again and lose more sleep sad

 

Regards

Greg

 

 

regards
Greg

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

gregd99 wrote:

When instantiating a cpp object, the noinit attribute can be specified. For example

ErrorLog errorLog __attribute__ ((section (".noinit")));

 

But `noinit` attribute is specified simply as `__attribute__ ((noinit))`, not as `__attribute__ ((section (".noinit")))` (assuming your compiler supports it.)

 

The specific behavior you observed is a consequence of you using that `section (".noinit")` instead of the actual `noinit` attribute. That way you disabled zero-initialization but preserved the constructor call.

 

 

Dessine-moi un mouton

Last Edited: Tue. Aug 18, 2020 - 06:23 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi Andrey,

I tried

extern ErrorLog errorLog __attribute__ ( (".noinit") );

but always rx'ed the error "expected ')' before string constant".

 

All of the other avr examples I have seen include "section". Do you have a compilable example?

Thanks

Regrds

Greg

regards
Greg

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

Did you try

extern ErrorLog errorLog __attribute__ ((noinit));

 

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

gregd99 wrote:

I tried

extern ErrorLog errorLog __attribute__ ( (".noinit") );

but always rx'ed the error "expected ')' before string constant".

 

As I stated above, it should be  `__attribute__ ((noinit))`, not `__attribute__((".noinit"))`. No string literals involved.

 

Having said that, while GCC documentation lists `noinit` as a valid variable attribute, I haven't been able to find an implementation that actually supports it. It is accepted by the syntax, but the compiler warns that this attribute is ignored.

Dessine-moi un mouton

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

Thanks for the correction.

 

I tried

__attribute__ ((noinit))

It compiles.... it seems to do nothing.

There was a warning

warning: 'noinit' attribute directive ignored [-Wattributes]

 

regards
Greg

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

Sorry.  So you were right in the first place.   That warning comes from the avr code in gcc itself.   The avr-libc manual section on memory indicates your original method is the correct approach.

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

MattRW wrote:

The avr-libc manual section on memory indicates your original method is the correct approach.

 

It is not a "correct" approach. `__attribute__((section (".noinit")))` is sufficient for C, but this topic is specifically about C++. 

 

`__attribute__((section (".noinit")))` is not a replacement for `__attribute__((noinit))` in C++ code, since the former does not suppress constructor calls. As far as I can see, avr-gcc offers no solution for C++ at all. Support for `__attribute__((noinit))` is simply not implemented.

Dessine-moi un mouton

Last Edited: Mon. Aug 24, 2020 - 03:33 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

A constructor can use assembly to determine whether the object is within the .noinit section.

Another possibility is to define the objects only in assembly.

Data in the .noinit section will not find its way to the hex file or binary.

Yet another possibility is to not define the objects at all: Just use assembly to define their symbols.

Be careful with that. You will be side-stepping the compiler's ability

to prevent overlaps and the linker's ability to detect overlaps.

You will need to explicitly set the address of the following section.

Still another possibility is to use a derived type with only empty constructors.

 

This is one instance where one might want to use inline assembly in order to insert sizeof(errorLog) into it.

Iluvatar is the better part of Valar.

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

skeeve wrote:

Be careful with that. You will be side-stepping the compiler's ability

to prevent overlaps and the linker's ability to detect overlaps.

You will need to explicitly set the address of the following section.

Or put it "out of the way" - like change the stack init to lower the top of stack and then put it above there perhaps?

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

clawson wrote:
skeeve wrote:

Be careful with that. You will be side-stepping the compiler's ability

to prevent overlaps and the linker's ability to detect overlaps.

You will need to explicitly set the address of the following section.

Or put it "out of the way" - like change the stack init to lower the top of stack and then put it above there perhaps?
I'd expect that to work.

The value desired is probably RAMEND-sizeof(errorLog).

IIRC the inline assembly should have "r"(RAMEND-sizeof(errorLog)) in the input constraint list.

If for some reason one wants to save a register at the expense of size and legibility,

"I"(RAMEND-sizeof(errorLog)) could also be used.

Iluvatar is the better part of Valar.