[Scummvm-git-logs] scummvm master -> 3a6a355c20c12f77a57cd85a278c36c9efb45254

mikrosk noreply at scummvm.org
Sun Apr 26 16:05:40 UTC 2026


This automated email contains information about 4 new commits which have been
pushed to the 'scummvm' repo located at https://api.github.com/repos/scummvm/scummvm .

Summary:
e09b9dfad6 PLUGINS: Provide __cxa_atexit & __cxa_finalize
83ebddc748 BACKENDS: ATARI: Implement plugins
b02c2de70f BACKENDS: ATARI: Match other platforms' plugin.ld ctors/dtors layout
3a6a355c20 BACKENDS: SDL: Add plugins support for Atari/FireBee


Commit: e09b9dfad6f686141120bd8ada4837459dd407bc
    https://github.com/scummvm/scummvm/commit/e09b9dfad6f686141120bd8ada4837459dd407bc
Author: Miro Kropacek (miro.kropacek at gmail.com)
Date: 2026-04-27T02:05:36+10:00

Commit Message:
PLUGINS: Provide __cxa_atexit & __cxa_finalize

Atari's mintelf platform has ELF support but its libc does not provide
__cxa_atexit / __cxa_finalize, so -fuse-cxa-atexit cannot be used out of
the box. Add a minimal shim (plus a __dso_handle definition for the main
executable) so plugins can register and finalize their function-local
static destructors per DSO on unload.

Note: earlier version ran __cxa_finalize from the host via
findSymbol("__dso_handle"). That works as long as exactly one
__dso_handle ends up in the plugin's symtab (the plugin's own).

When the main binary also defines __dso_handle (so the host's
function-local statics can link with -fuse-cxa-atexit), it breaks: the
plugin link uses --just-symbols=<main binary> and imports that as a
second __dso_handle, and findSymbol can then return the host-imported
one instead of the plugin's own. The two addresses differ, so
__cxa_finalize matches nothing.

The plugin-side helper avoids the ambiguity on every target by using
whichever __dso_handle the plugin's own code already resolved against --
the same one embedded in its __cxa_atexit calls. (PSP2's plugin runtime
has always called __cxa_finalize from inside the plugin for the same
reason; see backends/plugins/psp2/plugin.cpp.)

Changed paths:
  A backends/plugins/elf/cxa-atexit.cpp
    backends/module.mk
    backends/plugins/elf/elf-provider.cpp
    backends/plugins/elf/elf-provider.h
    backends/plugins/elf/plugin.syms
    base/plugins.h


diff --git a/backends/module.mk b/backends/module.mk
index f64a8112bcf..e6b2daa873a 100644
--- a/backends/module.mk
+++ b/backends/module.mk
@@ -170,6 +170,7 @@ endif
 ifdef USE_ELF_LOADER
 MODULE_OBJS += \
 	plugins/elf/arm-loader.o \
+	plugins/elf/cxa-atexit.o \
 	plugins/elf/elf-loader.o \
 	plugins/elf/elf-provider.o \
 	plugins/elf/memory-manager.o \
diff --git a/backends/plugins/elf/cxa-atexit.cpp b/backends/plugins/elf/cxa-atexit.cpp
new file mode 100644
index 00000000000..4865a691962
--- /dev/null
+++ b/backends/plugins/elf/cxa-atexit.cpp
@@ -0,0 +1,116 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "common/scummsys.h"
+
+#if defined(DYNAMIC_MODULES) && defined(USE_ELF_LOADER) && defined(ELF_LOADER_CXA_ATEXIT) && defined(__MINT__)
+
+#include "common/debug.h"
+#include "common/textconsole.h"
+
+#include <stdlib.h>
+
+/**
+ * Minimal __cxa_atexit / __cxa_finalize for targets whose libc lacks them
+ * (e.g. mintlib on Atari).
+ *
+ * With -fuse-cxa-atexit, GCC registers function-local static destructors via
+ * __cxa_atexit(&dtor, &obj, &__dso_handle).  The third argument tags which
+ * DSO owns the registration.  On plugin unload, ELFPlugin::unloadPlugin()
+ * calls __cxa_finalize(&plugin_dso_handle) to run and remove only that
+ * plugin's entries -- preventing dangling atexit pointers into freed memory.
+ *
+ * See also the detailed comment in elf-provider.cpp.
+ */
+
+#define CXA_ATEXIT_MAX 256
+
+struct CxaAtexitEntry {
+	void (*destructor)(void *);
+	void *arg;
+	void *dso_handle;
+};
+
+static CxaAtexitEntry s_entries[CXA_ATEXIT_MAX];
+static int s_count;
+
+extern "C" {
+
+// GCC with -fuse-cxa-atexit emits references to __dso_handle in every TU that
+// has function-local statics with non-trivial destructors. It is normally
+// provided by crtbegin.o; on targets whose startup files don't supply one,
+// define it here for the main executable. Its address uniquely identifies
+// the main DSO.
+void *__dso_handle = &__dso_handle;
+
+int __cxa_atexit(void (*destructor)(void *), void *arg, void *dso_handle) {
+	if (s_count >= CXA_ATEXIT_MAX) {
+		warning("elfloader: cxa-atexit table full (max=%d), dropping dtor %p dso=%p",
+			CXA_ATEXIT_MAX, (void *)destructor, dso_handle);
+		return -1;
+	}
+
+	s_entries[s_count].destructor = destructor;
+	s_entries[s_count].arg = arg;
+	s_entries[s_count].dso_handle = dso_handle;
+	s_count++;
+
+	debug(2, "elfloader: cxa-atexit register[%d] dtor=%p arg=%p dso=%p",
+		s_count - 1, (void *)destructor, arg, dso_handle);
+	return 0;
+}
+
+void __cxa_finalize(void *dso_handle) {
+	int ran = 0, matched = 0;
+
+	for (int i = s_count - 1; i >= 0; i--) {
+		if (s_entries[i].destructor == NULL)
+			continue;
+
+		if (dso_handle == NULL || s_entries[i].dso_handle == dso_handle) {
+			matched++;
+			void (*f)(void *) = s_entries[i].destructor;
+			void *a = s_entries[i].arg;
+			s_entries[i].destructor = NULL;  // mark before calling (re-entrancy)
+			f(a);
+			ran++;
+		}
+	}
+
+	debug(2, "elfloader: cxa-atexit finalize(dso=%p): matched=%d ran=%d (total registered=%d)",
+		dso_handle, matched, ran, s_count);
+}
+
+} // extern "C"
+
+// Ensure the main binary's own statics are finalized at process exit.
+// Registered early via constructor so it runs late in the atexit sequence.
+static void cxa_finalize_all() {
+	__cxa_finalize(NULL);
+}
+
+static void register_cxa_cleanup() __attribute__((constructor, used));
+static void register_cxa_cleanup() {
+	// debug() / stdio aren't ready at constructor time, so no log here.
+	atexit(cxa_finalize_all);
+}
+
+#endif // defined(DYNAMIC_MODULES) && defined(USE_ELF_LOADER) && defined(ELF_LOADER_CXA_ATEXIT) && defined(__MINT__)
diff --git a/backends/plugins/elf/elf-provider.cpp b/backends/plugins/elf/elf-provider.cpp
index 2c491c473a8..b579588ae05 100644
--- a/backends/plugins/elf/elf-provider.cpp
+++ b/backends/plugins/elf/elf-provider.cpp
@@ -23,10 +23,6 @@
 
 #if defined(DYNAMIC_MODULES) && defined(USE_ELF_LOADER)
 
-#ifdef ELF_LOADER_CXA_ATEXIT
-#include <cxxabi.h>
-#endif
-
 #include "backends/plugins/elf/elf-provider.h"
 #include "backends/plugins/dynamic-plugin.h"
 #include "backends/plugins/elf/memory-manager.h"
@@ -57,10 +53,13 @@
  * __cxa_finalize(&__dso_handle) to call all destructors of only that DSO.
  *
  * Prerequisites:
- * - The used libc needs to support __cxa_atexit
+ * - The used libc needs to support __cxa_atexit (or the target must supply it;
+ *   see backends/plugins/elf/cxa-atexit.cpp)
  * - -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
+ * - Every plugin needs its own hidden __dso_handle symbol, and an exported
+ *   PLUGIN_finalize() helper that calls __cxa_finalize(&__dso_handle) from
+ *   inside the plugin. 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,
@@ -137,11 +136,9 @@ bool ELFPlugin::loadPlugin() {
 
 #ifdef ELF_LOADER_CXA_ATEXIT
 	if (ret) {
-		// 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);
+		_finalizeFunc = findSymbol("PLUGIN_finalize");
+		if (!_finalizeFunc)
+			warning("elfloader: plugin '%s' is missing PLUGIN_finalize", _filename.toString(Common::Path::kNativeSeparator).c_str());
 	}
 #endif
 
@@ -155,10 +152,10 @@ void ELFPlugin::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;
+		if (_finalizeFunc) {
+			debug(2, "elfloader: calling PLUGIN_finalize");
+			_finalizeFunc();
+			_finalizeFunc = 0;
 		}
 #endif
 
diff --git a/backends/plugins/elf/elf-provider.h b/backends/plugins/elf/elf-provider.h
index 90a80b64598..6f03272a24c 100644
--- a/backends/plugins/elf/elf-provider.h
+++ b/backends/plugins/elf/elf-provider.h
@@ -44,7 +44,7 @@ protected:
 	typedef const char *(*CharFunc)();
 
 	DLObject *_dlHandle;
-	void *_dso_handle;
+	VoidFunc _finalizeFunc;
 
 	virtual VoidFunc findSymbol(const char *symbol);
 
@@ -52,7 +52,7 @@ public:
 	ELFPlugin(const Common::Path &filename) :
 		DynamicPlugin(filename),
 		_dlHandle(0),
-		_dso_handle(0) {
+		_finalizeFunc(0) {
 	}
 
 	virtual ~ELFPlugin() {
diff --git a/backends/plugins/elf/plugin.syms b/backends/plugins/elf/plugin.syms
index 97f9937f7a8..054b5cde104 100644
--- a/backends/plugins/elf/plugin.syms
+++ b/backends/plugins/elf/plugin.syms
@@ -3,8 +3,8 @@ PLUGIN_getVersion
 PLUGIN_getType
 PLUGIN_getTypeVersion
 PLUGIN_getObject
+PLUGIN_finalize
 ___plugin_ctors
 ___plugin_ctors_end
 ___plugin_dtors
 ___plugin_dtors_end
-__dso_handle
diff --git a/base/plugins.h b/base/plugins.h
index 15b7bdd7f1e..52d4dace970 100644
--- a/base/plugins.h
+++ b/base/plugins.h
@@ -27,6 +27,10 @@
 #include "common/str.h"
 #include "backends/plugins/elf/version.h"
 
+#if defined(USE_ELF_LOADER) && defined(ELF_LOADER_CXA_ATEXIT)
+#include <cxxabi.h>
+#endif
+
 #define INCLUDED_FROM_BASE_PLUGINS_H
 #include "base/internal_plugins.h"
 #undef INCLUDED_FROM_BASE_PLUGINS_H
@@ -64,8 +68,15 @@ extern const int pluginTypeVersions[PLUGIN_TYPE_MAX];
 #if defined(USE_ELF_LOADER) && defined(ELF_LOADER_CXA_ATEXIT)
 #define PLUGIN_DYNAMIC_DSO_HANDLE \
 	uint32 __dso_handle __attribute__((visibility("hidden"))) = 0;
+// Exported helper that runs __cxa_finalize from inside the plugin, so the
+// &__dso_handle argument is the plugin's own resolved address -- the same one
+// GCC embedded in its __cxa_atexit calls. Calling __cxa_finalize from the host
+// with a findSymbol() lookup is fragile (see elf-provider.cpp).
+#define PLUGIN_DYNAMIC_FINALIZE \
+	PLUGIN_EXPORT void PLUGIN_finalize() { __cxxabiv1::__cxa_finalize(&__dso_handle); }
 #else
 #define PLUGIN_DYNAMIC_DSO_HANDLE
+#define PLUGIN_DYNAMIC_FINALIZE
 #endif
 
 #ifdef USE_ELF_LOADER
@@ -106,6 +117,7 @@ extern const int pluginTypeVersions[PLUGIN_TYPE_MAX];
 #define REGISTER_PLUGIN_DYNAMIC(ID,TYPE,PLUGINCLASS) \
 	extern "C" { \
 		PLUGIN_DYNAMIC_DSO_HANDLE \
+		PLUGIN_DYNAMIC_FINALIZE \
 		PLUGIN_DYNAMIC_BUILD_DATE \
 		PLUGIN_EXPORT int32 PLUGIN_getVersion() { return PLUGIN_VERSION; } \
 		PLUGIN_EXPORT int32 PLUGIN_getType() { return TYPE; } \


Commit: 83ebddc748e3d38d999ac6a17216cf1e5455c6cc
    https://github.com/scummvm/scummvm/commit/83ebddc748e3d38d999ac6a17216cf1e5455c6cc
Author: Miro Kropacek (miro.kropacek at gmail.com)
Date: 2026-04-27T02:05:36+10:00

Commit Message:
BACKENDS: ATARI: Implement plugins

Changed paths:
  A backends/plugins/atari/atari-provider.cpp
  A backends/plugins/atari/atari-provider.h
  A backends/plugins/elf/m68k-loader.cpp
  A backends/plugins/elf/m68k-loader.h
  A backends/plugins/firebee/firebee-provider.cpp
  A backends/plugins/firebee/firebee-provider.h
  A backends/plugins/mintelf/plugin.ld
    backends/module.mk
    backends/platform/atari/atari.mk
    backends/platform/atari/build-release.sh
    backends/platform/atari/build-release030.sh
    backends/platform/atari/osystem_atari.cpp
    backends/platform/atari/readme.txt
    backends/platform/atari/readme.txt.in
    backends/plugins/elf/elf-loader.cpp
    backends/plugins/elf/elf32.h
    base/plugins.cpp
    configure


diff --git a/backends/module.mk b/backends/module.mk
index e6b2daa873a..4fb973b353e 100644
--- a/backends/module.mk
+++ b/backends/module.mk
@@ -173,6 +173,7 @@ MODULE_OBJS += \
 	plugins/elf/cxa-atexit.o \
 	plugins/elf/elf-loader.o \
 	plugins/elf/elf-provider.o \
+	plugins/elf/m68k-loader.o \
 	plugins/elf/memory-manager.o \
 	plugins/elf/mips-loader.o \
 	plugins/elf/ppc-loader.o \
@@ -428,6 +429,10 @@ MODULE_OBJS += \
 	graphics/atari/atari-supervidel.o \
 	graphics/atari/atari-surface.o \
 	mixer/atari/atari-mixer.o
+ifdef USE_ELF_LOADER
+MODULE_OBJS += \
+	plugins/atari/atari-provider.o
+endif
 endif
 
 ifeq ($(BACKEND),ds)
diff --git a/backends/platform/atari/atari.mk b/backends/platform/atari/atari.mk
index 77bd28c47ed..e57cf8713ff 100644
--- a/backends/platform/atari/atari.mk
+++ b/backends/platform/atari/atari.mk
@@ -17,7 +17,7 @@ FB_DATA		:= ${FB_DIR}
 FB_DOCS		:= ${FB_DIR}/doc
 FB_THEMES	:= ${FB_DIR}
 
-atarilitedist: $(EXECUTABLE)
+atarilitedist: $(EXECUTABLE) plugins
 	$(RM_REC) ${LITE_DIR}
 	$(MKDIR) ${LITE_DIR}
 
@@ -25,6 +25,13 @@ atarilitedist: $(EXECUTABLE)
 	$(NM) -C ${LITE_DIR}/$(EXECUTABLE) | grep -vF ' .L' | grep ' [TtWV] ' | $(CXXFILT) | sort -u > ${LITE_DIR}/scummvm.sym
 	$(STRIP) -s ${LITE_DIR}/$(EXECUTABLE)
 
+ifneq ($(PLUGINS),)
+	$(MKDIR) ${LITE_DIR}/plugins
+	$(CP) $(PLUGINS) ${LITE_DIR}/plugins
+	$(STRIP) --strip-debug ${LITE_DIR}/plugins/*$(PLUGIN_SUFFIX)
+	! [ -f ${LITE_DIR}/plugins/detection$(PLUGIN_SUFFIX) ] || mv ${LITE_DIR}/plugins/detection$(PLUGIN_SUFFIX) ${LITE_DIR}/plugins/detectio$(PLUGIN_SUFFIX)
+endif
+
 	$(MKDIR) ${LITE_DOCS}
 	$(CP) $(DIST_FILES_DOCS) ${LITE_DOCS}
 
@@ -48,7 +55,7 @@ ifeq ($(CREATE_ZIP),y)
 	$(ZIP) -r -9 ../${LITE_DIR}.zip ${LITE_DIR}
 endif
 
-atarifulldist: $(EXECUTABLE)
+atarifulldist: $(EXECUTABLE) plugins
 	$(RM_REC) ${FULL_DIR}
 	$(MKDIR) ${FULL_DIR}
 
@@ -56,6 +63,13 @@ atarifulldist: $(EXECUTABLE)
 	$(NM) -C ${FULL_DIR}/$(EXECUTABLE) | grep -vF ' .L' | grep ' [TtWV] ' | $(CXXFILT) | sort -u > ${FULL_DIR}/scummvm.sym
 	$(STRIP) -s ${FULL_DIR}/$(EXECUTABLE)
 
+ifneq ($(PLUGINS),)
+	$(MKDIR) ${FULL_DIR}/plugins
+	$(CP) $(PLUGINS) ${FULL_DIR}/plugins
+	$(STRIP) --strip-debug ${FULL_DIR}/plugins/*$(PLUGIN_SUFFIX)
+	! [ -f ${FULL_DIR}/plugins/detection$(PLUGIN_SUFFIX) ] || mv ${FULL_DIR}/plugins/detection$(PLUGIN_SUFFIX) ${FULL_DIR}/plugins/detectio$(PLUGIN_SUFFIX)
+endif
+
 	$(MKDIR) ${FULL_DOCS}
 	$(CP) $(DIST_FILES_DOCS) ${FULL_DOCS}
 
diff --git a/backends/platform/atari/build-release.sh b/backends/platform/atari/build-release.sh
index d819bf02e5d..a8c1d6d5e7a 100755
--- a/backends/platform/atari/build-release.sh
+++ b/backends/platform/atari/build-release.sh
@@ -8,6 +8,7 @@ cd build-release
 
 PLATFORM=m68k-atari-mintelf
 FASTCALL=false
+PLUGINS=true
 export ASFLAGS="-m68020-60"
 export CXXFLAGS="-m68020-60 -DUSE_MOVE16 -DUSE_SUPERVIDEL -DUSE_SV_BLITTER -DDISABLE_LAUNCHERDISPLAY_GRID"
 export LDFLAGS="-m68020-60"
@@ -21,6 +22,13 @@ then
 	LDFLAGS="$LDFLAGS -mfastcall"
 fi
 
+if $PLUGINS
+then
+	PLUGINS_FLAGS="--enable-plugins --default-dynamic --enable-detection-dynamic"
+else
+	PLUGINS_FLAGS=""
+fi
+
 if [ ! -f config.log ]
 then
 ../configure \
@@ -28,7 +36,8 @@ then
 	--host=${PLATFORM} \
 	--enable-release \
 	--enable-verbose-build \
-	--disable-engine=hugo,director,cine,ultima,pink,wage
+	--disable-engine=hugo,director,cine,ultima,pink,wage \
+	${PLUGINS_FLAGS}
 fi
 
 make -j$(getconf _NPROCESSORS_CONF) atarifulldist
diff --git a/backends/platform/atari/build-release030.sh b/backends/platform/atari/build-release030.sh
index 80ec6781ef4..4c78cfee3e2 100755
--- a/backends/platform/atari/build-release030.sh
+++ b/backends/platform/atari/build-release030.sh
@@ -8,6 +8,7 @@ cd build-release030
 
 PLATFORM=m68k-atari-mintelf
 FASTCALL=false
+PLUGINS=true
 export ASFLAGS="-m68030"
 export CXXFLAGS="-m68030 -DDISABLE_FANCY_THEMES -DDISABLE_DOSBOX_OPL -DDISABLE_MAME_OPL"
 export LDFLAGS="-m68030"
@@ -21,6 +22,13 @@ then
 	LDFLAGS="$LDFLAGS -mfastcall"
 fi
 
+if $PLUGINS
+then
+	PLUGINS_FLAGS="--enable-plugins --default-dynamic --enable-detection-dynamic"
+else
+	PLUGINS_FLAGS=""
+fi
+
 if [ ! -f config.log ]
 then
 ../configure \
@@ -30,7 +38,8 @@ then
 	--disable-highres \
 	--disable-bink \
 	--enable-verbose-build \
-	--disable-engine=hugo,director,cine,ultima
+	--disable-engine=hugo,director,cine,ultima \
+	${PLUGINS_FLAGS}
 fi
 
 make -j$(getconf _NPROCESSORS_CONF) atarilitedist
diff --git a/backends/platform/atari/osystem_atari.cpp b/backends/platform/atari/osystem_atari.cpp
index 527f7b10001..b2ec8429151 100644
--- a/backends/platform/atari/osystem_atari.cpp
+++ b/backends/platform/atari/osystem_atari.cpp
@@ -43,6 +43,9 @@
 #include "backends/platform/atari/osystem_atari.h"
 
 #include "backends/audiocd/default/default-audiocd.h"
+#ifdef DYNAMIC_MODULES
+#include "backends/plugins/atari/atari-provider.h"
+#endif
 #include "common/config-manager.h"
 #include "backends/events/atari/atari-events.h"
 #include "backends/events/default/default-events.h"
@@ -522,6 +525,10 @@ int main(int argc, char *argv[]) {
 	g_system = OSystem_Atari_create();
 	assert(g_system);
 
+#ifdef DYNAMIC_MODULES
+	PluginManager::instance().addPluginProvider(new AtariPluginProvider());
+#endif
+
 	// Invoke the actual ScummVM main entry point:
 	int res = scummvm_main(argc, argv);
 	g_system->destroy();
diff --git a/backends/platform/atari/readme.txt b/backends/platform/atari/readme.txt
index 199de1a38b3..504abf272b4 100644
--- a/backends/platform/atari/readme.txt
+++ b/backends/platform/atari/readme.txt
@@ -534,18 +534,10 @@ Future plans
 
 - DSP-based sample mixer (WAV, FLAC, MP2).
 
-- Avoid loading music/speech files (and thus slowing down everything) if muted.
-
-- Cached audio/video streams (i.e. don't load only "audio_buffer_size" number
-  of samples but cache, say, 1 second so disk i/o won't be so stressed).
-
-- Using Thorsten Otto's sharedlibs: https://tho-otto.de/sharedlibs.php for game
-  engine plugins to relieve the huge binary size.
+- Avoid decoding music/speech files (and thus slowing down everything) if muted.
 
 - True audio CD support via MetaDOS API.
 
-- OPL2LPT and Retrowave support (if I manage to purchase it somewhere).
-
 
 Closing words
 -------------
diff --git a/backends/platform/atari/readme.txt.in b/backends/platform/atari/readme.txt.in
index d2a13d4119e..f0ec035feb3 100644
--- a/backends/platform/atari/readme.txt.in
+++ b/backends/platform/atari/readme.txt.in
@@ -534,18 +534,10 @@ Future plans
 
 - DSP-based sample mixer (WAV, FLAC, MP2).
 
-- Avoid loading music/speech files (and thus slowing down everything) if muted.
-
-- Cached audio/video streams (i.e. don't load only "audio_buffer_size" number
-  of samples but cache, say, 1 second so disk i/o won't be so stressed).
-
-- Using Thorsten Otto's sharedlibs: https://tho-otto.de/sharedlibs.php for game
-  engine plugins to relieve the huge binary size.
+- Avoid decoding music/speech files (and thus slowing down everything) if muted.
 
 - True audio CD support via MetaDOS API.
 
-- OPL2LPT and Retrowave support (if I manage to purchase it somewhere).
-
 
 Closing words
 -------------
diff --git a/backends/plugins/atari/atari-provider.cpp b/backends/plugins/atari/atari-provider.cpp
new file mode 100644
index 00000000000..2c2aef4a91c
--- /dev/null
+++ b/backends/plugins/atari/atari-provider.cpp
@@ -0,0 +1,87 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#define FORBIDDEN_SYMBOL_ALLOW_ALL
+#include "common/scummsys.h"
+
+#if defined(DYNAMIC_MODULES) && defined(__MINT__) && defined(__ELF__) && !defined(__mcoldfire__)
+
+#include "backends/plugins/atari/atari-provider.h"
+#include "backends/plugins/elf/m68k-loader.h"
+
+#include <mint/cookie.h>
+#include <mint/mintbind.h>
+#include <mint/ssystem.h>
+
+class AtariDLObject final : public M68KDLObject {
+protected:
+	void relocateSymbols(ptrdiff_t offset) override {
+		// Symbols imported via `ld --just-symbols=$(EXECUTABLE)` (used by the
+		// plugin link step to resolve references into the main binary) end up as
+		// SHN_ABS with st_value = ELF VMA in the main binary. The atariprg loader
+		// loads the main binary at _base->p_tbase, so the runtime address is
+		// (ELF VMA + p_tbase). Patch SHN_ABS entries here; the base implementation
+		// then handles plugin-local symbols.
+		const uint32 mainOffset = (uint32)_base->p_tbase;
+		Elf32_Sym *s = _symtab;
+		for (uint32 c = _symbol_cnt; c--; s++) {
+			if (s->st_shndx == SHN_ABS)
+				s->st_value += mainOffset;
+		}
+
+		DLObject::relocateSymbols(offset);
+	}
+
+	void flushDataCache(void *ptr, uint32 len) const override {
+		if (Ssystem(-1, 0L, 0L) == 0) {
+			Ssystem(S_FLUSHCACHE, (long)ptr, (long)len);
+		} else {
+			long mcpu = 0;
+
+			if (Getcookie(C__CPU, &mcpu) == C_FOUND) {
+			    if (mcpu >= 40) {
+			    	long oldssp = Super(SUP_SET);
+			    	__asm__ volatile (
+						".word	0xF478\n\t"	// cpusha dc
+						".word	0xF498"	// cinva  ic
+						::: "memory"
+					);
+			    	Super((void *)oldssp);
+			    } else if (mcpu >= 20) {
+			    	long oldssp = Super(SUP_SET);
+			    	__asm__ volatile (
+						"movec	%%cacr,%%d0\n\t"
+						"or.w	#0x0008,%%d0\n\t"	// CI
+						"movec	%%d0,%%cacr"
+						::: "d0", "cc", "memory"
+					);
+			    	Super((void *)oldssp);
+			    }
+			}
+		}
+	}
+};
+
+Plugin *AtariPluginProvider::createPlugin(const Common::FSNode &node) const {
+	return new TemplatedELFPlugin<AtariDLObject>(node.getPath());
+}
+
+#endif // defined(DYNAMIC_MODULES) && defined(__MINT__) && defined(__ELF__) && !defined(__mcoldfire__)
diff --git a/backends/plugins/atari/atari-provider.h b/backends/plugins/atari/atari-provider.h
new file mode 100644
index 00000000000..fcc733906a6
--- /dev/null
+++ b/backends/plugins/atari/atari-provider.h
@@ -0,0 +1,36 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#if defined(DYNAMIC_MODULES) && defined(__MINT__) && defined(__ELF__) && !defined(__mcoldfire__)
+
+#ifndef BACKENDS_PLUGINS_ATARI_PROVIDER_H
+#define BACKENDS_PLUGINS_ATARI_PROVIDER_H
+
+#include "backends/plugins/elf/elf-provider.h"
+
+class AtariPluginProvider final : public ELFPluginProvider {
+public:
+	Plugin *createPlugin(const Common::FSNode &node) const override;
+};
+
+#endif // BACKENDS_PLUGINS_ATARI_PROVIDER_H
+
+#endif // defined(DYNAMIC_MODULES) && defined(__MINT__) && defined(__ELF__) && !defined(__mcoldfire__)
diff --git a/backends/plugins/elf/elf-loader.cpp b/backends/plugins/elf/elf-loader.cpp
index 75469875c67..4be63738675 100644
--- a/backends/plugins/elf/elf-loader.cpp
+++ b/backends/plugins/elf/elf-loader.cpp
@@ -127,6 +127,9 @@ bool DLObject::readElfHeader(Elf32_Ehdr *ehdr) {
 #endif
 #ifdef PPC_TARGET
 			EM_PPC
+#endif
+#ifdef M68K_TARGET
+			EM_68K
 #endif
 			) {
 		warning("elfloader: Wrong ELF file architecture.");
diff --git a/backends/plugins/elf/elf32.h b/backends/plugins/elf/elf32.h
index c436922bc73..2d406ab230d 100644
--- a/backends/plugins/elf/elf32.h
+++ b/backends/plugins/elf/elf32.h
@@ -81,6 +81,7 @@ typedef struct {
 #define ET_CORE		4			/* core file */
 
 // e_machine values
+#define EM_68K		4
 #define EM_MIPS		8
 #define EM_PPC		20
 #define EM_ARM		40
@@ -245,6 +246,15 @@ typedef struct {
 #define R_PPC_REL24			10
 #define R_PPC_REL32			26
 
+// m68k relocation types
+#define R_68K_NONE			0
+#define R_68K_32			1
+#define R_68K_16			2
+#define R_68K_8				3
+#define R_68K_PC32			4
+#define R_68K_PC16			5
+#define R_68K_PC8			6
+
 #endif // defined(DYNAMIC_MODULES) && defined(USE_ELF_LOADER)
 
 #endif /* BACKENDS_ELF_H */
diff --git a/backends/plugins/elf/m68k-loader.cpp b/backends/plugins/elf/m68k-loader.cpp
new file mode 100644
index 00000000000..1e520fa55a2
--- /dev/null
+++ b/backends/plugins/elf/m68k-loader.cpp
@@ -0,0 +1,120 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "common/scummsys.h"
+
+#if defined(DYNAMIC_MODULES) && defined(USE_ELF_LOADER) && defined(M68K_TARGET)
+
+#include "backends/plugins/elf/elf-loader.h"
+#include "backends/plugins/elf/m68k-loader.h"
+
+#include "common/debug.h"
+
+#include <mint/basepage.h>
+
+bool M68KDLObject::relocate(Elf32_Off offset, Elf32_Word size, byte *relSegment) {
+	Elf32_Rela *rel = (Elf32_Rela *)malloc(size);
+
+	if (!rel) {
+		warning("elfloader: Could not allocate %d bytes for the relocation table", size);
+		return false;
+	}
+
+	if (!_file->seek(offset, SEEK_SET) || _file->read(rel, size) != size) {
+		warning("elfloader: Relocation table load failed.");
+		free(rel);
+		return false;
+	}
+
+	uint32 cnt = size / sizeof(*rel);
+
+	debug(2, "elfloader: Loaded relocation table. %d entries. base address=%p", cnt, relSegment);
+
+	for (uint32 i = 0; i < cnt; i++) {
+		Elf32_Sym *sym = _symtab + REL_INDEX(rel[i].r_info);
+		byte *src = relSegment + rel[i].r_offset - _segmentVMA;
+		uint32 value = sym->st_value + rel[i].r_addend;
+
+		switch (REL_TYPE(rel[i].r_info)) {
+		case R_68K_NONE:
+			break;
+		case R_68K_32:
+			*(uint32 *)src = value;
+			debug(8, "elfloader: R_68K_32 -> 0x%08x", *(uint32 *)src);
+			break;
+		case R_68K_16:
+			*(uint16 *)src = (uint16)value;
+			debug(8, "elfloader: R_68K_16 -> 0x%04x", *(uint16 *)src);
+			break;
+		case R_68K_8:
+			*src = (uint8)value;
+			debug(8, "elfloader: R_68K_8 -> 0x%02x", *src);
+			break;
+		case R_68K_PC32:
+			*(uint32 *)src = value - (uint32)src;
+			debug(8, "elfloader: R_68K_PC32 -> 0x%08x", *(uint32 *)src);
+			break;
+		case R_68K_PC16:
+			*(uint16 *)src = (uint16)(value - (uint32)src);
+			debug(8, "elfloader: R_68K_PC16 -> 0x%04x", *(uint16 *)src);
+			break;
+		case R_68K_PC8:
+			*src = (uint8)(value - (uint32)src);
+			debug(8, "elfloader: R_68K_PC8 -> 0x%02x", *src);
+			break;
+		default:
+			warning("elfloader: Unknown relocation type %d", REL_TYPE(rel[i].r_info));
+			free(rel);
+			return false;
+		}
+	}
+
+	free(rel);
+	return true;
+}
+
+bool M68KDLObject::relocateRels(Elf32_Ehdr *ehdr, Elf32_Shdr *shdr) {
+	for (uint32 i = 0; i < ehdr->e_shnum; i++) {
+		Elf32_Shdr *curShdr = &(shdr[i]);
+
+		if ((curShdr->sh_type == SHT_REL) &&
+				curShdr->sh_entsize == sizeof(Elf32_Rel) &&
+				int32(curShdr->sh_link) == _symtab_sect &&
+				curShdr->sh_info < ehdr->e_shnum &&
+				(shdr[curShdr->sh_info].sh_flags & SHF_ALLOC)) {
+			warning("elfloader: REL entries not supported on m68k!");
+			return false;
+		}
+
+		if ((curShdr->sh_type == SHT_RELA) &&
+				curShdr->sh_entsize == sizeof(Elf32_Rela) &&
+				int32(curShdr->sh_link) == _symtab_sect &&
+				curShdr->sh_info < ehdr->e_shnum &&
+				(shdr[curShdr->sh_info].sh_flags & SHF_ALLOC)) {
+			if (!relocate(curShdr->sh_offset, curShdr->sh_size, _segment))
+				return false;
+		}
+	}
+
+	return true;
+}
+
+#endif /* defined(DYNAMIC_MODULES) && defined(USE_ELF_LOADER) && defined(M68K_TARGET) */
diff --git a/backends/plugins/elf/m68k-loader.h b/backends/plugins/elf/m68k-loader.h
new file mode 100644
index 00000000000..fd67ca08774
--- /dev/null
+++ b/backends/plugins/elf/m68k-loader.h
@@ -0,0 +1,39 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef BACKENDS_PLUGINS_M68K_LOADER_H
+#define BACKENDS_PLUGINS_M68K_LOADER_H
+
+#include "common/scummsys.h"
+
+#if defined(DYNAMIC_MODULES) && defined(USE_ELF_LOADER) && defined(M68K_TARGET)
+
+#include "backends/plugins/elf/elf-loader.h"
+
+class M68KDLObject : public DLObject {
+protected:
+	bool relocate(Elf32_Off offset, Elf32_Word size, byte *relSegment) override;
+	bool relocateRels(Elf32_Ehdr *ehdr, Elf32_Shdr *shdr) override;
+};
+
+#endif /* defined(DYNAMIC_MODULES) && defined(USE_ELF_LOADER) && defined(M68K_TARGET) */
+
+#endif /* BACKENDS_PLUGINS_M68K_LOADER_H */
diff --git a/backends/plugins/firebee/firebee-provider.cpp b/backends/plugins/firebee/firebee-provider.cpp
new file mode 100644
index 00000000000..011c74cfacb
--- /dev/null
+++ b/backends/plugins/firebee/firebee-provider.cpp
@@ -0,0 +1,91 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#define FORBIDDEN_SYMBOL_ALLOW_ALL
+#include "common/scummsys.h"
+
+#if defined(DYNAMIC_MODULES) && defined(__MINT__) && defined(__ELF__) && defined(__mcoldfire__)
+
+#include "backends/plugins/firebee/firebee-provider.h"
+#include "backends/plugins/elf/m68k-loader.h"
+
+#include <mint/cookie.h>
+#include <mint/mintbind.h>
+#include <mint/ssystem.h>
+
+class FireBeeDLObject final : public M68KDLObject {
+protected:
+	void relocateSymbols(ptrdiff_t offset) override {
+		// Symbols imported via `ld --just-symbols=$(EXECUTABLE)` (used by the
+		// plugin link step to resolve references into the main binary) end up as
+		// SHN_ABS with st_value = ELF VMA in the main binary. The atariprg loader
+		// loads the main binary at _base->p_tbase, so the runtime address is
+		// (ELF VMA + p_tbase). Patch SHN_ABS entries here; the base implementation
+		// then handles plugin-local symbols.
+		const uint32 mainOffset = (uint32)_base->p_tbase;
+		Elf32_Sym *s = _symtab;
+		for (uint32 c = _symbol_cnt; c--; s++) {
+			if (s->st_shndx == SHN_ABS)
+				s->st_value += mainOffset;
+		}
+
+		DLObject::relocateSymbols(offset);
+	}
+
+	void flushDataCache(void *ptr, uint32 len) const override {
+		if (Ssystem(-1, 0L, 0L) == 0) {
+			Ssystem(S_FLUSHCACHE, (long)ptr, (long)len);
+		} else {		
+			// ignored for now
+			(void)ptr;
+			(void)len;
+
+			long oldssp = Super(SUP_SET);
+			__asm__ volatile (
+				"nop\n\t"	// flush store buffer
+				"moveq.l #0,%%d0\n\t"	// way = 0
+				"moveq.l #0,%%d1\n\t"	// set = 0
+				"move.l  %%d0,%%a0\n"
+				"1:\n\t"
+				"cpushl  %%bc,(%%a0)\n\t"	// push + invalidate line
+				"add.l   #16,%%a0\n\t"
+				"addq.l  #1,%%d1\n\t"
+				"cmpi.l  #512,%%d1\n\t"
+				"bne.s   1b\n\t"
+				"moveq.l #0,%%d1\n\t"
+				"addq.l  #1,%%d0\n\t"
+				"move.l  %%d0,%%a0\n\t"
+				"cmpi.l  #4,%%d0\n\t"
+				"bne.s   1b"
+				:
+				:
+				: "d0", "d1", "a0", "memory", "cc"
+			);
+			Super((void *)oldssp);
+		}
+	}
+};
+
+Plugin *FireBeePluginProvider::createPlugin(const Common::FSNode &node) const {
+	return new TemplatedELFPlugin<FireBeeDLObject>(node.getPath());
+}
+
+#endif // defined(DYNAMIC_MODULES) && defined(__MINT__) && defined(__ELF__) && defined(__mcoldfire__)
diff --git a/backends/plugins/firebee/firebee-provider.h b/backends/plugins/firebee/firebee-provider.h
new file mode 100644
index 00000000000..0eabb690ef9
--- /dev/null
+++ b/backends/plugins/firebee/firebee-provider.h
@@ -0,0 +1,36 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#if defined(DYNAMIC_MODULES) && defined(__MINT__) && defined(__ELF__) && defined(__mcoldfire__)
+
+#ifndef BACKENDS_PLUGINS_FIREBEE_PROVIDER_H
+#define BACKENDS_PLUGINS_FIREBEE_PROVIDER_H
+
+#include "backends/plugins/elf/elf-provider.h"
+
+class FireBeePluginProvider final : public ELFPluginProvider {
+public:
+	Plugin *createPlugin(const Common::FSNode &node) const override;
+};
+
+#endif // BACKENDS_PLUGINS_FIREBEE_PROVIDER_H
+
+#endif // defined(DYNAMIC_MODULES) && defined(__MINT__) && defined(__ELF__) && defined(__mcoldfire__)
diff --git a/backends/plugins/mintelf/plugin.ld b/backends/plugins/mintelf/plugin.ld
new file mode 100644
index 00000000000..29683d3b319
--- /dev/null
+++ b/backends/plugins/mintelf/plugin.ld
@@ -0,0 +1,163 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+OUTPUT_FORMAT("elf32-m68k")
+OUTPUT_ARCH(m68k)
+ENTRY(_start)
+
+PHDRS
+{
+	/* ScummVM's elf loader only allows a single segment. */
+	plugin PT_LOAD FLAGS(7) /* Read | Write | Execute */;
+}
+
+SECTIONS
+{
+	. = 0;
+
+	.text ALIGN(4) :
+	{
+		*(.text.unlikely .text.*_unlikely .text.unlikely.*)
+		*(.text.exit .text.exit.*)
+		*(.text.startup .text.startup.*)
+		*(.text.hot .text.hot.*)
+		*(.text .stub .text.* .gnu.linkonce.t.*)
+		*(.gnu.warning)
+	} : plugin
+
+	.rodata ALIGN(4) :
+	{
+		*(.rodata)
+		*(.rodata.*)
+		*(.gnu.linkonce.r*)
+		*(.rodata1)
+		. = ALIGN(4);
+	} : plugin
+
+	.preinit_array ALIGN(4) :
+	{
+		PROVIDE (__preinit_array_start = .);
+		KEEP (*(.preinit_array))
+		PROVIDE (__preinit_array_end = .);
+	} : plugin
+
+	/* m68k-atari-mintelf gcc emits constructors into .init_array (and dtors
+	 * into .fini_array). The ELF plugin loader walks ___plugin_ctors and
+	 * ___plugin_dtors both forward; .init_array semantics match (ascending
+	 * priority = construction order), but standard .fini_array is walked
+	 * backward by a normal runtime, so we REVERSE the .fini_array sort here
+	 * to get reverse-of-construction destruction order out of a forward
+	 * walk. .ctors/.dtors are kept too in case any input object still uses
+	 * the legacy sections. */
+	.ctors ALIGN(4) :
+	{
+		___plugin_ctors = .;
+		KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*)))
+		KEEP (*(.init_array))
+		KEEP (*(SORT_BY_INIT_PRIORITY(.ctors.*)))
+		KEEP (*(.ctors))
+		___plugin_ctors_end = .;
+	} : plugin
+
+	.dtors ALIGN(4) :
+	{
+		___plugin_dtors = .;
+		KEEP (*(SORT_BY_INIT_PRIORITY(REVERSE(.fini_array.*))))
+		KEEP (*(.fini_array))
+		KEEP (*(SORT_BY_INIT_PRIORITY(REVERSE(.dtors.*))))
+		KEEP (*(.dtors))
+		___plugin_dtors_end = .;
+	} : plugin
+
+	.data ALIGN(4) :
+	{
+		*(.data)
+		*(.data.*)
+		*(.gnu.linkonce.d*)
+		CONSTRUCTORS
+		. = ALIGN(4);
+	} : plugin
+	.data1 :
+	{
+		*(.data1)
+		. = ALIGN(4);
+	} : plugin
+
+	__bss_start__ = .;
+	.bss ALIGN(4) :
+	{
+		*(.dynbss)
+		*(.bss)
+		*(SORT(.bss.*))
+		*(.gnu.linkonce.b*)
+		*(COMMON)
+		. = ALIGN(4);
+	} : plugin
+	__bss_end__ = .;
+
+	__end__ = ABSOLUTE(.) ;
+
+	/* Discard sections that complicate post-processing */
+	/DISCARD/ : { *(.group .comment .note) }
+
+	/* Stabs debugging sections. */
+	.stab          0 : { *(.stab) }
+	.stabstr       0 : { *(.stabstr) }
+	.stab.excl     0 : { *(.stab.excl) }
+	.stab.exclstr  0 : { *(.stab.exclstr) }
+	.stab.index    0 : { *(.stab.index) }
+	.stab.indexstr 0 : { *(.stab.indexstr) }
+
+	/* DWARF debug sections.
+	   Symbols in the DWARF debugging sections are relative to the beginning
+	   of the section so we begin them at 0. */
+
+	/* DWARF 1 */
+	.debug          0 : { *(.debug) }
+	.line           0 : { *(.line) }
+
+	/* GNU DWARF 1 extensions */
+	.debug_srcinfo  0 : { *(.debug_srcinfo) }
+	.debug_sfnames  0 : { *(.debug_sfnames) }
+
+	/* DWARF 1.1 and DWARF 2 */
+	.debug_aranges  0 : { *(.debug_aranges) }
+	.debug_pubnames 0 : { *(.debug_pubnames) }
+
+	/* DWARF 2 */
+	.debug_info     0 : { *(.debug_info) }
+	.debug_abbrev   0 : { *(.debug_abbrev) }
+	.debug_line     0 : { *(.debug_line) }
+	.debug_frame    0 : { *(.debug_frame) }
+	.debug_str      0 : { *(.debug_str) }
+	.debug_loc      0 : { *(.debug_loc) }
+	.debug_macinfo  0 : { *(.debug_macinfo) }
+
+	/* DWARF 3 */
+	.debug_pubtypes 0 : { *(.debug_pubtypes) }
+	.debug_ranges   0 : { *(.debug_ranges) }
+
+	/* DWARF Extension. */
+	.debug_macro    0 : { *(.debug_macro) }
+	.gnu.attributes 0 : { KEEP (*(.gnu.attributes)) }
+
+	/DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) }
+}
diff --git a/base/plugins.cpp b/base/plugins.cpp
index 5bdf09c5691..93aaa7bcbfd 100644
--- a/base/plugins.cpp
+++ b/base/plugins.cpp
@@ -318,7 +318,11 @@ void PluginManagerUncached::init() {
 	unloadPluginsExcept(PLUGIN_TYPE_ENGINE, nullptr, false); // empty the engine plugins
 
 #ifndef DETECTION_STATIC
-	Common::String detectPluginName = "detection";
+#ifdef PLUGIN_DETECTION_NAME
+Common::String detectPluginName = PLUGIN_DETECTION_NAME;
+#else
+Common::String detectPluginName = "detection";
+#endif
 #ifdef PLUGIN_SUFFIX
 	detectPluginName += PLUGIN_SUFFIX;
 #endif
diff --git a/configure b/configure
index 97c8097738a..9a6f8c280e2 100755
--- a/configure
+++ b/configure
@@ -684,7 +684,7 @@ get_system_exe_extension() {
 	mingw* | *os2-emx)
 		_exeext=".exe"
 		;;
-	mint)
+	mint*)
 		_exeext=".prg"
 		;;
 	emscripten)
@@ -1841,6 +1841,11 @@ kos32)
 	_host_cpu=i686
 	_host_alias=kos32
 	;;
+m68k-atari-mintelf*)
+	_host_os=mintelf
+	_host_cpu=m68k
+	_host_alias=$_host
+	;;
 m68k-atari-mint*)
 	_host_os=mint
 	_host_cpu=m68k
@@ -5203,6 +5208,18 @@ PLUGIN_EXTRA_DEPS =
 PLUGIN_LDFLAGS  += -shared
 PRE_OBJS_FLAGS  := -Wl,-export-dynamic -Wl,-whole-archive
 POST_OBJS_FLAGS := -Wl,-no-whole-archive
+'
+		;;
+	mintelf)
+		_elf_loader=yes
+		append_var DEFINES "-DM68K_TARGET"
+		append_var DEFINES "-DPLUGIN_DETECTION_NAME=\\\"detectio\\\""
+		append_var CXXFLAGS "-fuse-cxa-atexit"
+		append_var DEFINES "-DELF_LOADER_CXA_ATEXIT"
+		append_var DEFINES "-DUNCACHED_PLUGINS"
+		append_var DEFINES "-DELF_NO_MEM_MANAGER"
+_mak_plugins='
+PLUGIN_LDFLAGS		+= -Wl,-m,m68kelf,-T,$(srcdir)/backends/plugins/mintelf/plugin.ld
 '
 		;;
 	*cygwin* | *mingw32* | mingw64)


Commit: b02c2de70fc7235b5ed9dba302a70c3e89aad181
    https://github.com/scummvm/scummvm/commit/b02c2de70fc7235b5ed9dba302a70c3e89aad181
Author: Miro Kropacek (miro.kropacek at gmail.com)
Date: 2026-04-27T02:05:36+10:00

Commit Message:
BACKENDS: ATARI: Match other platforms' plugin.ld ctors/dtors layout

Revert the folding of .init_array / .fini_array into ___plugin_ctors /
___plugin_dtors. Other ELF-loader backends (3ds, riscos, wii, ds, psp)
keep these as separate sections, and the cross-platform migration to
walk .init_array / .fini_array directly from the loader will be done in
the future (see https://github.com/scummvm/scummvm/pull/7446).

m68k-atari-mintelf-gcc emits .init_array / .fini_array rather than
.ctors / .dtors. I have verified it two ways: scummvm.prg has populated
.init_array (6 entries) and .fini_array (1 entry); and adding a single
namespace-scope `static Foo g;` to an engine TU produces an .init_array
entry in the resulting .plg that lives outside ___plugin_ctors ..
___plugin_ctors_end. So with this layout, such an entry is silently
never run (same of every other ELF backend?). Fortunately, no engine has
such a static today (every built plugin has empty ctor/dtor ranges), so
nothing currently breaks.

Changed paths:
    backends/plugins/mintelf/plugin.ld


diff --git a/backends/plugins/mintelf/plugin.ld b/backends/plugins/mintelf/plugin.ld
index 29683d3b319..c82b2802f9a 100644
--- a/backends/plugins/mintelf/plugin.ld
+++ b/backends/plugins/mintelf/plugin.ld
@@ -59,20 +59,26 @@ SECTIONS
 		PROVIDE (__preinit_array_end = .);
 	} : plugin
 
-	/* m68k-atari-mintelf gcc emits constructors into .init_array (and dtors
-	 * into .fini_array). The ELF plugin loader walks ___plugin_ctors and
-	 * ___plugin_dtors both forward; .init_array semantics match (ascending
-	 * priority = construction order), but standard .fini_array is walked
-	 * backward by a normal runtime, so we REVERSE the .fini_array sort here
-	 * to get reverse-of-construction destruction order out of a forward
-	 * walk. .ctors/.dtors are kept too in case any input object still uses
-	 * the legacy sections. */
+	.init_array ALIGN(4) :
+	{
+		PROVIDE (__init_array_start = .);
+		KEEP (*(SORT(.init_array.*)))
+		KEEP (*(.init_array))
+		PROVIDE (__init_array_end = .);
+	} : plugin
+
+	.fini_array ALIGN(4) :
+	{
+		PROVIDE (__fini_array_start = .);
+		KEEP (*(.fini_array))
+		KEEP (*(SORT(.fini_array.*)))
+		PROVIDE (__fini_array_end = .);
+	} : plugin
+
 	.ctors ALIGN(4) :
 	{
 		___plugin_ctors = .;
-		KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*)))
-		KEEP (*(.init_array))
-		KEEP (*(SORT_BY_INIT_PRIORITY(.ctors.*)))
+		KEEP (*(SORT(.ctors.*)))
 		KEEP (*(.ctors))
 		___plugin_ctors_end = .;
 	} : plugin
@@ -80,9 +86,7 @@ SECTIONS
 	.dtors ALIGN(4) :
 	{
 		___plugin_dtors = .;
-		KEEP (*(SORT_BY_INIT_PRIORITY(REVERSE(.fini_array.*))))
-		KEEP (*(.fini_array))
-		KEEP (*(SORT_BY_INIT_PRIORITY(REVERSE(.dtors.*))))
+		KEEP (*(SORT(.dtors.*)))
 		KEEP (*(.dtors))
 		___plugin_dtors_end = .;
 	} : plugin


Commit: 3a6a355c20c12f77a57cd85a278c36c9efb45254
    https://github.com/scummvm/scummvm/commit/3a6a355c20c12f77a57cd85a278c36c9efb45254
Author: Miro Kropacek (miro.kropacek at gmail.com)
Date: 2026-04-27T02:05:36+10:00

Commit Message:
BACKENDS: SDL: Add plugins support for Atari/FireBee

Changed paths:
    backends/module.mk
    backends/platform/atari/atari.mk
    backends/platform/atari/build-firebee.sh
    backends/platform/sdl/posix/posix-main.cpp
    backends/plugins/posix/posix-provider.cpp
    configure


diff --git a/backends/module.mk b/backends/module.mk
index 4fb973b353e..e329ae04fa2 100644
--- a/backends/module.mk
+++ b/backends/module.mk
@@ -238,9 +238,15 @@ endif
 
 ifndef RISCOS
 ifndef KOLIBRIOS
+ifdef USE_ATARI_PLUGIN_PROVIDER
+MODULE_OBJS += plugins/atari/atari-provider.o
+else ifdef USE_FIREBEE_PLUGIN_PROVIDER
+MODULE_OBJS += plugins/firebee/firebee-provider.o
+else
 MODULE_OBJS += plugins/sdl/sdl-provider.o
 endif
 endif
+endif
 
 # SDL 2 removed audio CD support
 ifndef USE_SDL2
diff --git a/backends/platform/atari/atari.mk b/backends/platform/atari/atari.mk
index e57cf8713ff..244b38def91 100644
--- a/backends/platform/atari/atari.mk
+++ b/backends/platform/atari/atari.mk
@@ -108,13 +108,20 @@ ifeq ($(CREATE_ZIP),y)
 	$(ZIP) -r -9 ../${FULL_DIR}.zip ${FULL_DIR}
 endif
 
-fbdist: $(EXECUTABLE)
+fbdist: $(EXECUTABLE) plugins
 	$(RM_REC) ${FB_DIR}
 	$(MKDIR) ${FB_DIR}
 
 	$(CP) $(EXECUTABLE) ${FB_DIR}
 	$(STRIP) -s ${FB_DIR}/$(EXECUTABLE)
 
+ifneq ($(PLUGINS),)
+	$(MKDIR) ${FB_DIR}/plugins
+	$(CP) $(PLUGINS) ${FB_DIR}/plugins
+	$(STRIP) --strip-debug ${FB_DIR}/plugins/*$(PLUGIN_SUFFIX)
+	! [ -f ${FB_DIR}/plugins/detection$(PLUGIN_SUFFIX) ] || mv ${FB_DIR}/plugins/detection$(PLUGIN_SUFFIX) ${FB_DIR}/plugins/detectio$(PLUGIN_SUFFIX)
+endif
+
 	$(MKDIR) ${FB_DOCS}
 	$(CP) $(DIST_FILES_DOCS) ${FB_DOCS}
 
diff --git a/backends/platform/atari/build-firebee.sh b/backends/platform/atari/build-firebee.sh
index 51c5116f831..e175f5476a5 100755
--- a/backends/platform/atari/build-firebee.sh
+++ b/backends/platform/atari/build-firebee.sh
@@ -8,6 +8,7 @@ cd build-firebee
 
 PLATFORM=m68k-atari-mintelf
 FASTCALL=false
+PLUGINS=true
 export CXXFLAGS="-mcpu=5475"
 export LDFLAGS="-mcpu=5475"
 #export CXXFLAGS="-m68020-60"
@@ -23,6 +24,13 @@ then
 	LDFLAGS="$LDFLAGS -mfastcall"
 fi
 
+if $PLUGINS
+then
+	PLUGINS_FLAGS="--enable-plugins --default-dynamic --enable-detection-dynamic"
+else
+	PLUGINS_FLAGS=""
+fi
+
 if [ ! -f config.log ]
 then
 ../configure \
@@ -32,7 +40,8 @@ then
 	--with-freetype2-prefix="$(${PLATFORM}-gcc -print-sysroot)/usr/bin/${CPU_DIR}" \
 	--with-mikmod-prefix="$(${PLATFORM}-gcc -print-sysroot)/usr/bin/${CPU_DIR}" \
 	--enable-release \
-	--enable-verbose-build
+	--enable-verbose-build \
+	${PLUGINS_FLAGS}
 fi
 
 make -j$(getconf _NPROCESSORS_CONF) fbdist
diff --git a/backends/platform/sdl/posix/posix-main.cpp b/backends/platform/sdl/posix/posix-main.cpp
index 3bca233a86e..acdadd765ed 100644
--- a/backends/platform/sdl/posix/posix-main.cpp
+++ b/backends/platform/sdl/posix/posix-main.cpp
@@ -24,7 +24,13 @@
 #if defined(POSIX) && !defined(MACOSX) && !defined(SAMSUNGTV) && !defined(MAEMO) && !defined(OPENDINGUX) && !defined(OPENPANDORA) && !defined(PLAYSTATION3) && !defined(PSP2) && !defined(NINTENDO_SWITCH)  && !defined(__EMSCRIPTEN__) && !defined(MIYOO) && !defined(MIYOOMINI) && !defined(SAILFISH)
 
 #include "backends/platform/sdl/posix/posix.h"
+#ifdef USE_ATARI_PLUGIN_PROVIDER
+#include "backends/plugins/atari/atari-provider.h"
+#elif defined(USE_FIREBEE_PLUGIN_PROVIDER)
+#include "backends/plugins/firebee/firebee-provider.h"
+#else
 #include "backends/plugins/sdl/sdl-provider.h"
+#endif
 #include "base/main.h"
 
 int main(int argc, char *argv[]) {
@@ -37,7 +43,13 @@ int main(int argc, char *argv[]) {
 	g_system->init();
 
 #ifdef DYNAMIC_MODULES
+#if defined(USE_ATARI_PLUGIN_PROVIDER)
+	PluginManager::instance().addPluginProvider(new AtariPluginProvider());
+#elif defined(USE_FIREBEE_PLUGIN_PROVIDER)
+	PluginManager::instance().addPluginProvider(new FireBeePluginProvider());
+#else
 	PluginManager::instance().addPluginProvider(new SDLPluginProvider());
+#endif
 #endif
 
 	// Invoke the actual ScummVM main entry point:
diff --git a/backends/plugins/posix/posix-provider.cpp b/backends/plugins/posix/posix-provider.cpp
index 37c4656de3b..f669e0765ff 100644
--- a/backends/plugins/posix/posix-provider.cpp
+++ b/backends/plugins/posix/posix-provider.cpp
@@ -21,7 +21,7 @@
 
 #include "common/scummsys.h"
 
-#if defined(DYNAMIC_MODULES) && defined(POSIX) && !defined(__3DS__)
+#if defined(DYNAMIC_MODULES) && defined(POSIX) && !defined(__3DS__) && !defined(__MINT__)
 
 #include "backends/plugins/posix/posix-provider.h"
 #include "backends/plugins/dynamic-plugin.h"
@@ -81,4 +81,4 @@ Plugin *POSIXPluginProvider::createPlugin(const Common::FSNode &node) const {
 }
 
 
-#endif // defined(DYNAMIC_MODULES) && defined(POSIX)
+#endif // defined(DYNAMIC_MODULES) && defined(POSIX) && !defined(__3DS__) && !defined(__MINT__)
diff --git a/configure b/configure
index 9a6f8c280e2..bb52b25bd8c 100755
--- a/configure
+++ b/configure
@@ -3927,6 +3927,16 @@ if test -n "$_host"; then
 			_nuked_opl=no
 			_detection_features_full=no
 
+			if test "$_backend" = sdl; then
+				if cc_check_define __mcoldfire__; then
+					_firebee_plugin_provider=yes
+				else
+					_atari_plugin_provider=yes
+				fi
+				define_in_config_if_yes "$_atari_plugin_provider" 'USE_ATARI_PLUGIN_PROVIDER'
+				define_in_config_if_yes "$_firebee_plugin_provider" 'USE_FIREBEE_PLUGIN_PROVIDER'
+			fi
+
 			_port_mk="backends/platform/atari/atari.mk"
 			;;
 		maemo)




More information about the Scummvm-git-logs mailing list