diff options
author | Andre Heider | 2010-09-06 20:34:00 +0000 |
---|---|---|
committer | Andre Heider | 2010-09-06 20:34:00 +0000 |
commit | ae408db07f05407c41ed4831e4e23991574588d6 (patch) | |
tree | e12b3d57b671c1d2c437e788059036fde3aea66f /backends/plugins/elf | |
parent | c2cafe426e8216d46a70b479ff0071a8b66b9327 (diff) | |
download | scummvm-rg350-ae408db07f05407c41ed4831e4e23991574588d6.tar.gz scummvm-rg350-ae408db07f05407c41ed4831e4e23991574588d6.tar.bz2 scummvm-rg350-ae408db07f05407c41ed4831e4e23991574588d6.zip |
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
Diffstat (limited to 'backends/plugins/elf')
-rw-r--r-- | backends/plugins/elf/elf-provider.cpp | 57 | ||||
-rw-r--r-- | backends/plugins/elf/elf-provider.h | 4 |
2 files changed, 60 insertions, 1 deletions
diff --git a/backends/plugins/elf/elf-provider.cpp b/backends/plugins/elf/elf-provider.cpp index 7bb39d4347..f3f6bace07 100644 --- a/backends/plugins/elf/elf-provider.cpp +++ b/backends/plugins/elf/elf-provider.cpp @@ -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()); diff --git a/backends/plugins/elf/elf-provider.h b/backends/plugins/elf/elf-provider.h index 5dc61539e1..6918183f1f 100644 --- a/backends/plugins/elf/elf-provider.h +++ b/backends/plugins/elf/elf-provider.h @@ -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() { |