C++ warning with PROGMEM (4.2.2)

Go To Last Post
55 posts / 0 new

Pages

Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Recompiling a project with avr-gcc 4.2.2 leads to the message

Quote:
warning: only initialized variables can be placed into program memory area
. Both of the following variables lead to the same problem:

#include 
#include 


typedef struct {
  uint8_t reg_, addr_;
} init_table_t;

init_table_t initTable[] PROGMEM = {
    { 1, 17 },
    { 7, 33 },
};

char aString[] __attribute__((progmem)) = "initialized or not, that's the question";

Anybody know what's going on here?

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

At least the initTable has an extra comma there before };

- Jani

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

Quote:

the initTable has an extra comma there before };

Which actually is allowed in C (IIRC).

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

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

the comma is allowed (like an extra ; ).
I should also mention that the code compiles fine if compiled as C code, and the C++ version was OK for avr-gcc 4.1.1.

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

Quote:
the C++ version was OK for avr-gcc 4.1.1

Time to look for, or report, a regression bug?

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

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

I have seen the same warning. The most annoying thing is that every occurence of printf_P(PSTR("...")) emits this warning.

Here is a testcase and its output when using avr-c++. Notice that only one of the two initializations produces the warning. If I feed this code trough the C compiler no warnings are emitted and the resulting assembly code is identical.

#include 
#include 

const prog_char p_str2[] = "321";

int __attribute__((naked)) main()
{
   PGM_P p_str = PSTR("123"); //main.cpp:8: warning: ...

   PORTA = pgm_read_byte(&p_str[0]);
   PORTB = pgm_read_byte(&p_str2[0]);

   return 0;
}
[tuomas@blackbox var_test]$ make
avr-gcc -I. -g  -mmcu=atmega32 -Os -fpack-struct -fshort-enums -funsigned-bitfields -funsigned-char -Wall -Wa,-ahlms= -fno-exceptions -fcheck-new -Wa,-ahlms=main.lst -c main.cpp -o main.o
main.cpp: In function 'int main()':
main.cpp:8: warning: only initialized variables can be placed into program memory area
avr-gcc -o myproject.out  main.o    -Wl,-Map,myproject.out.map -mmcu=atmega32 -lm
[tuomas@blackbox var_test]$

For this second example I don't know a workaround that wouldn't produce any warnings.

#include 
#include 

const prog_char str[] = "123";
const prog_char* p_str PROGMEM = str; //warning

int __attribute__((naked)) main()
{
   PGM_P ptr;

   ptr = (prog_char*)pgm_read_word(&p_str);
   PORTA = pgm_read_byte(ptr);

   return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Using the new version (gcc-4.2.2, avr-libc-1.6.1) I've done some checking and found a solution, or work around, I'm not sure which one.

PSTR is defined as (pgmspace.h):

# define PSTR(s) (__extension__({static char __c[] PROGMEM = (s); &__c[0];}))

If I change the definition to

# define PSTR(s) (__extension__({static prog_char __c[] = (s); &__c[0];}))

g++ is happy as well. I'm not sure if this is a g++ issue or if g++ just got a little more standards compliant and it is an avr-libc issue.

Markus

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

I have just switched to WinAVR 20071221. I now get this compiler warning on all initialized variables I've defined with PROGMEM, which includes many structures and arrays. The work-around of changing type from char to prog_char can't be applied to structures.

It appears that I do get all the correct results, but it's startling to see a new WinAVR released with such an obvious (if minor) bug.

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

I am on to something but I don't know what.

Observation 1:

prog_int32_t rt; // no warning

int PROGMEM rt2; // warning

The difference is that prog_int32 is typedefed.

Observation 2:

class C
{
  void method( void );
} PROGMEM cObj1; // No warning.

C PROGMEM cObj2; // Warning

A class definition is treated as a typedef sometimes.

Observervation 3:

#if 1 // try 1 or 0
prog_int32_t rt1; // at the same time as
int PROGMEM rt2 = 5; // results in a error...
#else
class C
{
  void method( void );
} PROGMEM cObj1; // at the same time as
int PROGMEM rt2 = 5; // results in a error...
#endif

... error: rt2 causes a section type conflict.

Cheers

Olof

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

Tuomas wrote:

const prog_char str[] = "123";
const prog_char* p_str PROGMEM = str; //warning

You are trying to define a PROGMEM constant using what C thinks is a variable initializer (str). Instead, try:
const prog_char* p_str PROGMEM = "123";

All PROGMEM constants must be marked as "const", or at least it seems that way to me. I have scads of PROGMEM constants, all defined as const, which compile just fine in WinAVR 20071221. Examples:

static const char gen_SEMI  [] PROGMEM = "; "; 
static const char gen_ZERO  [] PROGMEM = "0"; 
static const char gen_DOT   [] PROGMEM = "."; 
static const char gen_DASH  [] PROGMEM = "-"; 
static const char gen_SPACE [] PROGMEM = " "; 
static const char gen_DUNNO [] PROGMEM = "";

. . . in another file, not so very far away...

#define CMD_ERROR_NO_ERROR	0

#define ERROR_TABLE(n) et_ ## n
		
#define ERROR_STRING(n,s) \
	const char et_ ## n [] PROGMEM = s ;

ERROR_STRING( CMD_ERROR_NO_ERROR, "Command succeeded" )

All of the above compile with no errors, no warnings.

Stu

Engineering seems to boil down to: Cheap. Fast. Good. Choose two. Sometimes choose only one.

Newbie? Be sure to read the thread Newbie? Start here!

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

oloftangrot wrote:

prog_int32_t rt; // no warning

int PROGMEM rt2; // warning

Again, it makes no sense to have a non-const PROGMEM variable. Try the following instead:
const int PROGMEM rt2 = 5;

Don't forget to give the const a value!

Stu

Engineering seems to boil down to: Cheap. Fast. Good. Choose two. Sometimes choose only one.

Newbie? Be sure to read the thread Newbie? Start here!

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

I suspect those of you not experiencing this problem are using C, not C++. If I cut & paste the line Stu suggests into a C++ program, it gives me the compiler warning.

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

If the keyword "const" is required than why dont I get a warning from:

prog_int32_t rt;  // const is not a part the the typedef!

???

As I see it the conditions where the warnings are emitted or not emitted from the compiler spurious and misleadning, that is what does not make sense.

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

stu_san wrote:
You are trying to define a PROGMEM constant using what C thinks is a variable initializer (str). Instead, try:
const prog_char* p_str PROGMEM = "123";


Ah, but that was only a simplification I made. What about if I wanted to have an array of flash strings in flash? According to forums PROGMEM tutorial the individual strings must be declared first, and then pointers to them are stored in an array.

const prog_char str1[] = "123";
const prog_char str2[] = "456";
const prog_char* p_str[] PROGMEM = { str1, str2 };

From that last line GCC C++ compiler (avr-g++ 4.2.2) prints a warning that says:

warning: only initialized variables can be placed into program memory area

With C compiler the same code is just fine.

EDIT: Added missing square brackets p_str -> p_str[]. Now it looks like the code I tested...

Last Edited: Tue. Jan 8, 2008 - 12:15 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

What if you change the code to this?:

const prog_char str1[] PROGMEM = "123";
const prog_char str2[] PROGMEM = "456";
const prog_char* p_str PROGMEM = { str1, str2 };

Do you still get a warning with the C++ compiler?

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

yup, you get 3 of them:

x.cpp:3: warning: only initialized variables can be placed into program memory area
x.cpp:4: warning: only initialized variables can be placed into program memory area
x.cpp:5: warning: only initialized variables can be placed into program memory area
x.cpp:5: error: scalar object 'p_str' requires one element in initializer
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yes, the result is as MegaTorr posted. In my previous post the square brackets needed in p_str[] were missing for some reason. I edited the post. However, that only gets rid of the show stopping error in MegaTorr's post...

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

I'm late to this party but if the typedef of prog_char is:

typedef char PROGMEM prog_char;

Then why would one want to use:

const prog_char str1[] PROGMEM = "123";

That seems to be delivering a lot more "PROGMEM" than is entirely necessary.

Cliff

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

Neither the (extra) PROGMEM nor the "const" make a difference on the variable initialization. It appears that it is necessary to use typedef to get rid of the warning:

struct foo
{
	int	i;
};

foo foovar1 PROGMEM = {5};

typedef foo prog_foo PROGMEM;
prog_foo foovar2 = {5};

The definition of foovar1 gets a warning, foovar2 doesn't.

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

So it seems there's some weird bug here. I would suggest filling out a bug report on the GCC project.

Note that support for C++ for AVR GCC may be incomplete as there aren't any dedicated people working on it AFAIK.

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

OK, I was preparing everything to report a gcc bug and while I was waiting for the paperwork to complete I went over the documentation again, and this is what I found:

The documentation regarding attributes (function,type,varaiable) is extremely vague and even says on several occasions (in one form or another):

Quote:
... but at present this is not implemented

However, right at the beginning of section "5.26 Attribute Syntax" it says:
Quote:
Some details may vary for C++ and Objective-C. Because of infelicities in the grammar for attributes, some forms described here may not be successfully parsed in all cases.
and later on:
Quote:
There are some problems with the semantics of attributes in C++. For example, there are no manglings for attributes, although they may affect code generation, so problems may arise when attributed types are used in conjunction with templates or overloading. Similarly, `typeid' does not distinguish between types with different attributes. Support for attributes in C++ may be restricted in future to attributes on declarations only, but not on nested declarators.
(italics added by me)

So the documentation says that not all of this might work in C++, and (as I understand it) the only safe way to declare attributes is in the declaration. Following that lead I wrote the following tests:

int i1 __attribute__((__progmem__)) = 1;
int __attribute__((__progmem__)) i2 = 2;
__attribute__((__progmem__)) int i3 = 3;
extern int i4 __attribute__((__progmem__)); int i4 = 4;
extern int __attribute__((__progmem__)) i5; int i5 = 5;
extern __attribute__((__progmem__)) int i6; int i6 = 6;
typedef int i7_t __attribute__((__progmem__)); i7_t i7 = 7;
typedef int __attribute__((__progmem__)) i8_t; i8_t i8 = 8;
typedef __attribute__((__progmem__)) int i9_t; i9_t i9 = 9;

(sorry about the formatting, but this way the line number corresponds with the version). According to the documentation all 9 variations should be legal for C, and they are. In C++ however the first 3 generate said warnings, whereas the other 6 compile just fine. As a note, the generated code is correct and identical for both, C and C++.

Moving on to strings (which are almost more important in this context than integers) I wrote the equivalent test cases:

const char s1[] __attribute__((__progmem__)) = "string 1";
const char __attribute__((__progmem__)) s2[] = "string 2";
const __attribute__((__progmem__)) char s3[] = "string 3";
__attribute__((__progmem__)) const char s4[] = "string 4";
extern const char s5[] __attribute__((__progmem__)); const char s5[] = "string 5";
extern const char __attribute__((__progmem__)) s6[]; const char s6[] = "string 6";
extern const __attribute__((__progmem__)) char s7[]; const char s7[] = "string 7";
extern __attribute__((__progmem__)) const char s8[]; const char s8[] = "string 8";
typedef const char s9_t __attribute__((__progmem__)); const s9_t s9[] = "string 9";
typedef const char __attribute__((__progmem__)) s10_t; const s10_t s10[] = "string 10";
typedef const __attribute__((__progmem__)) char s11_t; const s11_t s11[] = "string 11";
typedef __attribute__((__progmem__)) const char s12_t; const s12_t s12[] = "string 12";

Again, all 12 declarations/definitions are legal for C. In C++ however the first 4 generate the warning whereas the latter 8 compile fine. This time, however the generated code differs. The C++ compiler only generates code for the 4 extern declared variables (I currently have no explanation for that)!

The same exercise can be constructed for structs, with the same results. When the initialization goes along with the declaration C++ issues the warning, when declaration and definition/initialization are separated C++ has no issues.

Given the gcc documentation and the results from above I'm not sure if it actually is a gcc bug (it kinda' works like advertised).

I'm currently leaning towards an avr-libc issue. If somebody with more insight than me could let me know which way to go I'll file an issue.

Markus

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

The documentation you quote has not changed from the previous compiler version. But the compiler has clearly regressed, and it should be reported as such.

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

I'm aware of the old (4.1) documentation, but it didn't have to change. Even the old documentation (4.1) stated that it is not guaranteed to work for C++, although it did. Unfortunately the documentation in this regard is very vague and doesn't state what, and which scenario is supposed to work and which isn't. Strictly speaking, both version (4.1 and 4.2) work as documented.

The way I read it is that it might work, or might not, in both versions. As I understand the documentation it basically says: If it works in C++, good for you, if it doesn't, we told you so.

If I read the documentation wrong, please indicate what I'm missing.

Markus

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

This is not an issue about whether the attribute works. The attribute does work -- the data is placed in the correct section. This is about some additional logic processing this particular attribute that is producing a bogus warning. The EEMEM attribute, for example, continues to work fine.

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

That is most interesting. Replacing __attribute__((__progmem__)) with __attribute__((__section__(".eeprom")) in the tests above works, except for the typedefs. There I get an error that says:

Quote:
error: section attribute not allowed for ...

and more specifically on some of the structure tests:
Quote:
warning: '__section__' attribute does not apply to types
No wonder the documentation is so vague.

Markus

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

gcc bug #34734

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

Thanks. I'm on the CC list.

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

If I declare in my class declaration in the header file

static char text[] PROGMEM;

and then implement in source file

char text[] PROGMEM = "something";

then I have a warning, but if I implement in source file

char text[] = "something";//without PROGMEM macro

then everything is ok.

In my case typedef prog_char is not working properly.

Sorry for my not so good english.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
static char text[] PROGMEM

;
But you are not declaring it static in the source file. Don't you mean:

extern char text[] PROGMEM;

Quote:
If I declare in my class declaration in the header file

That is not a "class", it is simply a variable.

And what warning are you getting?

Regards,
Steve A.

The Board helps those that help themselves.

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

It's great news that someone has found a work-around for this erroneous warning. I have dozens of these warnings in my current project, and now there's a way to eliminate some of them. I'm changing variable declarations from this:

char StrTrue[] PROGMEM = "true";

to this:

extern char StrTrue[] PROGMEM;
char StrTrue[] = "true";

Many of my warnings are generated from the PSTR() macro and I haven't yet looked to see if it can be rewritten to use the same work-around.

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

Here's a workaround:

# Workaround for http://gcc.gnu.org/bugzilla/show_bug.cgi?id=34734
#ifdef PROGMEM
#undef PROGMEM
#define PROGMEM __attribute__((section(".progmem.data")))
#endif

From looking at the gcc source, that's all the __attribute__((__progmem__)) directive that PROGMEM expands to actually does.

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

A little more info that may help somebody investigating this problem:

I was getting the "...causes a section type conflict" error when I tried to place two different aggregate objects into Flash, using g++-4.5.0. After a bunch of screwing around, I figured out that if you place things in sections named ".progmemSOMETHING" and SOMETHING is different for every thing (i.e., every thing is in its own section) then the compiler and linker stay happy.

Unfortunately, I can't construct a simple 3-liner that shows the difference; there's obviously more going on under the covers than I'm aware of. But it's something to try, if you're having this problem and are starting to pull your hair out.

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

I figured out a reasonably easy fix for this. Just create a macro that drops the declaration into the .progmem.data section:

#define PS __attribute__((section (".progmem.data")))

Then, use it instead of PROGMEM. Seem to work, and the strings go into the text segment.

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

What I started doing is put all PROGMEM and EEPROM constants into a separate ansi-c file. So I have constants.c which holds all definitions and constants.h which has the declarations (extern).

constants.h:

extern const PROGMEM char ErrorString[];

constants.c:

const char ErrorString[] PROGMEM = "error";

'Bit of a pain but it gets rid of the warnings. For strings I typically use the files i18n.h and i18n.c and call it a feature ;).

Have fun,
Markus

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

Thanks, this hint was nice!

i modified the PSTR macro in pgmspace.h like that:

# define PSTR(s) (__extension__({static const char __c[] __attribute__((section (".progmem.data"))) = (s); &__c[0];}))

It seems to work for c and cpp.

I first tried to replace the PROGMEM macro as suggested, but I got errors with the typedefinitions "prog_uint16_t" and it friends.

It realy looks like, that the compiler does some additional penality check, when it sees the __progmem__ attribute and might gets confused with it. However, this checks seems not to be run on the similar attribute "section (".progmem.data")".

Regards,
cleanertm

bob16180 wrote:
I figured out a reasonably easy fix for this. Just create a macro that drops the declaration into the .progmem.data section:

#define PS __attribute__((section (".progmem.data")))

Then, use it instead of PROGMEM. Seem to work, and the strings go into the text segment.

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

Quote:

Code:
struct foo
{
   int   i;
};

foo foovar1 PROGMEM = {5};

typedef foo prog_foo PROGMEM;
prog_foo foovar2 = {5}; 

The definition of foovar1 gets a warning, foovar2 doesn't.


the point is that in g++, attributes does not survive through typedef so the reason why it does not produce warning is that g++ does not see the PROGMEM attribute at all, where prog_foo is used.

PS: I know my answer is late a little bit. It's just for people who get here using google.

EDIT: OMG, I should see I'm posting answer to the last comment on first page, not the last comment of the thread...

Last Edited: Wed. Feb 1, 2012 - 12:42 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

mihlit wrote:
the point is that in g++, attributes does not survive through typedef so the reason why it does not produce warning is that g++ does not see the PROGMEM attribute at all, where prog_foo is used.
In that case, the typedef really should get a warning.
Also, you might want to fix the [/code] tag.[done]

Iluvatar is the better part of Valar.

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

mihlit wrote:
g++ does not see the PROGMEM attribute at all, where prog_foo is used.
Please notice that attribute progmem in typedef is undocumented feature in avr-gcc, so you use it at your own risk just as any other unspecified behavior. See also

http://gcc.gnu.org/PR38342

avrfreaks does not support Opera. Profile inactive.

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

I've just tried to change a code to make it work with any combination of avr-gcc 4.3,4.4,4.5,4.6 and avr-libc 1.6.7..1.8.0 but I just found out that different avr-gcc versions are... "different" or just not compatible). That's such a mess... how do you write a code that different people should be able to compile? I got everything from "only initialized variables...", "conflict of sections",... to data not placed in program memory at all.

In the end, I've used following solution (PROGMEM redefinition is not needed with avr-gcc 4.6.2):

#include 
#undef PROGMEM
#define PROGMEM __attribute__(( section(".progmem.data") ))

typedef char pm_char;
const pm_char hello[] PROGMEM = "Hello world";

int foo(const pm_char *s)
{ 
  const pm_char *str = s;

So I have my own type pm_* instead of prog_* because new avr-libc does not provide such types unless you use special define in which case it spawns tons of "prog_* is deprecated" warnings. Anyway, prog_* or pm_* does not affect variable storage at all, it's just I can see this is variable stored in program section, so I can't use it directly.

Every variable using data stored in progmem section needs to be const or avr-gcc won't like you.

On variable initialization and only on variable initialization, there must be PROGMEM used - only where you specify the real data which should be stored in program section.

This way it works with new avr-gcc and any version of avr-libc I've tried - but I did not tried all of them. (I do this only because my build environment is up to date, but a lot of Mac users use CrossPack-AVR where the most recent version has avr-libc 1.6.7 and avr-gcc 4.3.3).

Does anyone know better solution how to make it work with old and new avr-gcc+avr-libc? Or is there any problem I've missed?

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

I suppose there's always:

E:\avr>avr-gcc -E -dM test.c | grep GNU
In file included from test.c:1:
#define __GNUC_PATCHLEVEL__ 3
#define __GNUC__ 4
#define __GNUC_MINOR__ 3

(this for my 4.3.3)
Similarly:

E:\avr>avr-gcc -E -dM test.c | grep LIBC
#define __AVR_LIBC_MAJOR__ 1
#define __AVR_LIBC_MINOR__ 6
#define __AVR_LIBC_REVISION__ 7

AVR LibC 1.6.7

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

mihlit wrote:
I've just tried to change a code to make it work with any combination of avr-gcc 4.3,4.4,4.5,4.6 and avr-libc 1.6.7..1.8.0 but I just found out that different avr-gcc versions are... "different" or just not compatible). That's such a mess...
Yes. The reason is there were bugs like PR44643, PR38342, PR34734 or PR43746 hanging around for quite some time. Some of these PRs are induced by abusing GCC's internal structures which worked in old versions but triggered problems in newer ones.

To make the mess complete, people greedily used undocumented and unsupported stuff like attribute 'progmem' in typedef, and avr-libc promoted abusage by providing custom prog_* types, which is issue #33716 there.

Quote:
How do you write a code that different people should be able to compile?
People don't compile code. Code is being compiled by compilers ;-) So the question is what versions of avr-gcc you'd like to cover. As general recommendation:
  • Only use attribute 'progmem' with read-only data
  • Don't use attribute 'progmem' in type(def)s
  • Use the compiler version with highest patch level within the release series. Release series is 4.5, for example and the patch levels are 4.5.0, 4.5.1, 4.5.2, etc.
  • As you observed, 'progmem' does not work with C++ for all versions. As PR34734's milestone is 4.6.2, you don't want to use 'progmem' with C++ if your set of compiles contains a version < 4.6.2.
  • Notice that a high patch level doe not guarantee an issue is fixed or will ever be fixed in the release series. The number of guys that are willing to contribute to avr-gcc is much too low as to backport every bugfix.
Quote:
Every variable using data stored in progmem section needs to be const or avr-gcc won't like you.
Correct. That's what the dcumentation says. Does it make sense to have non-read-only data in flash?

Finally, and as you have a proper build environment: Maybe you want to try future avr-gcc 4.7.0, too?

avrfreaks does not support Opera. Profile inactive.

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

SprinterSB wrote:
Finally, and as you have a proper build environment: Maybe you want to try future avr-gcc 4.7.0, too?

Tried that. PROGMEM data are on correct place, at least avr-size says it. I was not able to run that code, because gcc 4.7.0 has regression and when optimization is used, compiler fails:

http://gcc.gnu.org/bugzilla/show...

and without optimization, result is bigger than flash in processor.

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

Many thanks for the report, I can reproduce the bug.

For a quick fix you can add -fno-split-wide-types

avrfreaks does not support Opera. Profile inactive.

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

mihlit wrote:
I've just tried to change a code to make it work with any combination of avr-gcc [...] I got everything from "only initialized variables...", "conflict of sections",...
You also have a test case for the "conflicting section type flags" problem?

avrfreaks does not support Opera. Profile inactive.

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

SprinterSB wrote:
mihlit wrote:
I've just tried to change a code to make it work with any combination of avr-gcc [...] I got everything from "only initialized variables...", "conflict of sections",...
You also have a test case for the "conflicting section type flags" problem?

typedef char prog_char __attribute__((__progmem__));

const prog_char __attribute__(( section(".progmem.data") )) modn12x3[]= {4, 3, 2, 1 };

static const prog_char __attribute__(( section(".progmem.data") )) string_1[] = "Simple 4-CH";

const prog_char * n_Templates[1] __attribute__(( section(".progmem.data") )) = {
    string_1
};

avr-gcc 4.7.0,4.3.3 gives following error:

$ avr-gcc -c -mmcu=atmega64  reproducer2.cpp
reproducer2.cpp:3:61: error: modn12x3 causes a section type conflict with n_Templates
reproducer2.cpp:7:19: note: 'n_Templates' was declared here

avr-gcc 4.6.2 is silent

Btw, I've tried 20120204 snapshot and that 4.7 regression seems to be gone, but I got another one:

error: unable to find a register to spill in class 'POINTER_REGS'
error: this is the insn:
(insn 19 18 20 2 (parallel [
            (set (mem:BLK (reg:HI 26 r26) [0 A8])
                (mem:BLK (reg/v/f:HI 132 [ anas ]) [0 A8]))
            (unspec [
                    (const_int 0 [0])
                ] UNSPEC_MOVMEM)
            (use (reg:QI 24 r24 [134]))
            (clobber (reg:HI 26 r26))
            (clobber (reg:HI 30 r30))
            (clobber (reg:QI 0 r0))
            (clobber (reg:QI 24 r24 [134]))
        ]) open9x.cpp:245 29 {movmem_qi}
     (expr_list:REG_DEAD (reg:QI 24 r24 [134])
        (expr_list:REG_DEAD (reg:QI 27 r27)
            (expr_list:REG_UNUSED (reg:QI 24 r24 [134])
                (expr_list:REG_UNUSED (reg:QI 0 r0)
                    (expr_list:REG_UNUSED (reg:HI 30 r30)
                        (expr_list:REG_UNUSED (reg:HI 26 r26)
                            (nil))))))))
internal compiler error: in spill_failure, at reload1.c:2120

It's related to:
-O1 -fgcse -finline-small-functions -flto

If I remove anything from these, problem is gone.

This happens when linking final result. I'm not able to reduce reproducer right now.

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

Quote:
Btw, I've tried 20120204 snapshot and that 4.7 regression seems to be gone, but I got another one:

error: unable to find a register to spill in class 'POINTER_REGS'
...
internal compiler error: in spill_failure, at reload1.c:2120

It's related to:
-O1 -fgcse -finline-small-functions -flto

If I remove anything from these, problem is gone.

This happens when linking final result. I'm not able to reduce reproducer right now.

Looks similar to:
http://gcc.gnu.org/bugzilla/show...
http://gcc.gnu.org/bugzilla/show...

but compared to both bugs above, adding -fno-caller-saves does not fix the problem

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

mihlit wrote:

typedef char prog_char __attribute__((__progmem__));

const prog_char __attribute__(( section(".progmem.data") )) modn12x3[]= {4, 3, 2, 1 };

static const prog_char __attribute__(( section(".progmem.data") )) string_1[] = "Simple 4-CH";

const prog_char * n_Templates[1] __attribute__(( section(".progmem.data") )) = {
    string_1
};

  1. If you put stuff in flash, make it read-only.
  2. 'progmem' in types is undocumented. It does not work, did never work, will never work reliably, see http://gcc.gnu.org/PR38342
If you want to factor out PR34734 from some older avr-g++, you can
#ifdef __cplusplus
#define PROGMEM __attribute__((section (".progmem.data")))
#else
#define PROGMEM __attribute__((__progmem__))
#endif

const char modn12x3[] PROGMEM = {4, 3, 2, 1 };

static const char string_1[] PROGMEM = "Simple 4-CH";

PROGMEM const char * const n_Templates[1] =
{
    string_1
};

From the last definition you see that it does not matter where in the definition the PROGMEM occurs.

avrfreaks does not support Opera. Profile inactive.

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

mihlit wrote:

error: unable to find a register to spill in class 'POINTER_REGS'
...
internal compiler error: in spill_failure, at reload1.c:2120

It's related to:
-O1 -fgcse -finline-small-functions -flto

If I remove anything from these, problem is gone.

This happens when linking final result. I'm not able to reduce reproducer right now.

This is definitely a bug; likely it's related to PR50925 but I don't know definitely.

And from http://gcc.gnu.org/bugs/#need I don't get what the policy is to report LTO-only bugs. Maybe you find the time and ask at gcc-help@gcc.gnu.org how to proceed in such a case.

Maybe your problem will go away when PR50925 is fixed. Dunno if someone is cuurently working on that PR. For me it's too complicated.

avrfreaks does not support Opera. Profile inactive.

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

Quote:
If you want to factor out PR34734 from some older avr-g++, you can
#ifdef __cplusplus
#define PROGMEM __attribute__((section (".progmem.data")))
#else
#define PROGMEM __attribute__((__progmem__))
#endif
...

Is there any reason for that ifdef __cplusplus? Why not use just the first progmem definition?

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

mihlit wrote:
Quote:
If you want to factor out PR34734 from some older avr-g++, you can
#ifdef __cplusplus
#define PROGMEM __attribute__ ((section (".progmem.data")))
#else
#define PROGMEM __attribute__((__progmem__))
#endif

Is there any reason for that ifdef __cplusplus?
As I wrote, some versions of avr-g++ have PR34734 open.

In newer version of the compiler, progmem adds additional checking and semantics to the definition:

  • Ensure only read-only data is put into flash
  • -fdata-sections take effect with progmem definitions
  • -fmerge-constants take effect with progmem definitions
  • The compiler knows how to extend symbol references to progmem to __memx pointers

avrfreaks does not support Opera. Profile inactive.

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

OK, thanks for the info. I'll probably combine that with defines checks clawson has suggested:
#define __GNUC_PATCHLEVEL__ 3
#define __GNUC__ 4
#define __GNUC_MINOR__ 3

Btw, I was able to reproduce that new regression when putting all sources in one file and then reduce it significantly. Regression is filed as:
http://gcc.gnu.org/bugzilla/show...

Pages