Just as a note, there's no need to link with libstdc++; it has a tendency to pull in undesirable bits and pieces. The following stubs out the runtime support needed for g++. (libstdc++ uses atexit() to register exit-time destructors, something not even remotely desirable in embedded systems.)
// ABI stuff (both ELF and EABI stubs, for simplicity, though only one is needed)
extern "C" {
#undef abort
void abort() { panic("ABORT"); }
int __cxa_atexit(void (*func) (void*), void* arg, void* dso_handle);
int __cxa_pure_virtual();
int __aeabi_atexit (void *object, void (*destructor) (void *), void *dso_handle);
}
int __cxa_atexit(void (*func) (void*), void* arg, void* dso_handle)
{
return 0;
}
int __aeabi_atexit (void *object, void (*destructor) (void *), void *dso_handle)
{
return 0;
}
int __cxa_pure_virtual() { abort(); return 0; }
void* __dso_handle = (void*) &__dso_handle;
And, if using a custom startup, make sure to run initializers:
// Call from startup.S with:
// bl _Z10init_arrayv
// Somewhere else define:
// #define __weak gnu::weak for gcc
// For other compilers use other attributes if available, or an empty definition and make the symbols weak in the link script.
[[__weak]] extern void (*__preinit_array_start []) (void);
[[__weak]] extern void (*__preinit_array_end []) (void);
[[__weak]] extern void (*__init_array_start []) (void);
[[__weak]] extern void (*__init_array_end []) (void);
void init_array() {
size_t count, i;
count = __preinit_array_end - __preinit_array_start;
for (i = 0; i < count; i++)
__preinit_array_start[i]();
count = __init_array_end - __init_array_start;
for (i = 0; i < count; i++)
__init_array_start[i]();
}
The symbols __init_array_start etc need to match the linker script. init_array needs to be called from the startup code.
This removes all dependencies on standard libraries other than libgcc.a; but libgcc is a hard dependency, for arithmetic ops, floating point, and such.