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() {