https://gcc.gnu.org/bugzilla/show_bug.cgi?id=107500
Bug ID: 107500
Summary: Useless atexit entry for ~constant_init in
eh_globals.cc
Product: gcc
Version: 12.2.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: c++
Assignee: unassigned at gcc dot gnu.org
Reporter: rdiezmail-gcc at yahoo dot de
Target Milestone: ---
I have this embedded firmware project of mine, which uses Newlib:
https://github.com/rdiez/DebugDue
It is the template for other similar bare-metal projects I have. Even though
some targets have very little SRAM (like 16 KiB), I am still using C++ and
exceptions. The project above documents how I configure GCC to that effect.
Up until GCC 11.2, I have been doing this check:
if ( _GLOBAL_ATEXIT != nullptr )
{
Panic( "Unexpected entries in atexit table." );
}
On devices with very little RAM and without an operating system, initialisation
and destruction can be tricky. With the check above, I am making sure that
nothing unexpected comes up in that respect. I am initialising all static
objects manually anyway, to prevent any ordering surprises (the initialisation
order of C++ static objects can be problematic too).
The check above fails with GCC 12.2. Apparently, a destructor called
constant_init::~constant_init() gets added to the atexit table on start-up.
Because of the way that Newlib works, that wastes 400 bytes of SRAM, which
corresponds to sizeof( _global_atexit0 ). The structure has room for 32 atexit
calls (because of some ANSI conformance), but we are only using 1 entry.
The interesting thing is that the destructor is supposed to be empty, see:
https://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/libsupc%2B%2B/eh_globals.cc
~constant_init() { /* do nothing, union member is not destroyed */ }
GCC generates the following code for that empty destructor:
0008da68 <(anonymous namespace)::constant_init::~constant_init()>:
8da68: b580 push {r7, lr}
8da6a: af00 add r7, sp, #0
8da6c: bd80 pop {r7, pc}
That does not make any sense. Is there a way to prevent GCC from registering
such an empty atexit function? Failing that, is there a way to prevent GCC from
registering a particular atexit function, even if it is not empty?
I find surprising that GCC emits such code. My project is building its own
GCC/Newlib toolchain with optimisation level "-Os", so I would expect at least
the "add r7, sp, #0" to be optimised away.