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)
|
#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/elf/elf-provider.h"
|
||||||
#include "backends/plugins/dynamic-plugin.h"
|
#include "backends/plugins/dynamic-plugin.h"
|
||||||
|
|
||||||
|
#include "common/debug.h"
|
||||||
#include "common/fs.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) {
|
DynamicPlugin::VoidFunc ELFPlugin::findSymbol(const char *symbol) {
|
||||||
void *func = 0;
|
void *func = 0;
|
||||||
|
|
||||||
|
@ -71,6 +112,14 @@ bool ELFPlugin::loadPlugin() {
|
||||||
|
|
||||||
bool ret = DynamicPlugin::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();
|
_dlHandle->discard_symtab();
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -80,6 +129,14 @@ void ELFPlugin::unloadPlugin() {
|
||||||
DynamicPlugin::unloadPlugin();
|
DynamicPlugin::unloadPlugin();
|
||||||
|
|
||||||
if (_dlHandle) {
|
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())
|
if (!_dlHandle->close())
|
||||||
warning("elfloader: Failed unloading plugin '%s'", _filename.c_str());
|
warning("elfloader: Failed unloading plugin '%s'", _filename.c_str());
|
||||||
|
|
||||||
|
|
|
@ -45,13 +45,15 @@ class ELFPlugin : public DynamicPlugin {
|
||||||
protected:
|
protected:
|
||||||
DLObject *_dlHandle;
|
DLObject *_dlHandle;
|
||||||
Common::String _filename;
|
Common::String _filename;
|
||||||
|
void *_dso_handle;
|
||||||
|
|
||||||
virtual VoidFunc findSymbol(const char *symbol);
|
virtual VoidFunc findSymbol(const char *symbol);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ELFPlugin(const Common::String &filename) :
|
ELFPlugin(const Common::String &filename) :
|
||||||
_dlHandle(0),
|
_dlHandle(0),
|
||||||
_filename(filename) {
|
_filename(filename),
|
||||||
|
_dso_handle(0) {
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~ELFPlugin() {
|
virtual ~ELFPlugin() {
|
||||||
|
|
|
@ -90,6 +90,13 @@ extern int pluginTypeVersions[PLUGIN_TYPE_MAX];
|
||||||
#define PLUGIN_ENABLED_DYNAMIC(ID) \
|
#define PLUGIN_ENABLED_DYNAMIC(ID) \
|
||||||
(ENABLE_##ID && (ENABLE_##ID == DYNAMIC_PLUGIN) && DYNAMIC_MODULES)
|
(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
|
* REGISTER_PLUGIN_STATIC is a convenience macro which is used to declare
|
||||||
* the plugin interface for static plugins. Code (such as game engines)
|
* 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) \
|
#define REGISTER_PLUGIN_DYNAMIC(ID,TYPE,PLUGINCLASS) \
|
||||||
extern "C" { \
|
extern "C" { \
|
||||||
|
PLUGIN_DYNAMIC_EXTRA_DECL; \
|
||||||
PLUGIN_EXPORT int32 PLUGIN_getVersion() { return PLUGIN_VERSION; } \
|
PLUGIN_EXPORT int32 PLUGIN_getVersion() { return PLUGIN_VERSION; } \
|
||||||
PLUGIN_EXPORT int32 PLUGIN_getType() { return TYPE; } \
|
PLUGIN_EXPORT int32 PLUGIN_getType() { return TYPE; } \
|
||||||
PLUGIN_EXPORT int32 PLUGIN_getTypeVersion() { return TYPE##_VERSION; } \
|
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 -isystem $DEVKITPRO/libnds/include -isystem $DEVKITPRO/devkitARM/arm-eabi/include"
|
||||||
CXXFLAGS="$CXXFLAGS -mcpu=arm9tdmi -mtune=arm9tdmi -fomit-frame-pointer -mthumb-interwork"
|
CXXFLAGS="$CXXFLAGS -mcpu=arm9tdmi -mtune=arm9tdmi -fomit-frame-pointer -mthumb-interwork"
|
||||||
CXXFLAGS="$CXXFLAGS -ffunction-sections -fdata-sections -fno-strict-aliasing"
|
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"
|
LDFLAGS="$LDFLAGS -specs=ds_arm9.specs -mthumb-interwork -mno-fpu -Wl,-Map,map.txt"
|
||||||
if test "$_dynamic_modules" = no ; then
|
if test "$_dynamic_modules" = no ; then
|
||||||
LDFLAGS="$LDFLAGS -Wl,--gc-sections"
|
LDFLAGS="$LDFLAGS -Wl,--gc-sections"
|
||||||
|
@ -1495,6 +1496,7 @@ case $_host_os in
|
||||||
;;
|
;;
|
||||||
psp)
|
psp)
|
||||||
CXXFLAGS="$CXXFLAGS -O3 -I$PSPSDK/include -D_PSP_FW_VERSION=150"
|
CXXFLAGS="$CXXFLAGS -O3 -I$PSPSDK/include -D_PSP_FW_VERSION=150"
|
||||||
|
CXXFLAGS="$CXXFLAGS -fuse-cxa-atexit"
|
||||||
;;
|
;;
|
||||||
solaris*)
|
solaris*)
|
||||||
DEFINES="$DEFINES -DSOLARIS -DSYSTEM_NOT_SUPPORTING_D_TYPE"
|
DEFINES="$DEFINES -DSOLARIS -DSYSTEM_NOT_SUPPORTING_D_TYPE"
|
||||||
|
@ -1505,6 +1507,7 @@ case $_host_os in
|
||||||
wii)
|
wii)
|
||||||
CXXFLAGS="$CXXFLAGS -Os -mrvl -mcpu=750 -meabi -mhard-float"
|
CXXFLAGS="$CXXFLAGS -Os -mrvl -mcpu=750 -meabi -mhard-float"
|
||||||
CXXFLAGS="$CXXFLAGS -ffunction-sections -fdata-sections -fmodulo-sched"
|
CXXFLAGS="$CXXFLAGS -ffunction-sections -fdata-sections -fmodulo-sched"
|
||||||
|
CXXFLAGS="$CXXFLAGS -fuse-cxa-atexit"
|
||||||
CXXFLAGS="$CXXFLAGS -I$DEVKITPRO/libogc/include"
|
CXXFLAGS="$CXXFLAGS -I$DEVKITPRO/libogc/include"
|
||||||
# libogc is required to link the cc tests (includes _start())
|
# libogc is required to link the cc tests (includes _start())
|
||||||
LDFLAGS="$LDFLAGS -mrvl -mcpu=750 -L$DEVKITPRO/libogc/lib/wii -logc"
|
LDFLAGS="$LDFLAGS -mrvl -mcpu=750 -L$DEVKITPRO/libogc/lib/wii -logc"
|
||||||
|
@ -2004,7 +2007,7 @@ POST_OBJS_FLAGS := -Wl,--no-whole-archive
|
||||||
'
|
'
|
||||||
;;
|
;;
|
||||||
ds)
|
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='
|
_def_plugin='
|
||||||
#define PLUGIN_PREFIX ""
|
#define PLUGIN_PREFIX ""
|
||||||
#define PLUGIN_SUFFIX ".plg"
|
#define PLUGIN_SUFFIX ".plg"
|
||||||
|
@ -2015,7 +2018,7 @@ PLUGIN_PREFIX :=
|
||||||
PLUGIN_SUFFIX := .plg
|
PLUGIN_SUFFIX := .plg
|
||||||
PLUGIN_EXTRA_DEPS = $(EXECUTABLE)
|
PLUGIN_EXTRA_DEPS = $(EXECUTABLE)
|
||||||
CXXFLAGS += -DDYNAMIC_MODULES
|
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
|
PRE_OBJS_FLAGS := -Wl,--whole-archive
|
||||||
POST_OBJS_FLAGS := -Wl,--no-whole-archive
|
POST_OBJS_FLAGS := -Wl,--no-whole-archive
|
||||||
'
|
'
|
||||||
|
@ -2038,7 +2041,7 @@ POST_OBJS_FLAGS := -Wl,-no-whole-archive
|
||||||
'
|
'
|
||||||
;;
|
;;
|
||||||
gamecube | wii)
|
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='
|
_def_plugin='
|
||||||
#define PLUGIN_PREFIX ""
|
#define PLUGIN_PREFIX ""
|
||||||
#define PLUGIN_SUFFIX ".plg"
|
#define PLUGIN_SUFFIX ".plg"
|
||||||
|
@ -2108,7 +2111,7 @@ POST_OBJS_FLAGS := -Wl,--no-whole-archive
|
||||||
'
|
'
|
||||||
;;
|
;;
|
||||||
psp)
|
psp)
|
||||||
DEFINES="$DEFINES -DELF_LOADER_TARGET -DMIPS_TARGET"
|
DEFINES="$DEFINES -DELF_LOADER_TARGET -DMIPS_TARGET -DELF_LOADER_CXA_ATEXIT"
|
||||||
_def_plugin='
|
_def_plugin='
|
||||||
#define PLUGIN_PREFIX ""
|
#define PLUGIN_PREFIX ""
|
||||||
#define PLUGIN_SUFFIX ".plg"
|
#define PLUGIN_SUFFIX ".plg"
|
||||||
|
@ -2120,7 +2123,7 @@ PLUGIN_SUFFIX := .plg
|
||||||
PLUGIN_EXTRA_DEPS = $(EXECUTABLE)
|
PLUGIN_EXTRA_DEPS = $(EXECUTABLE)
|
||||||
CXXFLAGS += -DDYNAMIC_MODULES
|
CXXFLAGS += -DDYNAMIC_MODULES
|
||||||
LDFLAGS += -Wl,-T$(srcdir)/backends/platform/psp/main_prog.ld
|
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
|
PRE_OBJS_FLAGS := -Wl,--whole-archive
|
||||||
POST_OBJS_FLAGS := -Wl,--no-whole-archive
|
POST_OBJS_FLAGS := -Wl,--no-whole-archive
|
||||||
'
|
'
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue