PLUGINS: Plugin support for the GameCube/Wii backend.

svn-id: r52553
This commit is contained in:
Andre Heider 2010-09-05 12:49:29 +00:00
parent 5986aa96f2
commit 13770ce9cd
10 changed files with 532 additions and 1 deletions

View File

@ -26,6 +26,7 @@ MODULE_OBJS := \
plugins/mips-loader.o \
plugins/shorts-segment-manager.o \
plugins/arm-loader.o \
plugins/ppc-loader.o \
plugins/elf-provider.o \
plugins/dc/dc-provider.o \
plugins/posix/posix-provider.o \

View File

@ -25,6 +25,7 @@
#include <unistd.h>
#include "osystem.h"
#include "backends/plugins/wii/wii-provider.h"
#include <ogc/machine/processor.h>
#include <fat.h>
@ -210,6 +211,10 @@ int main(int argc, char *argv[]) {
g_system = new OSystem_Wii();
assert(g_system);
#ifdef DYNAMIC_MODULES
PluginManager::instance().addPluginProvider(new WiiPluginProvider());
#endif
res = scummvm_main(argc, argv);
g_system->quit();

View File

@ -37,6 +37,11 @@
#include <nds.h>
#endif
#ifdef __WII__
#include <malloc.h>
#include <ogc/cache.h>
#endif
#include "backends/plugins/elf-loader.h"
#include "common/debug.h"
@ -61,6 +66,10 @@ static void flushDataCache(void *ptr, uint32 len) {
sceKernelDcacheWritebackRange(ptr, len);
sceKernelIcacheInvalidateRange(ptr, len);
#endif
#ifdef __WII__
DCFlushRange(ptr, len);
ICInvalidateRange(ptr, len);
#endif
}
DLObject::DLObject() :
@ -72,7 +81,8 @@ DLObject::DLObject() :
_dtors_start(0),
_dtors_end(0),
_segmentSize(0),
_segmentOffset(0) {
_segmentOffset(0),
_segmentVMA(0) {
}
DLObject::~DLObject() {
@ -135,6 +145,9 @@ bool DLObject::readElfHeader(Common::SeekableReadStream* DLFile, Elf32_Ehdr *ehd
#endif
#ifdef MIPS_TARGET
EM_MIPS
#endif
#ifdef PPC_TARGET
EM_PPC
#endif
) {
warning("elfloader: Wrong ELF file architecture.");
@ -190,6 +203,7 @@ bool DLObject::loadSegment(Common::SeekableReadStream* DLFile, Elf32_Phdr *phdr)
// Get offset to load segment into
baseAddress = (char *)_segment;
_segmentSize = phdr->p_memsz + extra;
_segmentVMA = phdr->p_vaddr;
// Set bss segment to 0 if necessary (assumes bss is at the end)
if (phdr->p_memsz > phdr->p_filesz) {

View File

@ -52,6 +52,7 @@ protected:
uint32 _segmentSize;
ptrdiff_t _segmentOffset;
uint32 _segmentVMA;
virtual void unload();
bool load(Common::SeekableReadStream* DLFile);

View File

@ -82,6 +82,7 @@ typedef struct {
// e_machine values
#define EM_MIPS 8
#define EM_PPC 20
#define EM_ARM 40
// Program header (contains info about segment)
@ -233,6 +234,14 @@ typedef struct
#define R_ARM_TARGET1 38
#define R_ARM_V4BX 40
// PPC relocation types
#define R_PPC_ADDR32 1
#define R_PPC_ADDR16_LO 4
#define R_PPC_ADDR16_HI 5
#define R_PPC_ADDR16_HA 6
#define R_PPC_REL24 10
#define R_PPC_REL32 26
// Mock function to get value of global pointer for MIPS
#define getGP() ({ \
unsigned int __valgp; \

View File

@ -0,0 +1,128 @@
/* 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 2
* 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, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* $URL: https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/branches/gsoc2010-plugins/backends/plugins/arm-loader.cpp $
* $Id: arm-loader.cpp 52058 2010-08-13 05:58:11Z toneman1138 $
*
*/
#if defined(DYNAMIC_MODULES) && defined(PPC_TARGET)
#include "backends/plugins/elf-loader.h"
#include "backends/plugins/ppc-loader.h"
#include "common/debug.h"
bool PPCDLObject::relocate(Common::SeekableReadStream* DLFile, unsigned long offset, unsigned long size, void *relSegment) {
Elf32_Rela *rel = NULL;
if (!(rel = (Elf32_Rela *)malloc(size))) {
warning("elfloader: Out of memory.");
return false;
}
if (DLFile->seek(offset, SEEK_SET) < 0 ||
DLFile->read(rel, size) != size) {
warning("elfloader: Relocation table load failed.");
free(rel);
return false;
}
int cnt = size / sizeof(*rel);
debug(2, "elfloader: Loaded relocation table. %d entries. base address=%p\n", cnt, relSegment);
uint32 *src;
uint32 value;
for (int i = 0; i < cnt; i++) {
// Get the symbol this relocation entry is referring to
Elf32_Sym *sym = (Elf32_Sym *)(_symtab) + (REL_INDEX(rel[i].r_info));
// Get the target instruction in the code
src = (uint32 *)((char *)relSegment + rel[i].r_offset - _segmentVMA);
value = sym->st_value + rel[i].r_addend;
//debug(8, "elfloader: i=%05d %p +0x%04x: (0x%08x) 0x%08x ", i, src, rel[i].r_addend, sym->st_value, *src);
switch (REL_TYPE(rel[i].r_info)) {
case R_PPC_ADDR32:
*src = value;
debug(8, "elfloader: R_PPC_ADDR32 -> 0x%08x\n", *src);
break;
case R_PPC_ADDR16_LO:
*((uint16 *) src) = value;
debug(8, "elfloader: R_PPC_ADDR16_LO -> 0x%08x\n", *src);
break;
case R_PPC_ADDR16_HI:
*(uint16 *) src = value >> 16;
debug(8, "elfloader: R_PPC_ADDR16_HA -> 0x%08x\n", *src);
break;
case R_PPC_ADDR16_HA:
*(uint16 *) src = (value + 0x8000) >> 16;
debug(8, "elfloader: R_PPC_ADDR16_HA -> 0x%08x\n", *src);
break;
case R_PPC_REL24:
*src = (*src & ~0x03fffffc) | ((value - (uint32) src) & 0x03fffffc);
debug(8, "elfloader: R_PPC_REL24 -> 0x%08x\n", *src);
break;
case R_PPC_REL32:
*src = value - (uint32) src;
debug(8, "elfloader: R_PPC_REL32 -> 0x%08x\n", *src);
break;
default:
warning("elfloader: Unknown relocation type %d\n", REL_TYPE(rel[i].r_info));
free(rel);
return false;
}
}
free(rel);
return true;
}
bool PPCDLObject::relocateRels(Common::SeekableReadStream* DLFile, Elf32_Ehdr *ehdr, Elf32_Shdr *shdr) {
for (int i = 0; i < ehdr->e_shnum; i++) {
Elf32_Shdr *curShdr = &(shdr[i]);
if ((curShdr->sh_type == SHT_REL) &&
curShdr->sh_entsize == sizeof(Elf32_Rel) &&
(int)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!\n");
return false;
}
if ((curShdr->sh_type == SHT_RELA) &&
curShdr->sh_entsize == sizeof(Elf32_Rela) &&
(int)curShdr->sh_link == _symtab_sect &&
curShdr->sh_info < ehdr->e_shnum &&
(shdr[curShdr->sh_info].sh_flags & SHF_ALLOC)) {
if (!relocate(DLFile, curShdr->sh_offset, curShdr->sh_size, _segment))
return false;
}
}
return true;
}
#endif /* defined(DYNAMIC_MODULES) && defined(PPC_TARGET) */

View File

@ -0,0 +1,40 @@
/* 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 2
* 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, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* $URL: https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/branches/gsoc2010-plugins/backends/plugins/arm-loader.h $
* $Id: arm-loader.h 52053 2010-08-13 02:58:52Z toneman1138 $
*
*/
#if defined(DYNAMIC_MODULES) && defined(PPC_TARGET)
#include "backends/plugins/elf-loader.h"
class PPCDLObject : public DLObject {
protected:
virtual bool relocate(Common::SeekableReadStream* DLFile, unsigned long offset, unsigned long size, void *relSegment);
virtual bool relocateRels(Common::SeekableReadStream* DLFile, Elf32_Ehdr *ehdr, Elf32_Shdr *shdr);
public:
PPCDLObject() : DLObject() {}
};
#endif /* defined(DYNAMIC_MODULES) && defined(PPC_TARGET) */

View File

@ -0,0 +1,263 @@
/*
* Linkscript for Wii
*/
OUTPUT_FORMAT("elf32-powerpc", "elf32-powerpc", "elf32-powerpc");
OUTPUT_ARCH(powerpc:common);
PHDRS
{
plugin PT_LOAD FLAGS(7);
}
SECTIONS
{
. = 0x81000000;
/* Program */
.init :
{
KEEP (*crt0.o(*.init))
KEEP (*(.init))
} :plugin = 0
.plt : { *(.plt) }
.interp : { *(.interp) }
.hash : { *(.hash) }
.dynsym : { *(.dynsym) }
.dynstr : { *(.dynstr) }
.gnu.version : { *(.gnu.version) }
.gnu.version_d : { *(.gnu.version_d) }
.gnu.version_r : { *(.gnu.version_r) }
.rel.init : { *(.rel.init) }
.rela.init : { *(.rela.init) }
.rel.text : { *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) }
.rela.text : { *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) }
.rel.fini : { *(.rel.fini) }
.rela.fini : { *(.rela.fini) }
.rel.rodata : { *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) }
.rela.rodata : { *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) }
.rel.data : { *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*) }
.rela.data : { *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) }
.rel.tdata : { *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*) }
.rela.tdata : { *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) }
.rel.tbss : { *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*) }
.rela.tbss : { *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) }
.rel.ctors : { *(.rel.ctors) }
.rela.ctors : { *(.rela.ctors) }
.rel.dtors : { *(.rel.dtors) }
.rela.dtors : { *(.rela.dtors) }
.rel.got : { *(.rel.got) }
.rela.got : { *(.rela.got) }
.rela.got1 : { *(.rela.got1) }
.rela.got2 : { *(.rela.got2) }
.rel.sdata : { *(.rel.sdata .rel.sdata.* .rel.gnu.linkonce.s.*) }
.rela.sdata : { *(.rela.sdata .rela.sdata.* .rela.gnu.linkonce.s.*) }
.rel.sbss : { *(.rel.sbss .rel.sbss.* .rel.gnu.linkonce.sb.*) }
.rela.sbss : { *(.rela.sbss .rela.sbss.* .rel.gnu.linkonce.sb.*) }
.rel.sdata2 : { *(.rel.sdata2 .rel.sdata2.* .rel.gnu.linkonce.s2.*) }
.rela.sdata2 : { *(.rela.sdata2 .rela.sdata2.* .rela.gnu.linkonce.s2.*) }
.rel.sbss2 : { *(.rel.sbss2 .rel.sbss2.* .rel.gnu.linkonce.sb2.*) }
.rela.sbss2 : { *(.rela.sbss2 .rela.sbss2.* .rela.gnu.linkonce.sb2.*) }
.rel.bss : { *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) }
.rela.bss : { *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) }
.rel.plt : { *(.rel.plt) }
.rela.plt : { *(.rela.plt) }
.text :
{
*(.text)
*(.text.*)
/* .gnu.warning sections are handled specially by elf32.em. */
*(.gnu.warning)
*(.gnu.linkonce.t.*)
. = ALIGN(32); /* REQUIRED. LD is flaky without it. */
} = 0
.fini :
{
KEEP (*(.fini))
. = ALIGN(32); /* REQUIRED. LD is flaky without it. */
} = 0
PROVIDE (__etext = .);
PROVIDE (_etext = .);
PROVIDE (etext = .);
.rodata : { *(.rodata) *(.rodata.*) *(.gnu.linkonce.r.*) }
.rodata1 : { *(.rodata1) }
.sdata2 : { *(.sdata2) *(.sdata2.*) *(.gnu.linkonce.s2.*) }
.sbss2 : { *(.sbss2) *(.sbss2.*) *(.gnu.linkonce.sb2.*) }
/* Adjust the address for the data segment. We want to adjust up to
the same address within the page on the next page up. */
/* Ensure the __preinit_array_start label is properly aligned. We
could instead move the label definition inside the section, but
the linker would then create the section even if it turns out to
be empty, which isn't pretty. */
. = ALIGN(32 / 8);
PROVIDE (__preinit_array_start = .);
.preinit_array : { *(.preinit_array) }
PROVIDE (__preinit_array_end = .);
PROVIDE (__init_array_start = .);
.init_array : { *(.init_array) }
PROVIDE (__init_array_end = .);
PROVIDE (__fini_array_start = .);
.fini_array : { *(.fini_array) }
PROVIDE (__fini_array_end = .);
.data :
{
*(.data)
*(.data.*)
*(.gnu.linkonce.d.*)
SORT(CONSTRUCTORS)
. = ALIGN(32); /* REQUIRED. LD is flaky without it. */
}
.data1 : { *(.data1) }
.tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) }
.tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
.eh_frame : { KEEP (*(.eh_frame)) }
.gcc_except_table : { *(.gcc_except_table) }
.fixup : { *(.fixup) }
.got1 : { *(.got1) }
.got2 : { *(.got2) }
.dynamic : { *(.dynamic) }
.ctors :
{
___plugin_ctors = .;
KEEP (*(SORT(.ctors.*)))
KEEP (*(.ctors))
___plugin_ctors_end = .;
. = ALIGN(32); /* REQUIRED. LD is flaky without it. */
}
.dtors :
{
___plugin_dtors = .;
KEEP (*(SORT(.dtors.*)))
KEEP (*(.dtors))
___plugin_dtors_end = .;
. = ALIGN(32); /* REQUIRED. LD is flaky without it. */
}
.jcr : { KEEP (*(.jcr)) }
.got : { *(.got.plt) *(.got) }
/* We want the small data sections together, so single-instruction offsets
can access them all, and initialized data all before uninitialized, so
we can shorten the on-disk segment size. */
.sdata :
{
*(.sdata)
*(.sdata.*)
*(.gnu.linkonce.s.*)
. = ALIGN(32); /* REQUIRED. LD is flaky without it. */
}
_edata = .;
PROVIDE (edata = .);
.sbss :
{
__sbss_start = .;
PROVIDE (__sbss_start = .);
PROVIDE (___sbss_start = .);
*(.dynsbss)
*(.sbss)
*(.sbss.*)
*(.gnu.linkonce.sb.*)
*(.scommon)
PROVIDE (__sbss_end = .);
PROVIDE (___sbss_end = .);
. = ALIGN(32); /* REQUIRED. LD is flaky without it. */
__sbss_end = .;
}
.bss :
{
__bss_start = .;
PROVIDE (__bss_start = .);
*(.dynbss)
*(.bss)
*(.bss.*)
*(.gnu.linkonce.b.*)
*(COMMON)
/* Align here to ensure that the .bss section occupies space up to
_end. Align after .bss to ensure correct alignment even if the
.bss section disappears because there are no input sections. */
. = ALIGN(32);
PROVIDE (__bss_end = .);
__bss_end = .;
}
_end = .;
PROVIDE(end = .);
/* 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) }
.comment 0 : { *(.comment) }
/* 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) }
/* SGI/MIPS DWARF 2 extensions */
.debug_weaknames 0 : { *(.debug_weaknames) }
.debug_funcnames 0 : { *(.debug_funcnames) }
.debug_typenames 0 : { *(.debug_typenames) }
.debug_varnames 0 : { *(.debug_varnames) }
/* These must appear regardless of . */
}
__isIPL = 0;
__stack_addr = (__bss_start + SIZEOF(.bss) + 0x20000 + 7) & (-8);
__stack_end = (__bss_start + SIZEOF(.bss));
__intrstack_addr = (__stack_addr + 0x4000);
__intrstack_end = (__stack_addr);
__Arena1Lo = (__intrstack_addr + 31) & (-32);
__Arena1Hi = (0x816ffff0);
__Arena2Lo = (0x90002000);
__Arena2Hi = (0x933E0000);
__gxregs = (__Arena1Hi + 31) & (-32);
__ipcbufferLo = (0x933e0000);
__ipcbufferHi = (0x93400000);
/* for backward compatibility with old crt0 */
PROVIDE (__stack = (0x816ffff0));
PROVIDE(__isIPL = __isIPL);
PROVIDE(__stack_addr = __stack_addr);
PROVIDE(__stack_end = __stack_end);
PROVIDE(__intrstack_addr = __intrstack_addr);
PROVIDE(__intrstack_end = __intrstack_end);
PROVIDE(__Arena1Lo = __Arena1Lo);
PROVIDE(__Arena1Hi = __Arena1Hi);
PROVIDE(__Arena2Lo = __Arena2Lo);
PROVIDE(__Arena2Hi = __Arena2Hi);
PROVIDE(__ipcbufferLo = __ipcbufferLo);
PROVIDE(__ipcbufferHi = __ipcbufferHi);
PROVIDE(__gxregs = __gxregs);

View File

@ -0,0 +1,45 @@
/* 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 2
* 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, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* $URL: https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/branches/gsoc2010-plugins/backends/plugins/ds/ds-provider.h $
* $Id: ds-provider.h 52112 2010-08-16 08:41:04Z toneman1138 $
*
*/
#if defined(DYNAMIC_MODULES) && defined(__WII__)
#include "backends/plugins/elf-provider.h"
#include "backends/plugins/ppc-loader.h"
class WiiPluginProvider : public ELFPluginProvider {
class WiiPlugin : public ELFPlugin {
public:
WiiPlugin(const Common::String &filename) : ELFPlugin(filename) {}
DLObject *makeDLObject() { return new PPCDLObject(); }
};
public:
Plugin* createPlugin(const Common::FSNode &node) const {
return new WiiPlugin(node.getPath());
}
};
#endif // defined(DYNAMIC_MODULES) && defined(__WII__)

25
configure vendored
View File

@ -1418,6 +1418,10 @@ case $_host_os in
CXXFLAGS="$CXXFLAGS -I$DEVKITPRO/libogc/include"
# libogc is required to link the cc tests (includes _start())
LDFLAGS="$LDFLAGS -mogc -mcpu=750 -L$DEVKITPRO/libogc/lib/cube -logc"
if test "$_dynamic_modules" = "yes" ; then
# retarded toolchain patch forces --gc-sections, overwrite it
LDFLAGS="$LDFLAGS -Wl,--no-gc-sections"
fi
;;
haiku*)
DEFINES="$DEFINES -DSYSTEM_NOT_SUPPORTING_D_TYPE"
@ -1478,6 +1482,10 @@ case $_host_os in
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"
if test "$_dynamic_modules" = "yes" ; then
# retarded toolchain patch forces --gc-sections, overwrite it
LDFLAGS="$LDFLAGS -Wl,--no-gc-sections"
fi
;;
wince)
CXXFLAGS="$CXXFLAGS -O3 -march=armv4 -mtune=xscale"
@ -1969,6 +1977,23 @@ CXXFLAGS += -fpic
PLUGIN_LDFLAGS += -shared
PRE_OBJS_FLAGS := -Wl,-export-dynamic -Wl,-whole-archive
POST_OBJS_FLAGS := -Wl,-no-whole-archive
'
;;
gamecube | wii)
DEFINES="$DEFINES -DELF_LOADER_TARGET -DPPC_TARGET -DONE_PLUGIN_AT_A_TIME"
_def_plugin='
#define PLUGIN_PREFIX ""
#define PLUGIN_SUFFIX ".plg"
'
_mak_plugins='
DYNAMIC_MODULES := 1
PLUGIN_PREFIX :=
PLUGIN_SUFFIX := .plg
PLUGIN_EXTRA_DEPS = $(EXECUTABLE)
CXXFLAGS += -DDYNAMIC_MODULES
PLUGIN_LDFLAGS = -nostartfiles -Wl,-q,--just-symbols,$(EXECUTABLE),-T$(srcdir)/backends/plugins/wii/plugin.ld -Wl,--retain-symbols-file,$(srcdir)/backends/plugins/plugin.syms
PRE_OBJS_FLAGS := -Wl,--whole-archive
POST_OBJS_FLAGS := -Wl,--no-whole-archive
'
;;
gp2xwiz*)