avr-gcc -Os removes exported arrays from PROGMEM!

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

I'm using AVR-GCC 4.7.0-1 from Arch Linux, if it matters.

When compiling with -Os (which is pretty much a must for most source code,) an exported data array declared as PROGMEM will be removed by the compiler!

Compare without -Os:

$ avr-gcc -mmcu=atmega328p -c foo.cpp -o foo.o && avr-objdump -s foo.o

foo.o:     file format elf32-avr

Contents of section .progmem.data:
 0000 666f6f00                             foo.            
Contents of section .comment:
 0000 00474343 3a202847 4e552920 342e372e  .GCC: (GNU) 4.7.
 0010 3000                                 0.              

to with -Os:

$ avr-gcc -Os -mmcu=atmega328p -c foo.cpp -o foo.o && avr-objdump -s foo.o

foo.o:     file format elf32-avr

Contents of section .comment:
 0000 00474343 3a202847 4e552920 342e372e  .GCC: (GNU) 4.7.
 0010 3000                                 0.              

Here is foo.cpp:

#include 

unsigned char const foo[4] PROGMEM = { 'f', 'o', 'o', 0 };

Must I add some magic GNU make hack to my makefiles to not pass -Os for these files? That's fairly cumbersome :-(
Is this a known bug? Is there a patch?

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

> Must I add some magic GNU make hack to my makefiles to
> not pass -Os for these files?

No.

> That's fairly cumbersome

No. There is an unused, local variable that is optimized away. If you never use the variable, you won't even notice it has gone.

> Is this a known bug?

It's not a bug, it's a feature called optimization.

> Is there a patch?

Yes, you can apply this patch:

diff --git a/foo.cpp b/foo.cpp
index 98654f3..d88ba66 100644
--- a/foo.cpp
+++ b/foo.cpp
@@ -1,3 +1,3 @@
 #include  
 
-unsigned char const foo[4] PROGMEM = { 'f', 'o', 'o', 0 };
+extern unsigned char const foo[4] PROGMEM = { 'f', 'o', 'o', 0 };

That patch should also work:

diff --git a/foo.cpp b/foo.cpp
index 98654f3..3e6669e 100644
--- a/foo.cpp
+++ b/foo.cpp
@@ -1,3 +1,4 @@
 #include  
 
+extern unsigned char const foo[4] PROGMEM;
 unsigned char const foo[4] PROGMEM = { 'f', 'o', 'o', 0 };

avrfreaks does not support Opera. Profile inactive.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
unsigned char const foo[4] PROGMEM = { 'f', 'o', 'o', 0 };

It is offtopic, but...
You can use string literals as initializer for fixed-width arrays.

unsigned char const foo[4] PROGMEM = "foo"; // trailing zero present in array, the same as initial statement
unsigned char const foo[3] PROGMEM = "foo"; // valid, identical to { 'f', 'o', 'o' }
unsigned char const foo[6] PROGMEM = "foo"; // valid, identical to { 'f', 'o', 'o', 0, 0, 0 }

unsigned char const foo[2] PROGMEM = "foo"; // warning: initializer-string for array of chars is too long
                                            // result identical to { 'f', 'o' }

wbr, ReAl

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

Quote:
No. There is an unused, local variable that is optimized away. If you never use the variable, you won't even notice it has gone.

It is not local. According to the standard, it has "vague" linkage, which is the same as, say, inline expanded templates. Without the -Os option, it clearly has global scope, and the documentation for -Os does not say that it changes the semantics of the program.

Having the linkage success of a separately compiled program change based on the "-Os" setting is, in my opinion, not very useful. I think symbol use for externally visible symbols should be determined by the linker, not the compiler, and it certainly would be both useful and standards-conformant behavior to do so.

I'm sure you can come up with language lawyering to argue that the current behavior is language conformant -- and you can also come up with an argument that it isn't. I'm not going to enter into that discussion more than I did here, though. The work-around you suggest -- add "extern" to the definition -- fixes this behavior.

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

jwatte wrote:
Quote:
No. There is an unused, local variable that is optimized away. If you never use the variable, you won't even notice it has gone.
It is not local. According to the standard, it has "vague" linkage, ...

7.1.1 Storage Class Specifiers, Clause 6 wrote:
Objects declared const and not explicitly declared extern have internal linkage.

avrfreaks does not support Opera. Profile inactive.