Actually, you can. I've run C++ bare metal (two different bare
metal hypervisors and a massively parallel distributed Unix-like
microkernel based operating system), no RTL and a handful
of lines to support compiler generated symbols and a few lines of
assembler to start it up. A page based allocator and a generic
pool class suffices to support dynamic allocation (via overloaded
'new'/'delete'). Of course, no exceptions or RTTI.
//
// C++ Support functions
//
/*
* Symbols defined in the linker script to mark the ctor list.
*/
extern void (*__CTOR_LIST__[])();
#include "dvmm.h"
#include "util/support.h"
/*
* This is called by setup64.S to call the constructors of global objects,
* before it calls dvmm_bsp_start().
*
* GNU LD lays out the __CTOR_LIST__ as an array of function pointers. The
* first element of the array (index == 0) contains an integer which
* represents the value derived from subtracting two from the actual number
* of entries in the table. Thus the content of the first element is
* one less than the index of the last entry in the table.
*
* Call in reverse order XXX - why? Check crt0.o for canonical behavior
*/
extern "C" void
__call_constructors()
{
size_t count = *(size_t *)__CTOR_LIST__;
for(count++; count; --count) {
__CTOR_LIST__[count]();
}
}
/*
* G++'s generated code calls this if a pure virtual member is ever called.
*/
extern "C" void
__cxa_pure_virtual()
{
panic("pure virtual function called\n");
}
/*
* This is needed even though we don't ever use the delete operator because
* G++ generates an extra (unused) virtual destructor that calls it.
*/
void
operator delete(void *)
{
panic("operator delete(void*) called\n");
}
/*
* Catch unintended calls to new.
*/
void*
operator new(size_t)
{
panic("operator new(void*) called\n");
}
/*
* G++ generates code for shared library support, even though it isn't
* relevant (or called). That code looks for this symbol.
*/
void *__dso_handle;
/*
* Global object constructors call this to register their corresponding
* destructor. We just ignore it; we never call global object destructors
* because we never exit.
*/
extern "C" int
__cxa_atexit(void (*f)(void *), void *p, void *d)
{
return 0;
}