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:
parent
c2cafe426e
commit
ae408db07f
4 changed files with 76 additions and 6 deletions
|
@ -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());
|
||||
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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
13
configure
vendored
|
@ -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
|
||||
'
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue