PLUGINS: Use the C++ ABI to call dtors when unloading a plugin.

Avoid linking all plugins against libstdc++ to free up some memory
(about ~40kb on Wii per plugin). Enable it on GameCube, Wii, DS and PSP
(PS2 doesn't have __cxa_atexit support in its libc).

svn-id: r52607
This commit is contained in:
Andre Heider 2010-09-06 20:34:00 +00:00
parent c2cafe426e
commit ae408db07f
4 changed files with 76 additions and 6 deletions

View file

@ -25,11 +25,52 @@
#if defined(DYNAMIC_MODULES) && defined(ELF_LOADER_TARGET)
#ifdef ELF_LOADER_CXA_ATEXIT
#include <cxxabi.h>
#endif
#include "backends/plugins/elf/elf-provider.h"
#include "backends/plugins/dynamic-plugin.h"
#include "common/debug.h"
#include "common/fs.h"
/* Note about ELF_LOADER_CXA_ATEXIT:
*
* consider the code:
*
* class Foobar {
* const char *work() {
* static String foo = "bar";
* return s.c_str();
* }
* }
*
* When instantiating Foobar and calling work() for the first time the String
* foo will be constructed. GCC automatically registers its destruction via
* either atexit() or __cxa_atexit(). Only the latter will add information
* about which DSO did the construction (Using &__dso_handle).
*
* __cxa_atexit allows plugins to reference C++ ABI symbols in the main
* executable without code duplication (No need to link the plugin against
* libstdc++), since we can distinguish which registered exit functions belong
* to a specific DSO. When unloading a plugin, we just use the C++ ABI call
* __cxa_finalize(&__dso_handle) to call all destructors of only that DSO.
*
* Prerequisites:
* - The used libc needs to support __cxa_atexit
* - -fuse-cxa-atexit in CXXFLAGS
* - Every plugin needs its own hidden __dso_handle symbol
* This is automatically done via REGISTER_PLUGIN_DYNAMIC, see base/plugins.h
*
* When __cxa_atexit can not be used, each plugin needs to link against
* libstdc++ to embed its own set of C++ ABI symbols. When not doing so,
* registered destructors of already unloaded plugins will crash the
* application upon returning from main().
*
* See "3.3.5 DSO Object Destruction API" of the C++ ABI
*/
DynamicPlugin::VoidFunc ELFPlugin::findSymbol(const char *symbol) {
void *func = 0;
@ -71,6 +112,14 @@ bool ELFPlugin::loadPlugin() {
bool ret = DynamicPlugin::loadPlugin();
#ifdef ELF_LOADER_CXA_ATEXIT
// FIXME HACK: Reverse HACK of findSymbol() :P
VoidFunc tmp;
tmp = findSymbol("__dso_handle");
memcpy(&_dso_handle, &tmp, sizeof(VoidFunc));
debug(2, "elfloader: __dso_handle is %p", _dso_handle);
#endif
_dlHandle->discard_symtab();
return ret;
@ -80,6 +129,14 @@ void ELFPlugin::unloadPlugin() {
DynamicPlugin::unloadPlugin();
if (_dlHandle) {
#ifdef ELF_LOADER_CXA_ATEXIT
if (_dso_handle) {
debug(2, "elfloader: calling __cxa_finalize");
__cxxabiv1::__cxa_finalize(_dso_handle);
_dso_handle = 0;
}
#endif
if (!_dlHandle->close())
warning("elfloader: Failed unloading plugin '%s'", _filename.c_str());

View file

@ -45,13 +45,15 @@ class ELFPlugin : public DynamicPlugin {
protected:
DLObject *_dlHandle;
Common::String _filename;
void *_dso_handle;
virtual VoidFunc findSymbol(const char *symbol);
public:
ELFPlugin(const Common::String &filename) :
_dlHandle(0),
_filename(filename) {
_filename(filename),
_dso_handle(0) {
}
virtual ~ELFPlugin() {

View file

@ -90,6 +90,13 @@ extern int pluginTypeVersions[PLUGIN_TYPE_MAX];
#define PLUGIN_ENABLED_DYNAMIC(ID) \
(ENABLE_##ID && (ENABLE_##ID == DYNAMIC_PLUGIN) && DYNAMIC_MODULES)
// see comments in backends/plugins/elf/elf-provider.cpp
#if defined(ELF_LOADER_TARGET) && defined(ELF_LOADER_CXA_ATEXIT)
#define PLUGIN_DYNAMIC_EXTRA_DECL uint32 __dso_handle __attribute__((visibility ("hidden"))) = 0
#else
#define PLUGIN_DYNAMIC_EXTRA_DECL
#endif
/**
* REGISTER_PLUGIN_STATIC is a convenience macro which is used to declare
* the plugin interface for static plugins. Code (such as game engines)
@ -119,6 +126,7 @@ extern int pluginTypeVersions[PLUGIN_TYPE_MAX];
*/
#define REGISTER_PLUGIN_DYNAMIC(ID,TYPE,PLUGINCLASS) \
extern "C" { \
PLUGIN_DYNAMIC_EXTRA_DECL; \
PLUGIN_EXPORT int32 PLUGIN_getVersion() { return PLUGIN_VERSION; } \
PLUGIN_EXPORT int32 PLUGIN_getType() { return TYPE; } \
PLUGIN_EXPORT int32 PLUGIN_getTypeVersion() { return TYPE##_VERSION; } \

13
configure vendored
View file

@ -1424,6 +1424,7 @@ case $_host_os in
CXXFLAGS="$CXXFLAGS -isystem $DEVKITPRO/libnds/include -isystem $DEVKITPRO/devkitARM/arm-eabi/include"
CXXFLAGS="$CXXFLAGS -mcpu=arm9tdmi -mtune=arm9tdmi -fomit-frame-pointer -mthumb-interwork"
CXXFLAGS="$CXXFLAGS -ffunction-sections -fdata-sections -fno-strict-aliasing"
CXXFLAGS="$CXXFLAGS -fuse-cxa-atexit"
LDFLAGS="$LDFLAGS -specs=ds_arm9.specs -mthumb-interwork -mno-fpu -Wl,-Map,map.txt"
if test "$_dynamic_modules" = no ; then
LDFLAGS="$LDFLAGS -Wl,--gc-sections"
@ -1495,6 +1496,7 @@ case $_host_os in
;;
psp)
CXXFLAGS="$CXXFLAGS -O3 -I$PSPSDK/include -D_PSP_FW_VERSION=150"
CXXFLAGS="$CXXFLAGS -fuse-cxa-atexit"
;;
solaris*)
DEFINES="$DEFINES -DSOLARIS -DSYSTEM_NOT_SUPPORTING_D_TYPE"
@ -1505,6 +1507,7 @@ case $_host_os in
wii)
CXXFLAGS="$CXXFLAGS -Os -mrvl -mcpu=750 -meabi -mhard-float"
CXXFLAGS="$CXXFLAGS -ffunction-sections -fdata-sections -fmodulo-sched"
CXXFLAGS="$CXXFLAGS -fuse-cxa-atexit"
CXXFLAGS="$CXXFLAGS -I$DEVKITPRO/libogc/include"
# libogc is required to link the cc tests (includes _start())
LDFLAGS="$LDFLAGS -mrvl -mcpu=750 -L$DEVKITPRO/libogc/lib/wii -logc"
@ -2004,7 +2007,7 @@ POST_OBJS_FLAGS := -Wl,--no-whole-archive
'
;;
ds)
DEFINES="$DEFINES -DELF_LOADER_TARGET -DONE_PLUGIN_AT_A_TIME"
DEFINES="$DEFINES -DELF_LOADER_TARGET -DELF_LOADER_CXA_ATEXIT -DONE_PLUGIN_AT_A_TIME"
_def_plugin='
#define PLUGIN_PREFIX ""
#define PLUGIN_SUFFIX ".plg"
@ -2015,7 +2018,7 @@ PLUGIN_PREFIX :=
PLUGIN_SUFFIX := .plg
PLUGIN_EXTRA_DEPS = $(EXECUTABLE)
CXXFLAGS += -DDYNAMIC_MODULES
PLUGIN_LDFLAGS = -nostartfiles -Wl,-q,--just-symbols,$(EXECUTABLE),-T$(srcdir)/backends/plugins/ds/plugin.ld -lstdc++ -lc -mthumb-interwork -mno-fpu -Wl,--retain-symbols-file,$(srcdir)/backends/plugins/elf/plugin.syms
PLUGIN_LDFLAGS = -nostartfiles -Wl,-q,--just-symbols,$(EXECUTABLE),-T$(srcdir)/backends/plugins/ds/plugin.ld -mthumb-interwork -mno-fpu -Wl,--retain-symbols-file,$(srcdir)/backends/plugins/elf/plugin.syms
PRE_OBJS_FLAGS := -Wl,--whole-archive
POST_OBJS_FLAGS := -Wl,--no-whole-archive
'
@ -2038,7 +2041,7 @@ POST_OBJS_FLAGS := -Wl,-no-whole-archive
'
;;
gamecube | wii)
DEFINES="$DEFINES -DELF_LOADER_TARGET -DPPC_TARGET -DONE_PLUGIN_AT_A_TIME"
DEFINES="$DEFINES -DELF_LOADER_TARGET -DPPC_TARGET -DELF_LOADER_CXA_ATEXIT -DONE_PLUGIN_AT_A_TIME"
_def_plugin='
#define PLUGIN_PREFIX ""
#define PLUGIN_SUFFIX ".plg"
@ -2108,7 +2111,7 @@ POST_OBJS_FLAGS := -Wl,--no-whole-archive
'
;;
psp)
DEFINES="$DEFINES -DELF_LOADER_TARGET -DMIPS_TARGET"
DEFINES="$DEFINES -DELF_LOADER_TARGET -DMIPS_TARGET -DELF_LOADER_CXA_ATEXIT"
_def_plugin='
#define PLUGIN_PREFIX ""
#define PLUGIN_SUFFIX ".plg"
@ -2120,7 +2123,7 @@ PLUGIN_SUFFIX := .plg
PLUGIN_EXTRA_DEPS = $(EXECUTABLE)
CXXFLAGS += -DDYNAMIC_MODULES
LDFLAGS += -Wl,-T$(srcdir)/backends/platform/psp/main_prog.ld
PLUGIN_LDFLAGS = -nostartfiles -Wl,-q,--just-symbols,$(EXECUTABLE),--retain-symbols-file,$(srcdir)/backends/plugins/elf/plugin.syms,-T$(srcdir)/backends/plugins/psp/plugin.ld -lstdc++ -lc -lm -Wl,--wrap,memcpy
PLUGIN_LDFLAGS = -nostartfiles -Wl,-q,--just-symbols,$(EXECUTABLE),--retain-symbols-file,$(srcdir)/backends/plugins/elf/plugin.syms,-T$(srcdir)/backends/plugins/psp/plugin.ld -lc -Wl,--wrap,memcpy
PRE_OBJS_FLAGS := -Wl,--whole-archive
POST_OBJS_FLAGS := -Wl,--no-whole-archive
'