Open hlovdal opened 5 years ago
I tried to create a wrapper for all the binaries containing the string merge-constants
and rename and symlink the wrapper,
#!/bin/sh
exec $0.real "$@" -fno-merge-constants -fno-merge-all-constants -O0
but it did not help (only triggering a warning from <util/delay.h>
that it was not happy with optimizations disabled).
Please give it a try using the beta test version of the upcoming Arduino AVR Boards toolchain, which uses avr-gcc 7.3.0:
Using the sketch you provided with Arduino AVR Boards 1.6.23 (avr-gcc 5.4.0), I also get an incorrect value for days
printed to the Serial Monitor. When I use Arduino AVR Boards 1.6.209, I get the expected value of 31
.
Can we use the following code as a shorter and less convoluted demonstration of the issue?
const uint8_t numbers[] = {1, 2, 3, 4, 5};
const uint8_t progmemNumbers[] PROGMEM = {1, 2, 3, 4, 5};
void setup() {
Serial.begin(9600);
Serial.print("numbers: ");
for (uint8_t i = 0; i < sizeof(numbers); i++) {
Serial.print(numbers[i]);
}
Serial.println();
Serial.print("progmemNumbers: ");
for (uint8_t i = 0; i < sizeof(progmemNumbers); i++) {
Serial.print(pgm_read_byte(&progmemNumbers[i]));
}
}
void loop() {}
Result with Arduino AVR Boards 1.6.23:
numbers: 12345
progmemNumbers: 1459143115153
Result with Arduino AVR Boards 1.6.209:
numbers: 12345
progmemNumbers: 12345
Thanks, yes updating to AVR boards 1.6.209 makes the problem go away.
Problem still exists in gcc 7.3.0. https://github.com/arduino/Arduino/issues/9835 Workaround is adding -fno-ipa-icf-variables.
I initially intended to have the title "g++ incorrectly merges PROGMEM and non-PROGMEM data", but opted to focus on the consequences since I think this is a really bad show stopper bug.
The TL;DR version is that because library file
RTClib.cpp
contains (usingPROGMEM
)and library file
Time.cpp
contains (not usingPROGMEM
)the compiler incorrectly merges them, but due to the micro-controller's modified Harvard architecture they are stored in different memory types and cannot be accessed the same way. Attempts to read one of them will result in garbage data.
Initially I debugged the problem by adding some
Serial.print
toTime.cpp
andRTClib.cpp
and discovered that inTime.cpp
the number of days in a month were garbage values comming from itsmonthDays
array.I managed to reproduce similar behaviour in a standalone sketch, without requiering modifications of libraries.
When compiled it produces warning
but I do not understand why it does not also complain about
month_days1/2
andprimes1/2
, they should have the same issue.Initially I thought that this might have something to do with the actual access to the variable through the specific assembly instruction (hence also inlining the macro just to see if it made any difference (which it did not)), but it turns out that with the
#if
s disabled the variable is just optimized away. Just referencing the variable likewill keep it in the translation unit and produce the same issue. Running the above code on an Arduino Uno gives the following, notice the garbage value for
days
below:I guess this problem is related to https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80462.
I have tested compiling and flashing both with Arduino studio 1.8.8 & nightly (and with vscode, although it is just reusing the toolchain from the Arduino IDE). I have tested on two different computers. And I have tested with two different arduino boards.
The nightly build also uses 5.4.0-atmel3.6.1-arduino2, so no difference.