I have a project which is compiled at the O2 optimization level with GCC, but I occasionally put __attribute__((optimize("O0")))
before a function definition so that it's easier to step through during on-chip debugging.
This usually goes off without a hitch, but I'm getting undefined reference errors with the following code:
SomeClass.h
#include "SomeOtherClass.h"
#include <memory>
class SomeClass
{
public:
static constexpr unsigned char MAGIC_NUMBER = 42;
void foo();
std::unique_ptr<SomeOtherClass> someOtherClass;
};
SomeClass.cpp
#include "SomeClass.h"
void __attribute__((optimize("O0"))) SomeClass::foo()
{
someOtherClass = std::make_unique<SomeOtherClass>(MAGIC_NUMBER);
}
The error seems to indicate that when linking SomeClass.cpp, the linker is looking for a reference in the .rdata section for the constant:
./src/SomeClass.o:SomeClass.cpp:(.rdata$.refptr._ZN9SomeClass9MAGIC_NUMBERE[.refptr._ZN9SomeClass9MAGIC_NUMBERE]+0x0): undefined reference to `SomeClass::MAGIC_NUMBER'
Removing __attribute__((optimize("O0")))
from the method definition does eliminate the error, all else being equal.
In addition, changing someOtherClass from unique_ptr to raw pointer and using a bare new expression instead of make_unique eliminates the error. Similarly, using MAGIC_NUMBER as an argument to printf within foo() isn't sufficient to cause the error.
What I assume is occurring is that when GCC compiles foo() at O0, something about the weird argument forwarding in make_unique prevents it from figuring out that it's allowed to replace the reference to MAGIC_NUMBER with immediate data, so it retains the reference. But the class's static initializer is compiled at O2, and assumes that the constant can be eliminated from .rdata because all references to the constant elsewhere will also be compiled at O2 and will be transformed into immediate data. And when foo() is compiled at O2, GCC is able to figure out that it can replace the reference to MAGIC_DATA with immediate data, so there's no issue.
My question is, how do I tell GCC that it needs to preserve this constant because a class method will be compiled at O0? I tried putting __attribute__((optimize("O0")))
on the class declaration, the method declaration, and the constant's declaration-definition, but in all three cases got errors, or warnings that the optimize attribute is being ignored. I'm assuming there is some other GCC directive meant for this exact situation, but I've been unable to find it.
Or, if no such directive exists and GCC is meant to handle this situation automatically, is this a GCC bug I should report?
Compiling the entire program at O0 for debugging is unfortunately not a solution, as some parts of this program require certain features of optimization level O2/O3 to function correctly.