diff options
Diffstat (limited to 'backends')
51 files changed, 3255 insertions, 1014 deletions
diff --git a/backends/module.mk b/backends/module.mk index e0a3f4c683..b3a23f10e7 100644 --- a/backends/module.mk +++ b/backends/module.mk @@ -22,6 +22,14 @@ MODULE_OBJS := \ midi/timidity.o \ midi/dmedia.o \ midi/windows.o \ + plugins/elf/elf-loader.o \ + plugins/elf/mips-loader.o \ + plugins/elf/shorts-segment-manager.o \ + plugins/elf/ppc-loader.o \ + plugins/elf/arm-loader.o \ + plugins/elf/elf-provider.o \ + plugins/elf/version.o \ + plugins/dc/dc-provider.o \ plugins/posix/posix-provider.o \ plugins/sdl/sdl-provider.o \ plugins/win32/win32-provider.o \ @@ -43,7 +51,8 @@ endif ifeq ($(BACKEND),ds) MODULE_OBJS += \ fs/ds/ds-fs-factory.o \ - fs/ds/ds-fs.o + fs/ds/ds-fs.o \ + plugins/ds/ds-provider.o endif ifeq ($(BACKEND),n64) @@ -54,7 +63,8 @@ endif ifeq ($(BACKEND),ps2) MODULE_OBJS += \ - fs/ps2/ps2-fs-factory.o + fs/ps2/ps2-fs-factory.o \ + plugins/ps2/ps2-provider.o endif ifeq ($(BACKEND),psp) @@ -68,7 +78,8 @@ endif ifeq ($(BACKEND),wii) MODULE_OBJS += \ - fs/wii/wii-fs-factory.o + fs/wii/wii-fs-factory.o \ + plugins/wii/wii-provider.o endif # Include common rules diff --git a/backends/platform/ds/arm9/makefile b/backends/platform/ds/arm9/makefile index bf9fc1d826..db8e41af48 100644 --- a/backends/platform/ds/arm9/makefile +++ b/backends/platform/ds/arm9/makefile @@ -1,10 +1,13 @@ srcdir ?= . DEPDIR := .deps -#DYNAMIC_MODULES = 1 +VERBOSE_BUILD = 0 +DYNAMIC_MODULES = 1 libndsdir = $(DEVKITPRO)/libnds #libndsdir = /home/neil/devkitpror21/libnds +ENABLED = DYNAMIC_PLUGIN + # Select the build by setting SCUMM_BUILD to a,b,c,d,e,f or g. # Anything else gets build a. @@ -12,7 +15,7 @@ ifeq ($(SCUMM_BUILD),k) DS_BUILD_K = 1 else ifeq ($(SCUMM_BUILD),j) - DS_BUILD_J = 1 + DS_BUILD_J = 1 else ifeq ($(SCUMM_BUILD),i) DS_BUILD_I = 1 @@ -64,7 +67,7 @@ ifdef DS_BUILD_F else ifdef DS_BUILD_E # TODO: Inherit the earth uses so much RAM that I have removed libmad in order to - # claw some back. + # claw some back. @@ -75,7 +78,7 @@ else ifdef DS_BUILD_K else - # USE_MAD = 1 + #USE_MAD = 1 endif endif endif @@ -112,7 +115,7 @@ USE_ARM_COSTUME_ASM = 1 ifdef DS_BUILD_A DEFINES = -DDS_BUILD_A -DUSE_ARM_GFX_ASM -DUSE_ARM_COSTUME_ASM LOGO = logoa.bmp - ENABLE_SCUMM = STATIC_PLUGIN + ENABLE_SCUMM = $(ENABLED) USE_ARM_GFX_ASM = 1 BUILD=scummvm-A endif @@ -120,66 +123,66 @@ endif ifdef DS_BUILD_B DEFINES = -DDS_BUILD_B LOGO = logob.bmp - ENABLE_SKY = STATIC_PLUGIN - ENABLE_QUEEN = STATIC_PLUGIN + ENABLE_SKY = $(ENABLED) + ENABLE_QUEEN = $(ENABLED) BUILD=scummvm-B endif ifdef DS_BUILD_C DEFINES = -DDS_BUILD_C LOGO = logoc.bmp - ENABLE_AGOS = STATIC_PLUGIN + ENABLE_AGOS = $(ENABLED) BUILD=scummvm-C endif ifdef DS_BUILD_D DEFINES = -DDS_BUILD_D LOGO = logod.bmp - ENABLE_GOB = STATIC_PLUGIN - ENABLE_CINE = STATIC_PLUGIN - ENABLE_AGI = STATIC_PLUGIN + ENABLE_GOB = $(ENABLED) + ENABLE_CINE = $(ENABLED) + ENABLE_AGI = $(ENABLED) BUILD=scummvm-D endif ifdef DS_BUILD_E DEFINES = -DDS_BUILD_E LOGO = logoe.bmp - ENABLE_SAGA = STATIC_PLUGIN + ENABLE_SAGA = $(ENABLED) BUILD=scummvm-E endif ifdef DS_BUILD_F DEFINES = -DDS_BUILD_F LOGO = logof.bmp - ENABLE_KYRA = STATIC_PLUGIN + ENABLE_KYRA = $(ENABLED) BUILD=scummvm-F endif ifdef DS_BUILD_G DEFINES = -DDS_BUILD_G LOGO = logog.bmp - ENABLE_LURE = STATIC_PLUGIN + ENABLE_LURE = $(ENABLED) BUILD=scummvm-G endif ifdef DS_BUILD_H DEFINES = -DDS_BUILD_H LOGO = logoh.bmp - ENABLE_PARALLACTION = STATIC_PLUGIN + ENABLE_PARALLACTION = $(ENABLED) BUILD=scummvm-H endif ifdef DS_BUILD_I DEFINES = -DDS_BUILD_I LOGO = logoi.bmp - ENABLE_MADE = STATIC_PLUGIN + ENABLE_MADE = $(ENABLED) BUILD=scummvm-I endif ifdef DS_BUILD_K DEFINES = -DDS_BUILD_K LOGO = logok.bmp - ENABLE_CRUISE = STATIC_PLUGIN + ENABLE_CRUISE = $(ENABLED) BUILD=scummvm-K endif @@ -187,18 +190,18 @@ endif #ifdef DS_BUILD_L # DEFINES = -DDS_BUILD_L # LOGO = logog.bmp -# ENABLE_DRASCULA = STATIC_PLUGIN +# ENABLE_DRASCULA = $(ENABLED) # BUILD=scummvm-K #endif #ifdef DS_BUILD_M # DEFINES = -DDS_BUILD_M # LOGO = logog.bmp -# ENABLE_TUCKER = STATIC_PLUGIN +# ENABLE_TUCKER = $(ENABLED) # BUILD=scummvm-K #endif -ARM7BIN := -7 $(CURDIR)/../../arm7/arm7.bin +ARM7BIN := -7 $(CURDIR)/../arm7/arm7.bin CC = arm-eabi-gcc CXX = arm-eabi-g++ @@ -236,14 +239,14 @@ CXXFLAGS= $(CFLAGS) -Wno-non-virtual-dtor -Wno-unknown-pragmas -Wno-reorder \ ASFLAGS = -mcpu=arm9tdmi -mthumb-interwork -DEFINES += -D__DS__ -DNDS -DARM9 -DNONSTANDARD_PORT -DDISABLE_TEXT_CONSOLE -DDISABLE_FANCY_THEMES -DVECTOR_RENDERER_FORMAT=1555 -DDISABLE_DOSBOX_OPL -DDISABLE_DEFAULT_SAVEFILEMANAGER -DARM +DEFINES += -D__DS__ -DNDS -DARM9 -DNONSTANDARD_PORT -DDISABLE_TEXT_CONSOLE -DDISABLE_FANCY_THEMES -DVECTOR_RENDERER_FORMAT=1555 -DDISABLE_DOSBOX_OPL -DDISABLE_DEFAULT_SAVEFILEMANAGER -DUSE_ELF_LOADER -DARM -DARM_TARGET -DONE_PLUGIN_AT_A_TIME ifdef USE_MAD DEFINES += -DUSE_MAD endif DEFINES += -DREDUCE_MEMORY_USAGE -LDFLAGS = -specs=ds_arm9.specs -mthumb-interwork -mno-fpu -Wl,-Map,map.txt -Wl,--gc-sections +LDFLAGS = -specs=ds_arm9.specs -mthumb-interwork -mno-fpu -Wl,--target1-abs,-Map,map.txt#-Wl,--gc-sections ifdef WRAP_MALLOC LDFLAGS += -Wl,--wrap,malloc @@ -252,12 +255,11 @@ endif BACKEND := ds -INCLUDES= -I$(portdir)/$(BUILD) -I$(srcdir) -I$(srcdir)/engines \ +INCLUDES= -I$(portdir) -I$(srcdir) -I$(srcdir)/engines \ -I$(portdir)/data -I$(portdir)/../commoninclude \ -I$(portdir)/source -I$(portdir)/source/mad \ -I$(libndsdir)/include -include $(srcdir)/common/scummsys.h - LIBS = -lm -L$(libndsdir)/lib -L$(portdir)/lib -lnds9 ifdef USE_MAD LIBS += -lmad @@ -266,7 +268,19 @@ ifdef USE_DEBUGGER LIBS += -ldsdebugger -ldswifi9 endif +ifeq ($(DYNAMIC_MODULES),1) +DEFINES += -DDYNAMIC_MODULES +PRE_OBJS_FLAGS = -Wl,--whole-archive +POST_OBJS_FLAGS = -Wl,--no-whole-archive +endif + EXECUTABLE = scummvm.elf + +PLUGIN_PREFIX = +PLUGIN_SUFFIX = .plg +PLUGIN_EXTRA_DEPS = $(srcdir)/backends/plugins/ds/plugin.ld $(srcdir)/backends/plugins/elf/plugin.syms $(EXECUTABLE) +PLUGIN_LDFLAGS += -nostartfiles -Wl,-q,--target1-abs,--just-symbols,$(EXECUTABLE),-T$(srcdir)/backends/plugins/ds/plugin.ld,--retain-symbols-file,$(srcdir)/backends/plugins/elf/plugin.syms -lstdc++ -lc -mthumb-interwork -mno-fpu#-Wl,--gc-sections -mno-crt0 $(DEVKITPRO)/devkitARM/arm-eabi/lib/ds_arm9_crt0.o + MKDIR = mkdir -p RM = rm -f RM_REC = rm -rf @@ -340,25 +354,22 @@ OPT_SIZE := -Os -mthumb OBJS := $(DATA_OBJS) $(PORT_OBJS) $(FAT_OBJS) - MODULE_DIRS += . -ndsall: - @[ -d $(BUILD) ] || mkdir -p $(BUILD) - make -C ./$(BUILD) -f ../makefile scummvm.nds scummvm.ds.gba +ndsall: plugins + make -f makefile scummvm.nds scummvm.ds.gba include $(srcdir)/Makefile.common semiclean: $(RM) $(portdir)/source/dsoptions.o $(portdir)/source/dsmain.o $(FAT_OBJS) $(DATA_OBJS) $(portdir)/source/wordcompletion.o $(portdir)/source/dsoptions.o -clean: +clean: #TODO: Manual removal of engine, plugins, etc. isn't very elegant! $(RM) $(OBJS) $(EXECUTABLE) - rm -fr $(BUILD) + rm -rf *.h engines plugins graphics gui common sound backends base map.txt scummvm.nds scummvm.ds.gba dist : SCUMMVM.BIN plugins plugin_dist - #--------------------------------------------------------------------------------- # canned command sequence for binary data #--------------------------------------------------------------------------------- @@ -400,13 +411,14 @@ endef #--------------------------------------------------------------------------------- %.nds: %.bin - ndstool -c $@ -9 $< $(ARM7BIN) -b ../../$(LOGO) "$(@F);ScummVM $(VERSION);DS Port" + ndstool -c $@ -9 $< $(ARM7BIN) -b ../$(LOGO) "$(@F);ScummVM $(VERSION);DS Port" %.ds.gba: %.nds dsbuild $< -o $@ -l $(portdir)/ndsloader.bin padbin 16 $@ #--------------------------------------------------------------------------------- + %.bin: %.elf $(OBJCOPY) -S -O binary $< $@ diff --git a/backends/platform/ds/arm9/source/dsmain.cpp b/backends/platform/ds/arm9/source/dsmain.cpp index 1525647c2e..3e33b168ee 100644 --- a/backends/platform/ds/arm9/source/dsmain.cpp +++ b/backends/platform/ds/arm9/source/dsmain.cpp @@ -105,6 +105,7 @@ #endif #include "engine.h" +#include "backends/plugins/ds/ds-provider.h" #include "backends/fs/ds/ds-fs.h" #include "base/version.h" #include "common/util.h" @@ -3213,6 +3214,9 @@ int main(void) { const char *argv[] = {"/scummvmds"}; #endif +#ifdef DYNAMIC_MODULES + PluginManager::instance().addPluginProvider(new DSPluginProvider()); +#endif while (1) { scummvm_main(ARRAYSIZE(argv), (char **) &argv); @@ -3225,11 +3229,15 @@ int main(void) { } // End of namespace DS +#ifndef DISABLE_TEXT_CONSOLE +extern int gDebugLevel; +#endif int main() { #ifndef DISABLE_TEXT_CONSOLE consoleDebugInit(DebugDevice_NOCASH); nocashMessage("startup\n"); + gDebugLevel = 2; #endif DS::main(); } diff --git a/backends/platform/ps2/systemps2.cpp b/backends/platform/ps2/systemps2.cpp index fd2bf80761..d525a35b7d 100644 --- a/backends/platform/ps2/systemps2.cpp +++ b/backends/platform/ps2/systemps2.cpp @@ -62,6 +62,8 @@ #include "backends/platform/ps2/ps2debug.h" #include "backends/fs/ps2/ps2-fs-factory.h" +#include "backends/plugins/ps2/ps2-provider.h" + #include "backends/saves/default/default-saves.h" #include "common/config-manager.h" @@ -108,7 +110,6 @@ extern "C" int scummvm_main(int argc, char *argv[]); extern "C" int main(int argc, char *argv[]) { SifInitRpc(0); - ee_thread_t thisThread; int tid = GetThreadId(); ReferThreadStatus(tid, &thisThread); @@ -133,8 +134,11 @@ extern "C" int main(int argc, char *argv[]) { sioprintf("Creating system\n"); g_system = g_systemPs2 = new OSystem_PS2(argv[0]); - g_systemPs2->init(); +#ifdef DYNAMIC_MODULES + PluginManager::instance().addPluginProvider(new PS2PluginProvider()); +#endif + g_systemPs2->init(); sioprintf("init done. starting ScummVM.\n"); int res = scummvm_main(argc, argv); sioprintf("scummvm_main terminated: %d\n", res); @@ -340,6 +344,7 @@ OSystem_PS2::OSystem_PS2(const char *elfPath) { } void OSystem_PS2::init(void) { + //msgPrintf(FOREVER, "got to init! Now restart your console... %d\n", res); sioprintf("Timer...\n"); _scummTimerManager = new DefaultTimerManager(); _scummMixer = new Audio::MixerImpl(this, 48000); diff --git a/backends/platform/psp/Makefile b/backends/platform/psp/Makefile index a104e3297a..9f6b5c8921 100644 --- a/backends/platform/psp/Makefile +++ b/backends/platform/psp/Makefile @@ -67,7 +67,7 @@ endif # Variables for common Scummvm makefile CXX = psp-g++ CXXFLAGS = -O3 -Wall -Wno-multichar -fno-exceptions -fno-rtti -DEFINES = -D__PSP__ -DNONSTANDARD_PORT -DDISABLE_TEXT_CONSOLE -DDISABLE_COMMAND_LINE -DUSE_ZLIB -DDISABLE_DOSBOX_OPL -DUSE_RGB_COLOR +DEFINES = -D__PSP__ -DNONSTANDARD_PORT -DDISABLE_TEXT_CONSOLE -DDISABLE_COMMAND_LINE -DUSE_ZLIB -DDISABLE_DOSBOX_OPL -DUSE_RGB_COLOR -DUSE_ELF_LOADER -DMIPS_TARGET LDFLAGS := INCDIR := $(srcdir) . $(srcdir)/engines/ $(PSPSDK)/include @@ -87,8 +87,8 @@ CXX_UPDATE_DEP_FLAG = -Wp,-MMD,"$(*D)/$(DEPDIR)/$(*F).d",-MQ,"$@",-MP # Variables for dynamic plugin building PLUGIN_PREFIX = PLUGIN_SUFFIX = .plg -PLUGIN_EXTRA_DEPS = plugin.syms scummvm-psp.elf -PLUGIN_LDFLAGS = -nostartfiles -Wl,-q,--just-symbols=scummvm-psp.org.elf,-Tplugin.ld,--retain-symbols-file,plugin.syms -lstdc++ -lc +PLUGIN_EXTRA_DEPS = $(srcdir)/backends/plugins/elf/plugin.syms scummvm-psp.elf +PLUGIN_LDFLAGS = -nostartfiles -Wl,-q,--just-symbols=scummvm-psp.org.elf,-T$(srcdir)/backends/plugins/psp/plugin.ld,--retain-symbols-file,$(srcdir)/backends/plugins/elf/plugin.syms -lstdc++ -lc # PSP-specific variables STRIP = psp-strip @@ -128,6 +128,7 @@ PSPLIBS = -lpspprof -lpspvfpu -lpspdebug -lpspgu -lpspge -lpspdisplay -lpspctrl -lpsputility -lpspuser -lpsppower -lpsphprm -lpspsdk -lpsprtc -lpspaudio -lpspaudiocodec \ -lpspkernel -lpspnet_inet + # Add in PSPSDK includes and libraries. LIBS += -lpng -lz -lstdc++ -lc -lm $(PSPLIBS) @@ -142,7 +143,6 @@ OBJS := powerman.o \ input.o \ cursor.o \ trace.o \ - psploader.o \ pspkeyboard.o \ audio.o \ thread.o \ @@ -153,6 +153,7 @@ OBJS := powerman.o \ tests.o \ dummy.o + BACKEND := psp # Include common Scummvm makefile diff --git a/backends/platform/psp/audio.cpp b/backends/platform/psp/audio.cpp index d7487b0c1a..b5a72dccd0 100644 --- a/backends/platform/psp/audio.cpp +++ b/backends/platform/psp/audio.cpp @@ -18,8 +18,8 @@ * 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/trunk/backends/platform/psp/osys_psp.cpp $ - * $Id: osys_psp.cpp 46126 2009-11-24 14:18:46Z fingolfin $ + * $URL$ + * $Id$ * */ diff --git a/backends/platform/psp/audio.h b/backends/platform/psp/audio.h index ec9801185f..f5179028dc 100644 --- a/backends/platform/psp/audio.h +++ b/backends/platform/psp/audio.h @@ -18,8 +18,8 @@ * 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/trunk/backends/platform/psp/osys_psp.cpp $ - * $Id: osys_psp.cpp 46126 2009-11-24 14:18:46Z fingolfin $ + * $URL$ + * $Id$ * */ diff --git a/backends/platform/psp/cursor.cpp b/backends/platform/psp/cursor.cpp index ae3b8f0050..cf879e095a 100644 --- a/backends/platform/psp/cursor.cpp +++ b/backends/platform/psp/cursor.cpp @@ -18,8 +18,8 @@ * 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/trunk/backends/platform/psp/osys_psp.h $ - * $Id: osys_psp.h 46120 2009-11-24 10:33:30Z Bluddy $ + * $URL$ + * $Id$ * */ diff --git a/backends/platform/psp/default_display_client.h b/backends/platform/psp/default_display_client.h index 716e6fcc35..2e33632eb1 100644 --- a/backends/platform/psp/default_display_client.h +++ b/backends/platform/psp/default_display_client.h @@ -18,8 +18,8 @@ * 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/trunk/backends/platform/psp/trace.h $ - * $Id: trace.h 44276 2009-09-23 16:11:23Z joostp $ + * $URL$ + * $Id$ * */ diff --git a/backends/platform/psp/display_client.cpp b/backends/platform/psp/display_client.cpp index 9d4f573e28..4310b195dd 100644 --- a/backends/platform/psp/display_client.cpp +++ b/backends/platform/psp/display_client.cpp @@ -18,8 +18,8 @@ * 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/trunk/backends/platform/psp/osys_psp.cpp $ - * $Id: osys_psp.cpp 46126 2009-11-24 14:18:46Z fingolfin $ + * $URL$ + * $Id$ * */ diff --git a/backends/platform/psp/display_manager.cpp b/backends/platform/psp/display_manager.cpp index 2c94882a63..7454211da6 100644 --- a/backends/platform/psp/display_manager.cpp +++ b/backends/platform/psp/display_manager.cpp @@ -18,8 +18,8 @@ * 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/trunk/backends/platform/psp/osys_psp.cpp $ - * $Id: osys_psp.cpp 47541 2010-01-25 01:39:44Z lordhoto $ + * $URL$ + * $Id$ * */ diff --git a/backends/platform/psp/display_manager.h b/backends/platform/psp/display_manager.h index 4537af0096..5c7d4c799a 100644 --- a/backends/platform/psp/display_manager.h +++ b/backends/platform/psp/display_manager.h @@ -18,8 +18,8 @@ * 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/trunk/backends/platform/psp/osys_psp.cpp $ - * $Id: osys_psp.cpp 47541 2010-01-25 01:39:44Z lordhoto $ + * $URL$ + * $Id$ * */ diff --git a/backends/platform/psp/input.cpp b/backends/platform/psp/input.cpp index 0dad31e5ae..665f41504f 100644 --- a/backends/platform/psp/input.cpp +++ b/backends/platform/psp/input.cpp @@ -18,8 +18,8 @@ * 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/trunk/backends/platform/psp/osys_psp.cpp $ - * $Id: osys_psp.cpp 43618 2009-08-21 22:44:49Z joostp $ + * $URL$ + * $Id$ * */ diff --git a/backends/platform/psp/module.mk b/backends/platform/psp/module.mk index cdd0fa0ef5..e3eac153dd 100644 --- a/backends/platform/psp/module.mk +++ b/backends/platform/psp/module.mk @@ -11,7 +11,6 @@ MODULE_OBJS := powerman.o \ input.o \ cursor.o \ trace.o \ - psploader.o \ pspkeyboard.o \ audio.o \ thread.o \ diff --git a/backends/platform/psp/psp_main.cpp b/backends/platform/psp/psp_main.cpp index d24c614e33..019f6c12d1 100644 --- a/backends/platform/psp/psp_main.cpp +++ b/backends/platform/psp/psp_main.cpp @@ -37,7 +37,6 @@ #include <common/system.h> #include <engines/engine.h> #include <base/main.h> -#include <base/plugins.h> #include "backends/platform/psp/powerman.h" #include "backends/platform/psp/thread.h" diff --git a/backends/platform/psp/psploader.cpp b/backends/platform/psp/psploader.cpp deleted file mode 100644 index 464e20770c..0000000000 --- a/backends/platform/psp/psploader.cpp +++ /dev/null @@ -1,732 +0,0 @@ -/* 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$ - * $Id$ - * - */ - -#if defined(DYNAMIC_MODULES) && defined(__PSP__) - -#include <string.h> -#include <stdarg.h> -#include <stdio.h> -#include <malloc.h> -#include <unistd.h> -#include <sys/_default_fcntl.h> - -#include <psputils.h> - -#include "backends/platform/psp/psploader.h" -#include "backends/platform/psp/powerman.h" - -//#define __PSP_DEBUG_FUNCS__ /* For debugging the stack */ -//#define __PSP_DEBUG_PRINT__ - -#include "backends/platform/psp/trace.h" - -extern char __plugin_hole_start; // Indicates start of hole in program file for shorts -extern char __plugin_hole_end; // Indicates end of hole in program file -extern char _gp[]; // Value of gp register - -DECLARE_SINGLETON(ShortSegmentManager) // For singleton - -// Get rid of symbol table in memory -void DLObject::discard_symtab() { - DEBUG_ENTER_FUNC(); - free(_symtab); - free(_strtab); - _symtab = NULL; - _strtab = NULL; - _symbol_cnt = 0; -} - -// Unload all objects from memory -void DLObject::unload() { - DEBUG_ENTER_FUNC(); - discard_symtab(); - free(_segment); - _segment = NULL; - - if (_shortsSegment) { - ShortsMan.deleteSegment(_shortsSegment); - _shortsSegment = NULL; - } -} - -/** - * Follow the instruction of a relocation section. - * - * @param fd File Descriptor - * @param offset Offset into the File - * @param size Size of relocation section - * @param relSegment Base address of relocated segment in memory (memory offset) - * - */ -bool DLObject::relocate(int fd, unsigned long offset, unsigned long size, void *relSegment) { - DEBUG_ENTER_FUNC(); - Elf32_Rel *rel = NULL; // relocation entry - - // Allocate memory for relocation table - if (!(rel = (Elf32_Rel *)malloc(size))) { - PSP_ERROR("Out of memory."); - return false; - } - - // Read in our relocation table - if (lseek(fd, offset, SEEK_SET) < 0 || - read(fd, rel, size) != (ssize_t)size) { - PSP_ERROR("Relocation table load failed."); - free(rel); - return false; - } - - // Treat each relocation entry. Loop over all of them - int cnt = size / sizeof(*rel); - - PSP_DEBUG_PRINT("Loaded relocation table. %d entries. base address=%p\n", cnt, relSegment); - - bool seenHi16 = false; // For treating HI/LO16 commands - int firstHi16 = -1; // Mark the point of the first hi16 seen - Elf32_Addr ahl = 0; // Calculated addend - int a = 0; // Addend: taken from the target - - unsigned int *lastTarget = 0; // For processing hi16 when lo16 arrives - unsigned int relocation = 0; - int debugRelocs[10] = {0}; // For debugging - int extendedHi16 = 0; // Count extended hi16 treatments - Elf32_Addr lastHiSymVal = 0; - bool hi16InShorts = false; - -#define DEBUG_NUM 2 - - // Loop over relocation entries - 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 - unsigned int *target = (unsigned int *)((char *)relSegment + rel[i].r_offset); - - PSP_DEBUG_DO(unsigned int origTarget = *target); // Save for debugging - - // Act differently based on the type of relocation - switch (REL_TYPE(rel[i].r_info)) { - - case R_MIPS_HI16: // Absolute addressing. - if (sym->st_shndx < SHN_LOPROC && // Only shift for plugin section (ie. has a real section index) - firstHi16 < 0) { // Only process first in block of HI16s - firstHi16 = i; // Keep the first Hi16 we saw - seenHi16 = true; - ahl = (*target & 0xffff) << 16; // Take lower 16 bits shifted up - - lastHiSymVal = sym->st_value; - hi16InShorts = (ShortsMan.inGeneralSegment((char *)sym->st_value)); // Fix for problem with switching btw segments - if (debugRelocs[0]++ < DEBUG_NUM) // Print only a set number - PSP_DEBUG_PRINT("R_MIPS_HI16: i=%d, offset=%x, ahl = %x, target = %x\n", - i, rel[i].r_offset, ahl, *target); - } - break; - - case R_MIPS_LO16: // Absolute addressing. Needs a HI16 to come before it - if (sym->st_shndx < SHN_LOPROC) { // Only shift for plugin section. (ie. has a real section index) - if (!seenHi16) { // We MUST have seen HI16 first - PSP_ERROR("R_MIPS_LO16 w/o preceding R_MIPS_HI16 at relocation %d!\n", i); - free(rel); - return false; - } - - // Fix: bug in gcc makes LO16s connect to wrong HI16s sometimes (shorts and regular segment) - // Note that we can check the entire shorts segment because the executable's shorts don't belong to this plugin section - // and will be screened out above - bool lo16InShorts = ShortsMan.inGeneralSegment((char *)sym->st_value); - - // Correct the bug by getting the proper value in ahl (taken from the current symbol) - if ((hi16InShorts && !lo16InShorts) || (!hi16InShorts && lo16InShorts)) { - ahl -= (lastHiSymVal & 0xffff0000); // We assume gcc meant the same offset - ahl += (sym->st_value & 0xffff0000); - } - - ahl &= 0xffff0000; // Clean lower 16 bits for repeated LO16s - a = *target & 0xffff; // Take lower 16 bits of the target - a = (a << 16) >> 16; // Sign extend them - ahl += a; // Add lower 16 bits. AHL is now complete - - // Fix: we can have LO16 access to the short segment sometimes - if (lo16InShorts) { - relocation = ahl + _shortsSegment->getOffset(); // Add in the short segment offset - } else // It's in the regular segment - relocation = ahl + (Elf32_Addr)_segment; // Add in the new offset for the segment - - if (firstHi16 >= 0) { // We haven't treated the HI16s yet so do it now - for (int j = firstHi16; j < i; j++) { - if (REL_TYPE(rel[j].r_info) != R_MIPS_HI16) continue; // Skip over non-Hi16s - - lastTarget = (unsigned int *)((char *)relSegment + rel[j].r_offset); // get hi16 target - *lastTarget &= 0xffff0000; // Clear the lower 16 bits of the last target - *lastTarget |= (relocation >> 16) & 0xffff; // Take the upper 16 bits of the relocation - if (relocation & 0x8000)(*lastTarget)++; // Subtle: we need to add 1 to the HI16 in this case - } - firstHi16 = -1; // Reset so we'll know we treated it - } else { - extendedHi16++; - } - - *target &= 0xffff0000; // Clear the lower 16 bits of current target - *target |= relocation & 0xffff; // Take the lower 16 bits of the relocation - - if (debugRelocs[1]++ < DEBUG_NUM) - PSP_DEBUG_PRINT("R_MIPS_LO16: i=%d, offset=%x, a=%x, ahl = %x, lastTarget = %x, origt = %x, target = %x\n", - i, rel[i].r_offset, a, ahl, *lastTarget, origTarget, *target); - if (lo16InShorts && debugRelocs[2]++ < DEBUG_NUM) - PSP_DEBUG_PRINT("R_MIPS_LO16s: i=%d, offset=%x, a=%x, ahl = %x, lastTarget = %x, origt = %x, target = %x\n", - i, rel[i].r_offset, a, ahl, *lastTarget, origTarget, *target); - } - break; - - case R_MIPS_26: // Absolute addressing (for jumps and branches only) - if (sym->st_shndx < SHN_LOPROC) { // Only relocate for main segment - a = *target & 0x03ffffff; // Get 26 bits' worth of the addend - a = (a << 6) >> 6; // Sign extend a - relocation = ((a << 2) + (Elf32_Addr)_segment) >> 2; // a already points to the target. Subtract our offset - *target &= 0xfc000000; // Clean lower 26 target bits - *target |= (relocation & 0x03ffffff); - - if (debugRelocs[3]++ < DEBUG_NUM) - PSP_DEBUG_PRINT("R_MIPS_26: i=%d, offset=%x, symbol=%d, stinfo=%x, a=%x, origTarget=%x, target=%x\n", - i, rel[i].r_offset, REL_INDEX(rel[i].r_info), sym->st_info, a, origTarget, *target); - } else { - if (debugRelocs[4]++ < DEBUG_NUM) - PSP_DEBUG_PRINT("R_MIPS_26: i=%d, offset=%x, symbol=%d, stinfo=%x, a=%x, origTarget=%x, target=%x\n", - i, rel[i].r_offset, REL_INDEX(rel[i].r_info), sym->st_info, a, origTarget, *target); - } - break; - - case R_MIPS_GPREL16: // GP Relative addressing - if (_shortsSegment->getOffset() != 0 && // Only relocate if we shift the shorts section - ShortsMan.inGeneralSegment((char *)sym->st_value)) { // Only relocate things in the plugin hole - a = *target & 0xffff; // Get 16 bits' worth of the addend - a = (a << 16) >> 16; // Sign extend it - - relocation = a + _shortsSegment->getOffset(); - - *target &= 0xffff0000; // Clear the lower 16 bits of the target - *target |= relocation & 0xffff; - - if (debugRelocs[5]++ < DEBUG_NUM) - PSP_DEBUG_PRINT("R_MIPS_GPREL16: i=%d, a=%x, gpVal=%x, origTarget=%x, target=%x, offset=%x\n", - i, a, _gpVal, origTarget, *target, _shortsSegment->getOffset()); - } - - break; - - case R_MIPS_32: // Absolute addressing - if (sym->st_shndx < SHN_LOPROC) { // Only shift for plugin section. - a = *target; // Get full 32 bits of addend - - if (ShortsMan.inGeneralSegment((char *)sym->st_value)) // Check if we're in the shorts segment - relocation = a + _shortsSegment->getOffset(); // Shift by shorts offset - else // We're in the main section - relocation = a + (Elf32_Addr)_segment; // Shift by main offset - *target = relocation; - - if (debugRelocs[6]++ < DEBUG_NUM) - PSP_DEBUG_PRINT("R_MIPS_32: i=%d, a=%x, origTarget=%x, target=%x\n", i, a, origTarget, *target); - } - break; - - default: - PSP_ERROR("Unknown relocation type %x at relocation %d.\n", REL_TYPE(rel[i].r_info), i); - free(rel); - return false; - } - } - - PSP_DEBUG_PRINT("Done with relocation. extendedHi16=%d\n\n", extendedHi16); - - free(rel); - return true; -} - -bool DLObject::readElfHeader(int fd, Elf32_Ehdr *ehdr) { - DEBUG_ENTER_FUNC(); - // Start reading the elf header. Check for errors - if (read(fd, ehdr, sizeof(*ehdr)) != sizeof(*ehdr) || - memcmp(ehdr->e_ident, ELFMAG, SELFMAG) || // Check MAGIC - ehdr->e_type != ET_EXEC || // Check for executable - ehdr->e_machine != EM_MIPS || // Check for MIPS machine type - ehdr->e_phentsize < sizeof(Elf32_Phdr) || // Check for size of program header - ehdr->e_shentsize != sizeof(Elf32_Shdr)) { // Check for size of section header - PSP_ERROR("Invalid file type."); - return false; - } - - PSP_DEBUG_PRINT("phoff = %d, phentsz = %d, phnum = %d\n", - ehdr->e_phoff, ehdr->e_phentsize, ehdr->e_phnum); - - return true; -} - -bool DLObject::readProgramHeaders(int fd, Elf32_Ehdr *ehdr, Elf32_Phdr *phdr, int num) { - DEBUG_ENTER_FUNC(); - // Read program header - if (lseek(fd, ehdr->e_phoff + sizeof(*phdr)*num, SEEK_SET) < 0 || - read(fd, phdr, sizeof(*phdr)) != sizeof(*phdr)) { - PSP_ERROR("Program header load failed."); - return false; - } - - // Check program header values - if (phdr->p_type != PT_LOAD || phdr->p_filesz > phdr->p_memsz) { - PSP_ERROR("Invalid program header."); - return false; - } - - PSP_DEBUG_PRINT("offs = %x, filesz = %x, memsz = %x, align = %x\n", - phdr->p_offset, phdr->p_filesz, phdr->p_memsz, phdr->p_align); - - return true; - -} - -bool DLObject::loadSegment(int fd, Elf32_Phdr *phdr) { - DEBUG_ENTER_FUNC(); - - char *baseAddress = 0; - - // We need to take account of non-allocated segment for shorts - if (phdr->p_flags & PF_X) { // This is a relocated segment - - // Attempt to allocate memory for segment - int extra = phdr->p_vaddr % phdr->p_align; // Get extra length TODO: check logic here - PSP_DEBUG_PRINT("extra mem is %x\n", extra); - - if (phdr->p_align < 0x10000) phdr->p_align = 0x10000; // Fix for wrong alignment on e.g. AGI - - if (!(_segment = (char *)memalign(phdr->p_align, phdr->p_memsz + extra))) { - PSP_ERROR("Out of memory.\n"); - return false; - } - PSP_DEBUG_PRINT("allocated segment @ %p\n", _segment); - - // Get offset to load segment into - baseAddress = (char *)_segment + phdr->p_vaddr; - _segmentSize = phdr->p_memsz + extra; - } else { // This is a shorts section. - _shortsSegment = ShortsMan.newSegment(phdr->p_memsz, (char *)phdr->p_vaddr); - - baseAddress = _shortsSegment->getStart(); - PSP_DEBUG_PRINT("shorts segment @ %p to %p. Segment wants to be at %x. Offset=%x\n", - _shortsSegment->getStart(), _shortsSegment->getEnd(), phdr->p_vaddr, _shortsSegment->getOffset()); - - } - - // Set bss segment to 0 if necessary (assumes bss is at the end) - if (phdr->p_memsz > phdr->p_filesz) { - PSP_DEBUG_PRINT("Setting %p to %p to 0 for bss\n", baseAddress + phdr->p_filesz, baseAddress + phdr->p_memsz); - memset(baseAddress + phdr->p_filesz, 0, phdr->p_memsz - phdr->p_filesz); - } - // Read the segment into memory - if (lseek(fd, phdr->p_offset, SEEK_SET) < 0 || - read(fd, baseAddress, phdr->p_filesz) != (ssize_t)phdr->p_filesz) { - PSP_ERROR("Segment load failed."); - return false; - } - - return true; -} - - -Elf32_Shdr * DLObject::loadSectionHeaders(int fd, Elf32_Ehdr *ehdr) { - DEBUG_ENTER_FUNC(); - - Elf32_Shdr *shdr = NULL; - - // Allocate memory for section headers - if (!(shdr = (Elf32_Shdr *)malloc(ehdr->e_shnum * sizeof(*shdr)))) { - PSP_ERROR("Out of memory."); - return NULL; - } - - // Read from file into section headers - if (lseek(fd, ehdr->e_shoff, SEEK_SET) < 0 || - read(fd, shdr, ehdr->e_shnum * sizeof(*shdr)) != - (ssize_t)(ehdr->e_shnum * sizeof(*shdr))) { - PSP_ERROR("Section headers load failed."); - return NULL; - } - - return shdr; -} - -int DLObject::loadSymbolTable(int fd, Elf32_Ehdr *ehdr, Elf32_Shdr *shdr) { - DEBUG_ENTER_FUNC(); - - // Loop over sections, looking for symbol table linked to a string table - for (int i = 0; i < ehdr->e_shnum; i++) { - PSP_DEBUG_PRINT("Section %d: type = %x, size = %x, entsize = %x, link = %x\n", - i, shdr[i].sh_type, shdr[i].sh_size, shdr[i].sh_entsize, shdr[i].sh_link); - - if (shdr[i].sh_type == SHT_SYMTAB && - shdr[i].sh_entsize == sizeof(Elf32_Sym) && - shdr[i].sh_link < ehdr->e_shnum && - shdr[shdr[i].sh_link].sh_type == SHT_STRTAB && - _symtab_sect < 0) { - _symtab_sect = i; - } - } - - // Check for no symbol table - if (_symtab_sect < 0) { - PSP_ERROR("No symbol table."); - return -1; - } - - PSP_DEBUG_PRINT("Symbol section at section %d, size %x\n", _symtab_sect, shdr[_symtab_sect].sh_size); - - // Allocate memory for symbol table - if (!(_symtab = malloc(shdr[_symtab_sect].sh_size))) { - PSP_ERROR("Out of memory."); - return -1; - } - - // Read symbol table into memory - if (lseek(fd, shdr[_symtab_sect].sh_offset, SEEK_SET) < 0 || - read(fd, _symtab, shdr[_symtab_sect].sh_size) != - (ssize_t)shdr[_symtab_sect].sh_size) { - PSP_ERROR("Symbol table load failed."); - return -1; - } - - // Set number of symbols - _symbol_cnt = shdr[_symtab_sect].sh_size / sizeof(Elf32_Sym); - PSP_DEBUG_PRINT("Loaded %d symbols.\n", _symbol_cnt); - - return _symtab_sect; - -} - -bool DLObject::loadStringTable(int fd, Elf32_Shdr *shdr) { - DEBUG_ENTER_FUNC(); - - int string_sect = shdr[_symtab_sect].sh_link; - - // Allocate memory for string table - if (!(_strtab = (char *)malloc(shdr[string_sect].sh_size))) { - PSP_ERROR("Out of memory."); - return false; - } - - // Read string table into memory - if (lseek(fd, shdr[string_sect].sh_offset, SEEK_SET) < 0 || - read(fd, _strtab, shdr[string_sect].sh_size) != - (ssize_t)shdr[string_sect].sh_size) { - PSP_ERROR("Symbol table strings load failed."); - return false; - } - return true; -} - -void DLObject::relocateSymbols(Elf32_Addr offset, Elf32_Addr shortsOffset) { - DEBUG_ENTER_FUNC(); - - int shortsCount = 0, othersCount = 0; - PSP_DEBUG_PRINT("Relocating symbols by %x. Shorts offset=%x\n", offset, shortsOffset); - - // Loop over symbols, add relocation offset - Elf32_Sym *s = (Elf32_Sym *)_symtab; - for (int c = _symbol_cnt; c--; s++) { - // Make sure we don't relocate special valued symbols - if (s->st_shndx < SHN_LOPROC) { - if (!ShortsMan.inGeneralSegment((char *)s->st_value)) { - othersCount++; - s->st_value += offset; - if (s->st_value < (Elf32_Addr)_segment || s->st_value > (Elf32_Addr)_segment + _segmentSize) - PSP_ERROR("Symbol out of bounds! st_value = %x\n", s->st_value); - } else { // shorts section - shortsCount++; - s->st_value += shortsOffset; - if (!_shortsSegment->inSegment((char *)s->st_value)) - PSP_ERROR("Symbol out of bounds! st_value = %x\n", s->st_value); - } - - } - - } - - PSP_DEBUG_PRINT("Relocated %d short symbols, %d others.\n", shortsCount, othersCount); -} - -bool DLObject::relocateRels(int fd, Elf32_Ehdr *ehdr, Elf32_Shdr *shdr) { - DEBUG_ENTER_FUNC(); - - // Loop over sections, finding relocation sections - for (int i = 0; i < ehdr->e_shnum; i++) { - - Elf32_Shdr *curShdr = &(shdr[i]); - //Elf32_Shdr *linkShdr = &(shdr[curShdr->sh_info]); - - if (curShdr->sh_type == SHT_REL && // Check for a relocation section - curShdr->sh_entsize == sizeof(Elf32_Rel) && // Check for proper relocation size - (int)curShdr->sh_link == _symtab_sect && // Check that the sh_link connects to our symbol table - curShdr->sh_info < ehdr->e_shnum && // Check that the relocated section exists - (shdr[curShdr->sh_info].sh_flags & SHF_ALLOC)) { // Check if relocated section resides in memory - if (!ShortsMan.inGeneralSegment((char *)shdr[curShdr->sh_info].sh_addr)) { // regular segment - if (!relocate(fd, curShdr->sh_offset, curShdr->sh_size, _segment)) { - return false; - } - } else { // In Shorts segment - if (!relocate(fd, curShdr->sh_offset, curShdr->sh_size, (void *)_shortsSegment->getOffset())) { - return false; - } - } - - } - } - - return true; -} - - -bool DLObject::load(int fd) { - DEBUG_ENTER_FUNC(); - - Elf32_Ehdr ehdr; // ELF header - Elf32_Phdr phdr; // Program header - Elf32_Shdr *shdr; // Section header - bool ret = true; - - if (readElfHeader(fd, &ehdr) == false) { - return false; - } - - for (int i = 0; i < ehdr.e_phnum; i++) { // Load our 2 segments - PSP_DEBUG_PRINT("Loading segment %d\n", i); - - if (readProgramHeaders(fd, &ehdr, &phdr, i) == false) - return false; - - if (!loadSegment(fd, &phdr)) - return false; - } - - if ((shdr = loadSectionHeaders(fd, &ehdr)) == NULL) - ret = false; - - if (ret && ((_symtab_sect = loadSymbolTable(fd, &ehdr, shdr)) < 0)) - ret = false; - - if (ret && (loadStringTable(fd, shdr) == false)) - ret = false; - - if (ret) - relocateSymbols((Elf32_Addr)_segment, _shortsSegment->getOffset()); // Offset by our segment allocated address - - if (ret && (relocateRels(fd, &ehdr, shdr) == false)) - ret = false; - - free(shdr); - - return ret; -} - -bool DLObject::open(const char *path) { - DEBUG_ENTER_FUNC(); - int fd; - void *ctors_start, *ctors_end; - - PSP_DEBUG_PRINT("open(\"%s\")\n", path); - - // Get the address of the global pointer - _gpVal = (unsigned int) & _gp; - PSP_DEBUG_PRINT("_gpVal is %x\n", _gpVal); - - PowerMan.beginCriticalSection(); - - if ((fd = ::open(path, O_RDONLY)) < 0) { - PSP_ERROR("%s not found.", path); - return false; - } - - // Try to load and relocate - if (!load(fd)) { - ::close(fd); - unload(); - return false; - } - - ::close(fd); - - PowerMan.endCriticalSection(); - - // flush data cache - sceKernelDcacheWritebackAll(); - - // Get the symbols for the global constructors and destructors - ctors_start = symbol("___plugin_ctors"); - ctors_end = symbol("___plugin_ctors_end"); - _dtors_start = symbol("___plugin_dtors"); - _dtors_end = symbol("___plugin_dtors_end"); - - if (ctors_start == NULL || ctors_end == NULL || _dtors_start == NULL || - _dtors_end == NULL) { - PSP_ERROR("Missing ctors/dtors."); - _dtors_start = _dtors_end = NULL; - unload(); - return false; - } - - PSP_DEBUG_PRINT("Calling constructors.\n"); - for (void (**f)(void) = (void (**)(void))ctors_start; f != ctors_end; f++) - (**f)(); - - PSP_DEBUG_PRINT("%s opened ok.\n", path); - return true; -} - -bool DLObject::close() { - DEBUG_ENTER_FUNC(); - if (_dtors_start != NULL && _dtors_end != NULL) - for (void (**f)(void) = (void (**)(void))_dtors_start; f != _dtors_end; f++) - (**f)(); - _dtors_start = _dtors_end = NULL; - unload(); - return true; -} - -void *DLObject::symbol(const char *name) { - DEBUG_ENTER_FUNC(); - PSP_DEBUG_PRINT("symbol(\"%s\")\n", name); - - if (_symtab == NULL || _strtab == NULL || _symbol_cnt < 1) { - PSP_ERROR("No symbol table loaded."); - return NULL; - } - - Elf32_Sym *s = (Elf32_Sym *)_symtab; - for (int c = _symbol_cnt; c--; s++) { - - // We can only import symbols that are global or weak in the plugin - if ((SYM_BIND(s->st_info) == STB_GLOBAL || SYM_BIND(s->st_info) == STB_WEAK) && - /*_strtab[s->st_name] == '_' && */ // Try to make this more efficient - !strcmp(name, _strtab + s->st_name)) { - - // We found the symbol - PSP_DEBUG_PRINT("=> %p\n", (void*)s->st_value); - return (void*)s->st_value; - } - } - - PSP_ERROR("Symbol \"%s\" not found.", name); - return NULL; -} - - - -ShortSegmentManager::ShortSegmentManager() { - DEBUG_ENTER_FUNC(); - _shortsStart = &__plugin_hole_start ; - _shortsEnd = &__plugin_hole_end; -} - -ShortSegmentManager::Segment *ShortSegmentManager::newSegment(int size, char *origAddr) { - DEBUG_ENTER_FUNC(); - char *lastAddress = origAddr; - Common::List<Segment *>::iterator i; - - // Find a block that fits, starting from the beginning - for (i = _list.begin(); i != _list.end(); ++i) { - char *currAddress = (*i)->getStart(); - - if ((int)(currAddress - lastAddress) >= size) break; - - lastAddress = (*i)->getEnd(); - } - - if ((Elf32_Addr)lastAddress & 3) - lastAddress += 4 - ((Elf32_Addr)lastAddress & 3); // Round up to multiple of 4 - - if (lastAddress + size > _shortsEnd) { - PSP_ERROR("No space in shorts segment for %x bytes. Last address is %p, max address is %p.\n", - size, lastAddress, _shortsEnd); - return NULL; - } - - Segment *seg = new Segment(lastAddress, size, origAddr); // Create a new segment - - if (lastAddress + size > _highestAddress) _highestAddress = lastAddress + size; // Keep track of maximum - - _list.insert(i, seg); - - PSP_DEBUG_PRINT("Shorts segment size %x allocated. End = %p. Remaining space = %x. Highest so far is %p.\n", - size, lastAddress + size, _shortsEnd - _list.back()->getEnd(), _highestAddress); - - return seg; -} - -void ShortSegmentManager::deleteSegment(ShortSegmentManager::Segment *seg) { - DEBUG_ENTER_FUNC(); - PSP_DEBUG_PRINT("Deleting shorts segment from %p to %p.\n\n", seg->getStart(), seg->getEnd()); - _list.remove(seg); - delete seg; -} - -static char dlerr[MAXDLERRLEN]; - -void *dlopen(const char *filename, int flags) { - DLObject *obj = new DLObject(dlerr); - if (obj->open(filename)) - return (void *)obj; - delete obj; - return NULL; -} - -int dlclose(void *handle) { - DLObject *obj = (DLObject *)handle; - if (obj == NULL) { - strcpy(dlerr, "Handle is NULL."); - return -1; - } - if (obj->close()) { - delete obj; - return 0; - } - return -1; -} - -void *dlsym(void *handle, const char *symbol) { - if (handle == NULL) { - strcpy(dlerr, "Handle is NULL."); - return NULL; - } - return ((DLObject *)handle)->symbol(symbol); -} - -const char *dlerror() { - return dlerr; -} - -void dlforgetsyms(void *handle) { - if (handle != NULL) - ((DLObject *)handle)->discard_symtab(); -} - - -#endif /* DYNAMIC_MODULES && __PSP__ */ diff --git a/backends/platform/psp/psploader.h b/backends/platform/psp/psploader.h deleted file mode 100644 index 13dcf6ef98..0000000000 --- a/backends/platform/psp/psploader.h +++ /dev/null @@ -1,137 +0,0 @@ -/* 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$ - * $Id$ - * - */ - -#ifndef PSPLOADER_H -#define PSPLOADER_H - -#include "elf32.h" -#include "common/list.h" -#include "common/singleton.h" - -#define MAXDLERRLEN 80 - -#define ShortsMan ShortSegmentManager::instance() - -class ShortSegmentManager : public Common::Singleton<ShortSegmentManager> { -private: - char *_shortsStart; - char *_shortsEnd; - -public: - char *getShortsStart() { - return _shortsStart; - } - bool inGeneralSegment(char *addr) { - return ((char *)addr >= _shortsStart && (char *)addr < _shortsEnd); - } - - class Segment { - private: - friend class ShortSegmentManager; - Segment(char *start, int size, char *origAddr) : _startAddress(start), _size(size), _origAddress(origAddr) {} - ~Segment() {} - char *_startAddress; // Start of shorts segment in memory - int _size; // Size of shorts segment - char *_origAddress; // Original address this segment was supposed to be at - public: - char *getStart() { - return _startAddress; - } - char *getEnd() { - return (_startAddress + _size); - } - Elf32_Addr getOffset() { - return (Elf32_Addr)(_startAddress - _origAddress); - } - bool inSegment(char *addr) { - return ((char *)addr >= _startAddress && (char *)addr <= _startAddress + _size); - } - }; - - Segment *newSegment(int size, char *origAddr); - void deleteSegment(Segment *); - -private: - ShortSegmentManager(); - friend class Common::Singleton<ShortSegmentManager>; - Common::List<Segment *> _list; - char *_highestAddress; -}; - - - - -class DLObject { -protected: - char *_errbuf; /* For error messages, at least MAXDLERRLEN in size */ - - ShortSegmentManager::Segment *_shortsSegment; // For assigning shorts ranges - void *_segment, *_symtab; - char *_strtab; - int _symbol_cnt; - int _symtab_sect; - void *_dtors_start, *_dtors_end; - - unsigned int _gpVal; // Value of Global Pointer - int _segmentSize; - - void seterror(const char *fmt, ...); - void unload(); - bool relocate(int fd, unsigned long offset, unsigned long size, void *); - bool load(int fd); - - bool readElfHeader(int fd, Elf32_Ehdr *ehdr); - bool readProgramHeaders(int fd, Elf32_Ehdr *ehdr, Elf32_Phdr *phdr, int num); - bool loadSegment(int fd, Elf32_Phdr *phdr); - Elf32_Shdr *loadSectionHeaders(int fd, Elf32_Ehdr *ehdr); - int loadSymbolTable(int fd, Elf32_Ehdr *ehdr, Elf32_Shdr *shdr); - bool loadStringTable(int fd, Elf32_Shdr *shdr); - void relocateSymbols(Elf32_Addr offset, Elf32_Addr shortsOffset); - bool relocateRels(int fd, Elf32_Ehdr *ehdr, Elf32_Shdr *shdr); - -public: - bool open(const char *path); - bool close(); - void *symbol(const char *name); - void discard_symtab(); - - DLObject(char *errbuf = NULL) : _errbuf(_errbuf), _shortsSegment(NULL), _segment(NULL), _symtab(NULL), - _strtab(NULL), _symbol_cnt(0), _symtab_sect(-1), _dtors_start(NULL), _dtors_end(NULL), _gpVal(0) , - _segmentSize(0) {} -}; - - - -#define RTLD_LAZY 0 - -extern "C" { - void *dlopen(const char *filename, int flags); - int dlclose(void *handle); - void *dlsym(void *handle, const char *symbol); - const char *dlerror(); - void dlforgetsyms(void *handle); -} - -#endif /* PSPLOADER_H */ diff --git a/backends/platform/psp/thread.cpp b/backends/platform/psp/thread.cpp index f9e497a342..3e1303a4e6 100644 --- a/backends/platform/psp/thread.cpp +++ b/backends/platform/psp/thread.cpp @@ -18,8 +18,8 @@ * 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/trunk/backends/platform/psp/osys_psp.h $ - * $Id: osys_psp.h 49173 2010-05-24 03:05:17Z bluddy $ + * $URL$ + * $Id$ * */ diff --git a/backends/platform/psp/thread.h b/backends/platform/psp/thread.h index bbad2a9ead..1ca6ef5c42 100644 --- a/backends/platform/psp/thread.h +++ b/backends/platform/psp/thread.h @@ -18,8 +18,8 @@ * 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/trunk/backends/platform/psp/portdefs.h $ - * $Id: portdefs.h 38687 2009-02-21 12:08:52Z joostp $ + * $URL$ + * $Id$ * */ diff --git a/backends/platform/wii/main.cpp b/backends/platform/wii/main.cpp index 7f141f2339..aa688534fc 100644 --- a/backends/platform/wii/main.cpp +++ b/backends/platform/wii/main.cpp @@ -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(); diff --git a/backends/platform/wii/wii.mk b/backends/platform/wii/wii.mk index c1512551d7..28066df8d4 100644 --- a/backends/platform/wii/wii.mk +++ b/backends/platform/wii/wii.mk @@ -32,6 +32,10 @@ else $(CP) $(srcdir)/dists/wii/icon.png wiidist/scummvm/ sed "s/@REVISION@/$(VER_SVNREV)/;s/@TIMESTAMP@/`date +%Y%m%d%H%M%S`/" < $(srcdir)/dists/wii/meta.xml > wiidist/scummvm/meta.xml endif +ifeq ($(DYNAMIC_MODULES),1) + $(MKDIR) wiidist/scummvm/plugins + for i in $(PLUGINS); do $(STRIP) --strip-debug $$i -o wiidist/scummvm/plugins/`basename $$i`; done +endif sed 's/$$/\r/' < $(srcdir)/dists/wii/READMII > wiidist/scummvm/READMII.txt for i in $(DIST_FILES_DOCS); do sed 's/$$/\r/' < $$i > wiidist/scummvm/`basename $$i`.txt; done $(CP) $(DIST_FILES_THEMES) wiidist/scummvm/ diff --git a/backends/plugins/ds/ds-provider.cpp b/backends/plugins/ds/ds-provider.cpp new file mode 100644 index 0000000000..c188b6c9df --- /dev/null +++ b/backends/plugins/ds/ds-provider.cpp @@ -0,0 +1,75 @@ +/* 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$ + * $Id$ + * + */ + +#if defined(DYNAMIC_MODULES) && defined(__DS__) + +#include <malloc.h> +#include <nds.h> + +#include "backends/plugins/ds/ds-provider.h" +#include "backends/plugins/elf/arm-loader.h" + +class DSDLObject : public ARMDLObject { +public: + DSDLObject() : + ARMDLObject() { + } + + virtual ~DSDLObject() { + unload(); + } + +protected: + virtual void *allocSegment(size_t boundary, size_t size) const { + return memalign(boundary, size); + } + + virtual void freeSegment(void *segment) const { + free(segment); + } + + virtual void flushDataCache(void *ptr, uint32 len) const { + DC_FlushRange(ptr, len); + IC_InvalidateRange(ptr, len); + } +}; + +class DSPlugin : public ELFPlugin { +public: + DSPlugin(const Common::String &filename) : + ELFPlugin(filename) { + } + + virtual DLObject *makeDLObject() { + return new DSDLObject(); + } +}; + +Plugin *DSPluginProvider::createPlugin(const Common::FSNode &node) const { + return new DSPlugin(node.getPath()); +} + +#endif // defined(DYNAMIC_MODULES) && defined(__DS__) + diff --git a/backends/plugins/ds/ds-provider.h b/backends/plugins/ds/ds-provider.h new file mode 100644 index 0000000000..dcb93c085f --- /dev/null +++ b/backends/plugins/ds/ds-provider.h @@ -0,0 +1,41 @@ +/* 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$ + * $Id$ + * + */ + +#if defined(DYNAMIC_MODULES) && defined(__DS__) + +#ifndef BACKENDS_PLUGINS_DS_PROVIDER_H +#define BACKENDS_PLUGINS_DS_PROVIDER_H + +#include "backends/plugins/elf/elf-provider.h" + +class DSPluginProvider : public ELFPluginProvider { +public: + Plugin *createPlugin(const Common::FSNode &node) const; +}; + +#endif // BACKENDS_PLUGINS_DS_PROVIDER_H + +#endif // defined(DYNAMIC_MODULES) && defined(__DS__) + diff --git a/backends/plugins/ds/plugin.ld b/backends/plugins/ds/plugin.ld new file mode 100644 index 0000000000..04035b0169 --- /dev/null +++ b/backends/plugins/ds/plugin.ld @@ -0,0 +1,217 @@ +OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", "elf32-littlearm") +OUTPUT_ARCH(arm) + +/* PHDRS specifies ELF Program Headers (or segments) to the plugin linker */ +PHDRS { + plugin PT_LOAD ; /* Specifies that the plugin segment should be loaded from file */ +} + +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + . = 0; + .interp : { *(.interp) } : plugin + .note.gnu.build-id : { *(.note.gnu.build-id) } + .hash : { *(.hash) } + .gnu.hash : { *(.gnu.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .gnu.version : { *(.gnu.version) } + .gnu.version_d : { *(.gnu.version_d) } + .gnu.version_r : { *(.gnu.version_r) } + .rel.dyn : + { + *(.rel.init) + *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) + *(.rel.fini) + *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) + *(.rel.data.rel.ro* .rel.gnu.linkonce.d.rel.ro.*) + *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*) + *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*) + *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*) + *(.rel.ctors) + *(.rel.dtors) + *(.rel.got) + *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) + PROVIDE_HIDDEN (__rel_iplt_start = .); + *(.rel.iplt) + PROVIDE_HIDDEN (__rel_iplt_end = .); + PROVIDE_HIDDEN (__rela_iplt_start = .); + PROVIDE_HIDDEN (__rela_iplt_end = .); + } + .rela.dyn : + { + *(.rela.init) + *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) + *(.rela.fini) + *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) + *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) + *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) + *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) + *(.rela.ctors) + *(.rela.dtors) + *(.rela.got) + *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) + PROVIDE_HIDDEN (__rel_iplt_start = .); + PROVIDE_HIDDEN (__rel_iplt_end = .); + PROVIDE_HIDDEN (__rela_iplt_start = .); + *(.rela.iplt) + PROVIDE_HIDDEN (__rela_iplt_end = .); + } + .rel.plt : + { + *(.rel.plt) + } + .rela.plt : + { + *(.rela.plt) + } + .init : + { + KEEP (*(.init)) + } =0 + .plt : { *(.plt) } + .iplt : { *(.iplt) } + .text : + { + *(.text.unlikely .text.*_unlikely) + *(.text .stub .text.* .gnu.linkonce.t.*) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + *(.glue_7t) *(.glue_7) *(.vfp11_veneer) *(.v4_bx) + } =0 + .fini : + { + KEEP (*(.fini)) + } =0 + PROVIDE (__etext = .); + PROVIDE (_etext = .); + PROVIDE (etext = .); + .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } + .rodata1 : { *(.rodata1) } + .ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } + __exidx_start = .; + .ARM.exidx : { *(.ARM.exidx* .gnu.linkonce.armexidx.*) } + __exidx_end = .; + .eh_frame_hdr : { *(.eh_frame_hdr) } + .eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) } + .gcc_except_table : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) } + /* Adjust the address for the data segment. We want to adjust up to + the same address within the page on the next page up. */ + . = ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)); + /* Exception handling */ + .eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) } + .gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) } + /* Thread Local Storage sections */ + .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) } + .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } + .preinit_array : + { + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + } + .init_array : + { + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + PROVIDE_HIDDEN (__init_array_end = .); + } + .fini_array : + { + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(.fini_array)) + KEEP (*(SORT(.fini_array.*))) + PROVIDE_HIDDEN (__fini_array_end = .); + } + .ctors : + { + ___plugin_ctors = .; + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + ___plugin_ctors_end = .; + } + .dtors : + { + ___plugin_dtors = .; + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + ___plugin_dtors_end = .; + } + .jcr : { KEEP (*(.jcr)) } + .data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro* .gnu.linkonce.d.rel.ro.*) } + .dynamic : { *(.dynamic) } + .got : { *(.got.plt) *(.igot.plt) *(.got) *(.igot) } + .data : + { + __data_start = . ; + *(.data .data.* .gnu.linkonce.d.*) + SORT(CONSTRUCTORS) + } + .data1 : { *(.data1) } + _edata = .; PROVIDE (edata = .); + __bss_start = .; + __bss_start__ = .; + .bss : + { + *(.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. + FIXME: Why do we need it? When there is no .bss section, we don't + pad the .data section. */ + . = ALIGN(. != 0 ? 32 / 8 : 1); + } + _bss_end__ = . ; __bss_end__ = . ; + . = ALIGN(32 / 8); + . = ALIGN(32 / 8); + __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 .gnu.linkonce.wi.*) } + .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) } + /* DWARF 3 */ + .debug_pubtypes 0 : { *(.debug_pubtypes) } + .debug_ranges 0 : { *(.debug_ranges) } + .stack 0x80000 : + { + _stack = .; + *(.stack) + } + .ARM.attributes 0 : { KEEP (*(.ARM.attributes)) KEEP (*(.gnu.attributes)) } + .note.gnu.arm.ident 0 : { KEEP (*(.note.gnu.arm.ident)) } + /DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) } +} diff --git a/backends/plugins/dynamic-plugin.h b/backends/plugins/dynamic-plugin.h index ec051c4ed7..0c6a797947 100644 --- a/backends/plugins/dynamic-plugin.h +++ b/backends/plugins/dynamic-plugin.h @@ -28,7 +28,6 @@ #include "base/plugins.h" - class DynamicPlugin : public Plugin { protected: typedef int32 (*IntFunc)(); @@ -45,6 +44,7 @@ public: unloadPlugin(); return false; } + if (verFunc() != PLUGIN_VERSION) { warning("Plugin uses a different API version (you have: '%d', needed is: '%d')", verFunc(), PLUGIN_VERSION); unloadPlugin(); @@ -57,6 +57,7 @@ public: unloadPlugin(); return false; } + _type = (PluginType)typeFunc(); if (_type >= PLUGIN_TYPE_MAX) { warning("Plugin type unknown: %d", _type); @@ -70,6 +71,7 @@ public: unloadPlugin(); return false; } + if (typeVerFunc() != pluginTypeVersions[_type]) { warning("Plugin uses a different type API version (you have: '%d', needed is: '%d')", typeVerFunc(), pluginTypeVersions[_type]); unloadPlugin(); diff --git a/backends/plugins/elf/arm-loader.cpp b/backends/plugins/elf/arm-loader.cpp new file mode 100644 index 0000000000..93d3c60f84 --- /dev/null +++ b/backends/plugins/elf/arm-loader.cpp @@ -0,0 +1,133 @@ +/* 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$ + * $Id$ + * + */ + +#include "common/scummsys.h" + +#if defined(DYNAMIC_MODULES) && defined(USE_ELF_LOADER) && defined(ARM_TARGET) + +#include "backends/plugins/elf/arm-loader.h" + +#include "common/debug.h" + +bool ARMDLObject::relocate(Elf32_Off offset, Elf32_Word size, byte *relSegment) { + Elf32_Rel *rel = 0; //relocation entry + + // Allocate memory for relocation table + if (!(rel = (Elf32_Rel *)malloc(size))) { + warning("elfloader: Out of memory."); + return false; + } + + // Read in our relocation table + if (!_file->seek(offset, SEEK_SET) || _file->read(rel, size) != size) { + warning("elfloader: Relocation table load failed."); + free(rel); + return false; + } + + // Treat each relocation entry. Loop over all of them + uint32 cnt = size / sizeof(*rel); + + debug(2, "elfloader: Loaded relocation table. %d entries. base address=%p", cnt, relSegment); + + int32 a = 0; + uint32 relocation = 0; + + // Loop over relocation entries + for (uint32 i = 0; i < cnt; i++) { + // Get the symbol this relocation entry is referring to + Elf32_Sym *sym = _symtab + (REL_INDEX(rel[i].r_info)); + + // Get the target instruction in the code. TODO: repect _segmentVMA + uint32 *target = (uint32 *)((byte *)relSegment + rel[i].r_offset); + + uint32 origTarget = *target; //Save for debugging + + // Act differently based on the type of relocation + switch (REL_TYPE(rel[i].r_info)) { + case R_ARM_ABS32: + if (sym->st_shndx < SHN_LOPROC) { // Only shift for plugin section. + a = *target; // Get full 32 bits of addend + relocation = a + Elf32_Addr(_segment); // Shift by main offset + + *target = relocation; + + debug(8, "elfloader: R_ARM_ABS32: i=%d, a=%x, origTarget=%x, target=%x", i, a, origTarget, *target); + } + break; + + case R_ARM_THM_CALL: + debug(8, "elfloader: R_ARM_THM_CALL: PC-relative jump, ld takes care of necessary relocation work for us."); + break; + + case R_ARM_CALL: + debug(8, "elfloader: R_ARM_CALL: PC-relative jump, ld takes care of necessary relocation work for us."); + break; + + case R_ARM_JUMP24: + debug(8, "elfloader: R_ARM_JUMP24: PC-relative jump, ld takes care of all relocation work for us."); + break; + + case R_ARM_V4BX: + debug(8, "elfloader: R_ARM_V4BX: No relocation calculation necessary."); + break; + + default: + warning("elfloader: Unknown relocation type %d.", REL_TYPE(rel[i].r_info)); + free(rel); + return false; + } + } + + free(rel); + return true; +} + +bool ARMDLObject::relocateRels(Elf32_Ehdr *ehdr, Elf32_Shdr *shdr) { + // Loop over sections, finding relocation sections + for (uint32 i = 0; i < ehdr->e_shnum; i++) { + Elf32_Shdr *curShdr = &(shdr[i]); + + if ((curShdr->sh_type == SHT_REL || curShdr->sh_type == SHT_RELA) && // Check for a relocation section + curShdr->sh_entsize == sizeof(Elf32_Rel) && // Check for proper relocation size + int32(curShdr->sh_link) == _symtab_sect && // Check that the sh_link connects to our symbol table + curShdr->sh_info < ehdr->e_shnum && // Check that the relocated section exists + (shdr[curShdr->sh_info].sh_flags & SHF_ALLOC)) { // Check if relocated section resides in memory + + if (curShdr->sh_type == SHT_RELA) { + warning("elfloader: RELA entries not supported yet!"); + return false; + } + + if (!relocate(curShdr->sh_offset, curShdr->sh_size, _segment)) + return false; + } + } + + return true; +} + +#endif /* defined(DYNAMIC_MODULES) && defined(USE_ELF_LOADER) && defined(ARM_TARGET) */ + diff --git a/backends/plugins/elf/arm-loader.h b/backends/plugins/elf/arm-loader.h new file mode 100644 index 0000000000..e08f8cd0a5 --- /dev/null +++ b/backends/plugins/elf/arm-loader.h @@ -0,0 +1,49 @@ +/* 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$ + * $Id$ + * + */ + +#ifndef BACKENDS_PLUGINS_ARM_LOADER_H +#define BACKENDS_PLUGINS_ARM_LOADER_H + +#include "common/scummsys.h" + +#if defined(DYNAMIC_MODULES) && defined(USE_ELF_LOADER) && defined(ARM_TARGET) + +#include "backends/plugins/elf/elf-loader.h" + +class ARMDLObject : public DLObject { +protected: + virtual bool relocate(Elf32_Off offset, Elf32_Word size, byte *relSegment); + virtual bool relocateRels(Elf32_Ehdr *ehdr, Elf32_Shdr *shdr); + +public: + ARMDLObject() : + DLObject() { + } +}; + +#endif /* defined(DYNAMIC_MODULES) && defined(USE_ELF_LOADER) && defined(ARM_TARGET) */ + +#endif /* BACKENDS_PLUGINS_ARM_LOADER_H */ + diff --git a/backends/plugins/elf/elf-loader.cpp b/backends/plugins/elf/elf-loader.cpp new file mode 100644 index 0000000000..17a67f4d02 --- /dev/null +++ b/backends/plugins/elf/elf-loader.cpp @@ -0,0 +1,429 @@ +/* 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$ + * $Id$ + * + */ + +#include "common/scummsys.h" + +#if defined(DYNAMIC_MODULES) && defined(USE_ELF_LOADER) + +#include "backends/plugins/elf/elf-loader.h" + +#include "common/debug.h" +#include "common/file.h" +#include "common/fs.h" +#include "common/ptr.h" + +DLObject::DLObject() : + _file(0), + _segment(0), + _symtab(0), + _strtab(0), + _segmentSize(0), + _segmentOffset(0), + _segmentVMA(0), + _symbol_cnt(0), + _symtab_sect(-1), + _dtors_start(0), + _dtors_end(0) { +} + +DLObject::~DLObject() { +} + +// Expel the symbol table from memory +void DLObject::discard_symtab() { + free(_symtab); + _symtab = 0; + + free(_strtab); + _strtab = 0; + + _symbol_cnt = 0; +} + +// Unload all objects from memory +void DLObject::unload() { + discard_symtab(); + + freeSegment(_segment); + + _segment = 0; + _segmentSize = 0; + _segmentOffset = 0; + _segmentVMA = 0; +} + +bool DLObject::readElfHeader(Elf32_Ehdr *ehdr) { + assert(_file); + + // Start reading the elf header. Check for errors and magic + if (_file->read(ehdr, sizeof(*ehdr)) != sizeof(*ehdr) || + memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) { + warning("elfloader: No ELF file."); + return false; + } + + if (ehdr->e_ident[EI_CLASS] != ELFCLASS32) { + warning("elfloader: Wrong ELF file class."); + return false; + } + + if (ehdr->e_ident[EI_DATA] != +#ifdef SCUMM_BIG_ENDIAN + ELFDATA2MSB +#else + ELFDATA2LSB +#endif + ) { + warning("elfloader: Wrong ELF file endianess."); + return false; + } + + if (ehdr->e_ident[EI_VERSION] != EV_CURRENT) { + warning("elfloader: Wrong ELF file version."); + return false; + } + + if (ehdr->e_type != ET_EXEC) { + warning("elfloader: No executable ELF file."); + return false; + } + + if (ehdr->e_machine != +#ifdef ARM_TARGET + EM_ARM +#endif +#ifdef MIPS_TARGET + EM_MIPS +#endif +#ifdef PPC_TARGET + EM_PPC +#endif + ) { + warning("elfloader: Wrong ELF file architecture."); + return false; + } + + if (ehdr->e_phentsize < sizeof(Elf32_Phdr) || // Check for size of program header + ehdr->e_shentsize != sizeof(Elf32_Shdr)) { // Check for size of section header + warning("elfloader: Invalid ELF structure sizes."); + return false; + } + + debug(2, "elfloader: phoff = %d, phentsz = %d, phnum = %d", + ehdr->e_phoff, ehdr->e_phentsize, ehdr->e_phnum); + + return true; +} + +bool DLObject::readProgramHeaders(Elf32_Ehdr *ehdr, Elf32_Phdr *phdr, Elf32_Half num) { + assert(_file); + + // Read program header + if (!_file->seek(ehdr->e_phoff + sizeof(*phdr) * num, SEEK_SET) || + _file->read(phdr, sizeof(*phdr)) != sizeof(*phdr)) { + warning("elfloader: Program header load failed."); + return false; + } + + // Check program header values + if (phdr->p_type != PT_LOAD || phdr->p_filesz > phdr->p_memsz) { + warning("elfloader: Invalid program header."); + return false; + } + + debug(2, "elfloader: offs = %x, filesz = %x, memsz = %x, align = %x", + phdr->p_offset, phdr->p_filesz, phdr->p_memsz, phdr->p_align); + + return true; +} + +bool DLObject::loadSegment(Elf32_Phdr *phdr) { + _segment = (byte *)allocSegment(phdr->p_align, phdr->p_memsz); + + if (!_segment) { + warning("elfloader: Out of memory."); + return false; + } + + debug(2, "elfloader: Allocated segment @ %p", _segment); + + // Get offset to load segment into + _segmentSize = phdr->p_memsz; + _segmentVMA = phdr->p_vaddr; + + // Set .bss segment to 0 if necessary + if (phdr->p_memsz > phdr->p_filesz) { + debug(2, "elfloader: Setting %p to %p to 0 for bss", + _segment + phdr->p_filesz, _segment + phdr->p_memsz); + memset(_segment + phdr->p_filesz, 0, phdr->p_memsz - phdr->p_filesz); + } + + debug(2, "elfloader: Reading the segment into memory"); + + // Read the segment into memory + if (!_file->seek(phdr->p_offset, SEEK_SET) || + _file->read(_segment, phdr->p_filesz) != phdr->p_filesz) { + warning("elfloader: Segment load failed."); + return false; + } + + debug(2, "elfloader: Segment has been read into memory"); + + return true; +} + +Elf32_Shdr * DLObject::loadSectionHeaders(Elf32_Ehdr *ehdr) { + assert(_file); + + Elf32_Shdr *shdr = 0; + + // Allocate memory for section headers + if (!(shdr = (Elf32_Shdr *)malloc(ehdr->e_shnum * sizeof(*shdr)))) { + warning("elfloader: Out of memory."); + return 0; + } + + // Read from file into section headers + if (!_file->seek(ehdr->e_shoff, SEEK_SET) || + _file->read(shdr, ehdr->e_shnum * sizeof(*shdr)) != + ehdr->e_shnum * sizeof(*shdr)) { + warning("elfloader: Section headers load failed."); + free(shdr); + return 0; + } + + return shdr; +} + +int DLObject::loadSymbolTable(Elf32_Ehdr *ehdr, Elf32_Shdr *shdr) { + assert(_file); + + // Loop over sections, looking for symbol table linked to a string table + for (uint32 i = 0; i < ehdr->e_shnum; i++) { + if (shdr[i].sh_type == SHT_SYMTAB && + shdr[i].sh_entsize == sizeof(Elf32_Sym) && + shdr[i].sh_link < ehdr->e_shnum && + shdr[shdr[i].sh_link].sh_type == SHT_STRTAB && + _symtab_sect < 0) { + _symtab_sect = i; + } + } + + // Check for no symbol table + if (_symtab_sect < 0) { + warning("elfloader: No symbol table."); + return -1; + } + + debug(2, "elfloader: Symbol section at section %d, size %x", + _symtab_sect, shdr[_symtab_sect].sh_size); + + // Allocate memory for symbol table + if (!(_symtab = (Elf32_Sym *)malloc(shdr[_symtab_sect].sh_size))) { + warning("elfloader: Out of memory."); + return -1; + } + + // Read symbol table into memory + if (!_file->seek(shdr[_symtab_sect].sh_offset, SEEK_SET) || + _file->read(_symtab, shdr[_symtab_sect].sh_size) != + shdr[_symtab_sect].sh_size) { + warning("elfloader: Symbol table load failed."); + free(_symtab); + _symtab = 0; + return -1; + } + + // Set number of symbols + _symbol_cnt = shdr[_symtab_sect].sh_size / sizeof(Elf32_Sym); + debug(2, "elfloader: Loaded %d symbols.", _symbol_cnt); + + return _symtab_sect; +} + +bool DLObject::loadStringTable(Elf32_Shdr *shdr) { + assert(_file); + + uint32 string_sect = shdr[_symtab_sect].sh_link; + + // Allocate memory for string table + if (!(_strtab = (char *)malloc(shdr[string_sect].sh_size))) { + warning("elfloader: Out of memory."); + return false; + } + + // Read string table into memory + if (!_file->seek(shdr[string_sect].sh_offset, SEEK_SET) || + _file->read(_strtab, shdr[string_sect].sh_size) != + shdr[string_sect].sh_size) { + warning("elfloader: Symbol table strings load failed."); + free(_strtab); + _strtab = 0; + return false; + } + + return true; +} + +void DLObject::relocateSymbols(ptrdiff_t offset) { + // Loop over symbols, add relocation offset + Elf32_Sym *s = _symtab; + + for (uint32 c = _symbol_cnt; c--; s++) { + // Make sure we don't relocate special valued symbols + if (s->st_shndx < SHN_LOPROC) { + s->st_value += offset; + + if (s->st_value < Elf32_Addr(_segment) || + s->st_value > Elf32_Addr(_segment) + _segmentSize) + warning("elfloader: Symbol out of bounds! st_value = %x", s->st_value); + } + } +} + +bool DLObject::load() { + Elf32_Ehdr ehdr; + Elf32_Phdr phdr; + + if (readElfHeader(&ehdr) == false) + return false; + + for (uint32 i = 0; i < ehdr.e_phnum; i++) { //Load our segments + debug(2, "elfloader: Loading segment %d", i); + + if (readProgramHeaders(&ehdr, &phdr, i) == false) + return false; + + if (!loadSegment(&phdr)) + return false; + } + + Common::ScopedPtrC<Elf32_Shdr> shdr(loadSectionHeaders(&ehdr)); + if (!shdr) + return false; + + _symtab_sect = loadSymbolTable(&ehdr, shdr); + if (_symtab_sect < 0) + return false; + + if (!loadStringTable(shdr)) + return false; + + // Offset by our segment allocated address + // must use _segmentVMA here for multiple segments (MIPS) + _segmentOffset = ptrdiff_t(_segment) - _segmentVMA; + relocateSymbols(_segmentOffset); + + if (!relocateRels(&ehdr, shdr)) + return false; + + return true; +} + +bool DLObject::open(const char *path) { + void *ctors_start, *ctors_end; + + debug(2, "elfloader: open(\"%s\")", path); + + _file = Common::FSNode(path).createReadStream(); + + if (!_file) { + warning("elfloader: File %s not found.", path); + return false; + } + + debug(2, "elfloader: %s found!", path); + + /*Try to load and relocate*/ + if (!load()) { + unload(); + return false; + } + + debug(2, "elfloader: Loaded!"); + + delete _file; + _file = 0; + + flushDataCache(_segment, _segmentSize); + + ctors_start = symbol("___plugin_ctors"); + ctors_end = symbol("___plugin_ctors_end"); + _dtors_start = symbol("___plugin_dtors"); + _dtors_end = symbol("___plugin_dtors_end"); + + if (!ctors_start || !ctors_end || !_dtors_start || !_dtors_end) { + warning("elfloader: Missing ctors/dtors."); + _dtors_start = _dtors_end = 0; + unload(); + return false; + } + + debug(2, "elfloader: Calling constructors."); + for (void (**f)(void) = (void (**)(void))ctors_start; f != ctors_end; f++) + (**f)(); + + debug(2, "elfloader: %s opened ok.", path); + + return true; +} + +bool DLObject::close() { + if (_dtors_start && _dtors_end) + for (void (**f)(void) = (void (**)(void))_dtors_start; f != _dtors_end; f++) + (**f)(); + + _dtors_start = _dtors_end = 0; + unload(); + return true; +} + +void *DLObject::symbol(const char *name) { + debug(2, "elfloader: Symbol(\"%s\")", name); + + if (!_symtab || !_strtab || _symbol_cnt < 1) { + warning("elfloader: No symbol table loaded."); + return 0; + } + + Elf32_Sym *s = _symtab; + + for (uint32 c = _symbol_cnt; c--; s++) + // We can only import symbols that are global or weak in the plugin + if ((SYM_BIND(s->st_info) == STB_GLOBAL || + SYM_BIND(s->st_info) == STB_WEAK) && + !strcmp(name, _strtab + s->st_name)) { + // We found the symbol + debug(2, "elfloader: => 0x%08x", s->st_value); + return (void*)s->st_value; + } + + // We didn't find the symbol + warning("elfloader: Symbol \"%s\" not found.", name); + return 0; +} + +#endif /* defined(DYNAMIC_MODULES) && defined(USE_ELF_LOADER) */ + diff --git a/backends/plugins/elf/elf-loader.h b/backends/plugins/elf/elf-loader.h new file mode 100644 index 0000000000..87907d67c9 --- /dev/null +++ b/backends/plugins/elf/elf-loader.h @@ -0,0 +1,104 @@ +/* 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$ + * $Id$ + * + */ + +#ifndef BACKENDS_PLUGINS_ELF_LOADER_H +#define BACKENDS_PLUGINS_ELF_LOADER_H + +#include "common/scummsys.h" + +#if defined(DYNAMIC_MODULES) && defined(USE_ELF_LOADER) + +#include <stddef.h> + +#include "backends/plugins/elf/elf32.h" +#include "backends/plugins/dynamic-plugin.h" + +#include "common/stream.h" + +/** + * DLObject + * + * Class that most directly handles operations on a plugin file + * (opening it for reading, loading/unloading it in memory, finding a specific symbol in the file, etc.) + * Subclasses have the same functionality, but implementations specific to different processors/platforms. + */ +class DLObject { +protected: + Common::SeekableReadStream *_file; + + byte *_segment; + Elf32_Sym *_symtab; + char *_strtab; + + uint32 _segmentSize; + ptrdiff_t _segmentOffset; + uint32 _segmentVMA; + + uint32 _symbol_cnt; + int32 _symtab_sect; + void *_dtors_start, *_dtors_end; + + virtual void unload(); + bool load(); + + bool readElfHeader(Elf32_Ehdr *ehdr); + bool readProgramHeaders(Elf32_Ehdr *ehdr, Elf32_Phdr *phdr, Elf32_Half num); + virtual bool loadSegment(Elf32_Phdr *phdr); + Elf32_Shdr *loadSectionHeaders(Elf32_Ehdr *ehdr); + int loadSymbolTable(Elf32_Ehdr *ehdr, Elf32_Shdr *shdr); + bool loadStringTable(Elf32_Shdr *shdr); + virtual void relocateSymbols(ptrdiff_t offset); + + // architecture specific + + /** + * Follow the instruction of a relocation section. + * + * @param fileOffset Offset into the File + * @param size Size of relocation section + * @param relSegment Base address of relocated segment in memory (memory offset) + */ + virtual bool relocate(Elf32_Off offset, Elf32_Word size, byte *relSegment) = 0; + virtual bool relocateRels(Elf32_Ehdr *ehdr, Elf32_Shdr *shdr) = 0; + + // platform specific + virtual void *allocSegment(size_t boundary, size_t size) const = 0; + virtual void freeSegment(void *segment) const = 0; + virtual void flushDataCache(void *ptr, uint32 len) const = 0; + +public: + DLObject(); + virtual ~DLObject(); + + bool open(const char *path); + bool close(); + void *symbol(const char *name); + void discard_symtab(); +}; + +#endif /* defined(DYNAMIC_MODULES) && defined(USE_ELF_LOADER) */ + +#endif /* BACKENDS_PLUGINS_ELF_LOADER_H */ + diff --git a/backends/plugins/elf/elf-provider.cpp b/backends/plugins/elf/elf-provider.cpp new file mode 100644 index 0000000000..d1c8f6aa05 --- /dev/null +++ b/backends/plugins/elf/elf-provider.cpp @@ -0,0 +1,177 @@ +/* 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$ + * $Id$ + * + */ + +#include "common/scummsys.h" + +#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 "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; + + if (_dlHandle) + func = _dlHandle->symbol(symbol); + + if (!func) { + if (!_dlHandle) + warning("elfloader: Failed loading symbol '%s' from plugin '%s' (Handle is NULL)", symbol, _filename.c_str()); + else + warning("elfloader: Failed loading symbol '%s' from plugin '%s'", symbol, _filename.c_str()); + } + + // FIXME HACK: This is a HACK to circumvent a clash between the ISO C++ + // standard and POSIX: ISO C++ disallows casting between function pointers + // and data pointers, but dlsym always returns a void pointer. For details, + // see e.g. <http://www.trilithium.com/johan/2004/12/problem-with-dlsym/>. + assert(sizeof(VoidFunc) == sizeof(func)); + VoidFunc tmp; + memcpy(&tmp, &func, sizeof(VoidFunc)); + return tmp; +} + +bool ELFPlugin::loadPlugin() { + assert(!_dlHandle); + + DLObject *obj = makeDLObject(); + if (obj->open(_filename.c_str())) { + _dlHandle = obj; + } else { + delete obj; + _dlHandle = 0; + } + + if (!_dlHandle) { + warning("elfloader: Failed loading plugin '%s'", _filename.c_str()); + return false; + } + + CharFunc buildDateFunc = (CharFunc)findSymbol("PLUGIN_getBuildDate"); + if (!buildDateFunc) { + unloadPlugin(); + warning("elfloader: plugin '%s' is missing symbols", _filename.c_str()); + return false; + } + + if (strncmp(gScummVMPluginBuildDate, buildDateFunc(), strlen(gScummVMPluginBuildDate))) { + unloadPlugin(); + warning("elfloader: plugin '%s' has a different build date", _filename.c_str()); + return false; + } + + bool ret = DynamicPlugin::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); + } +#endif + + _dlHandle->discard_symtab(); + + return ret; +} + +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()); + + delete _dlHandle; + _dlHandle = 0; + } +} + +bool ELFPluginProvider::isPluginFilename(const Common::FSNode &node) const { + // Check the plugin suffix + Common::String filename = node.getName(); + + if (!filename.hasSuffix(".PLG") && !filename.hasSuffix(".plg") && + !filename.hasSuffix(".PLUGIN") && !filename.hasSuffix(".plugin")) + return false; + + return true; +} + +#endif // defined(DYNAMIC_MODULES) && defined(USE_ELF_LOADER) + diff --git a/backends/plugins/elf/elf-provider.h b/backends/plugins/elf/elf-provider.h new file mode 100644 index 0000000000..0309ffcece --- /dev/null +++ b/backends/plugins/elf/elf-provider.h @@ -0,0 +1,84 @@ +/* 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$ + * $Id$ + * + */ + +#ifndef BACKENDS_PLUGINS_ELF_PROVIDER_H +#define BACKENDS_PLUGINS_ELF_PROVIDER_H + +#include "common/scummsys.h" + +#if defined(DYNAMIC_MODULES) && defined(USE_ELF_LOADER) + +#include "backends/plugins/elf/elf-loader.h" + +#include "common/fs.h" + +/** + * ELFPlugin + * + * Objects of this class are returned when the PluginManager calls + * getPlugins() on an ELFPluginProvider. An intermediary class for + * dealing with plugin files, ELFPlugin is responsible for creating/destroying + * a DLObject that handles the opening/loading/unloading of the plugin file whose + * path in the target backend's file system is "_filename". + */ +class ELFPlugin : public DynamicPlugin { +protected: + typedef const char *(*CharFunc)(); + + DLObject *_dlHandle; + Common::String _filename; + void *_dso_handle; + + virtual VoidFunc findSymbol(const char *symbol); + +public: + ELFPlugin(const Common::String &filename) : + _dlHandle(0), + _filename(filename), + _dso_handle(0) { + } + + virtual ~ELFPlugin() { + if (_dlHandle) + unloadPlugin(); + } + + virtual DLObject *makeDLObject() = 0; + + bool loadPlugin(); + void unloadPlugin(); +}; + +class ELFPluginProvider : public FilePluginProvider { +protected: + virtual Plugin *createPlugin(const Common::FSNode &node) const = 0; + + bool isPluginFilename(const Common::FSNode &node) const; +}; + +#endif // defined(DYNAMIC_MODULES) && defined(USE_ELF_LOADER) + +#endif /* BACKENDS_PLUGINS_ELF_PROVIDER_H */ + diff --git a/backends/plugins/elf/elf32.h b/backends/plugins/elf/elf32.h new file mode 100644 index 0000000000..d3a8d2e436 --- /dev/null +++ b/backends/plugins/elf/elf32.h @@ -0,0 +1,258 @@ +/* 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$ + * $Id$ + * + */ + +#ifndef BACKENDS_ELF_H +#define BACKENDS_ELF_H + +#include "common/scummsys.h" + +#if defined(DYNAMIC_MODULES) && defined(USE_ELF_LOADER) + +/** + * ELF stuff: + * The contents of this file were gathered mainly from the SYSTEM V APPLICATION BINARY INTERFACE. + * Processor-specific things were garnered from processor-specific supplements to the abi. + */ + +typedef uint16 Elf32_Half, Elf32_Section; +typedef uint32 Elf32_Word, Elf32_Addr, Elf32_Off; +typedef int32 Elf32_Sword; +typedef Elf32_Half Elf32_Versym; + +#define EI_NIDENT (16) +#define SELFMAG 4 + +/* ELF File format structures. Look up ELF structure for more details */ + +// ELF header (contains info about the file) +typedef struct { + byte e_ident[EI_NIDENT]; /* Magic number and other info */ + Elf32_Half e_type; /* Object file type */ + Elf32_Half e_machine; /* Architecture */ + Elf32_Word e_version; /* Object file version */ + Elf32_Addr e_entry; /* Entry point virtual address */ + Elf32_Off e_phoff; /* Program header table file offset */ + Elf32_Off e_shoff; /* Section header table file offset */ + Elf32_Word e_flags; /* Processor-specific flags */ + Elf32_Half e_ehsize; /* ELF header size in bytes */ + Elf32_Half e_phentsize; /* Program header table entry size */ + Elf32_Half e_phnum; /* Program header table entry count */ + Elf32_Half e_shentsize; /* Section header table entry size */ + Elf32_Half e_shnum; /* Section header table entry count */ + Elf32_Half e_shstrndx; /* Section header string table index */ +} Elf32_Ehdr; + +// Should be in e_ident +#define ELFMAG "\177ELF" /* ELF Magic number */ + +#define EI_CLASS 4 /* File class byte index */ +#define ELFCLASS32 1 /* 32-bit objects */ + +#define EI_DATA 5 /* Data encoding byte index */ +#define ELFDATA2LSB 1 /* 2's complement, little endian */ +#define ELFDATA2MSB 2 /* 2's complement, big endian */ + +#define EI_VERSION 6 +#define EV_CURRENT 1 /* Current version */ + +// e_type values +#define ET_NONE 0 /* no file type */ +#define ET_REL 1 /* relocatable */ +#define ET_EXEC 2 /* executable */ +#define ET_DYN 3 /* shared object */ +#define ET_CORE 4 /* core file */ + +// e_machine values +#define EM_MIPS 8 +#define EM_PPC 20 +#define EM_ARM 40 + +// Program header (contains info about segment) +typedef struct { + Elf32_Word p_type; /* Segment type */ + Elf32_Off p_offset; /* Segment file offset */ + Elf32_Addr p_vaddr; /* Segment virtual address */ + Elf32_Addr p_paddr; /* Segment physical address */ + Elf32_Word p_filesz; /* Segment size in file */ + Elf32_Word p_memsz; /* Segment size in memory */ + Elf32_Word p_flags; /* Segment flags */ + Elf32_Word p_align; /* Segment alignment */ +} Elf32_Phdr; + +// p_type values +#define PT_NULL 0 /* ignored */ +#define PT_LOAD 1 /* loadable segment */ +#define PT_DYNAMIC 2 /* dynamic linking info */ +#define PT_INTERP 3 /* info about interpreter */ +#define PT_NOTE 4 /* note segment */ +#define PT_SHLIB 5 /* reserved */ +#define PT_PHDR 6 /* Program header table */ +#define PT_MIPS_REGINFO 0x70000000 /* Register usage info for MIPS */ +#define PT_ARM_ARCHEXT 0x70000000 /* Platform architecture compatibility info for ARM */ +#define PT_ARM_EXIDX 0x70000001 /* Exception unwind tables for ARM */ + +// p_flags value +#define PF_X 1 /* execute */ +#define PF_W 2 /* write */ +#define PF_R 4 /* read */ + +// Section header (contains info about section) +typedef struct { + Elf32_Word sh_name; /* Section name (string tbl index) */ + Elf32_Word sh_type; /* Section type */ + Elf32_Word sh_flags; /* Section flags */ + Elf32_Addr sh_addr; /* Section virtual addr at execution */ + Elf32_Off sh_offset; /* Section file offset */ + Elf32_Word sh_size; /* Section size in bytes */ + Elf32_Word sh_link; /* Link to another section */ + Elf32_Word sh_info; /* Additional section information */ + Elf32_Word sh_addralign; /* Section alignment */ + Elf32_Word sh_entsize; /* Entry size if section holds table */ +} Elf32_Shdr; + +// sh_type values +#define SHT_NULL 0 /* Inactive section */ +#define SHT_PROGBITS 1 /* Proprietary */ +#define SHT_SYMTAB 2 /* Symbol table */ +#define SHT_STRTAB 3 /* String table */ +#define SHT_RELA 4 /* Relocation entries with addend */ +#define SHT_HASH 5 /* Symbol hash table */ +#define SHT_DYNAMIC 6 /* Info for dynamic linking */ +#define SHT_NOTE 7 /* Note section */ +#define SHT_NOBITS 8 /* Occupies no space */ +#define SHT_REL 9 /* Relocation entries without addend */ +#define SHT_SHLIB 10 /* Reserved */ +#define SHT_DYNSYM 11 /* Minimal set of dynamic linking symbols */ +#define SHT_MIPS_LIBLSIT 0x70000000 /* Info about dynamic shared object libs for MIPS*/ +#define SHT_MIPS_CONFLICT 0x70000002 /* Conflicts btw executables and shared objects for MIPS */ +#define SHT_MIPS_GPTAB 0x70000003 /* Global pointer table for MIPS*/ +#define SHT_ARM_EXIDX 0x70000001 /* Exception Index table for ARM*/ +#define SHT_ARM_PREEMPTMAP 0x70000002 /* BPABI DLL dynamic linking pre-emption map for ARM */ +#define SHT_ARM_ATTRIBUTES 0x70000003 /* Object file compatibility attributes for ARM*/ + +// sh_flags values +#define SHF_WRITE 0 /* writable section */ +#define SHF_ALLOC 2 /* section occupies memory */ +#define SHF_EXECINSTR 4 /* machine instructions */ +#define SHF_MIPS_GPREL 0x10000000 /* Must be made part of global data area for MIPS */ + +// Symbol entry (contain info about a symbol) +typedef struct { + Elf32_Word st_name; /* Symbol name (string tbl index) */ + Elf32_Addr st_value; /* Symbol value */ + Elf32_Word st_size; /* Symbol size */ + byte st_info; /* Symbol type and binding */ + byte st_other; /* Symbol visibility */ + Elf32_Section st_shndx; /* Section index */ +} Elf32_Sym; + +// Extract from the st_info +#define SYM_TYPE(x) ((x) & 0xf) +#define SYM_BIND(x) ((x) >> 4) + +// Symbol binding values from st_info +#define STB_LOCAL 0 /* Symbol not visible outside object */ +#define STB_GLOBAL 1 /* Symbol visible to all object files */ +#define STB_WEAK 2 /* Similar to STB_GLOBAL */ + +// Symbol type values from st_info +#define STT_NOTYPE 0 /* Not specified */ +#define STT_OBJECT 1 /* Data object e.g. variable */ +#define STT_FUNC 2 /* Function */ +#define STT_SECTION 3 /* Section */ +#define STT_FILE 4 /* Source file associated with object file */ + +// Special section header index values from st_shndex +#define SHN_UNDEF 0 +#define SHN_LOPROC 0xFF00 /* Extended values */ +#define SHN_ABS 0xFFF1 /* Absolute value: don't relocate */ +#define SHN_COMMON 0xFFF2 /* Common block. Not allocated yet */ +#define SHN_HIPROC 0xFF1F +#define SHN_HIRESERVE 0xFFFF + +// Relocation entry with implicit addend (info about how to relocate) +typedef struct { + Elf32_Addr r_offset; /* Address */ + Elf32_Word r_info; /* Relocation type and symbol index */ +} Elf32_Rel; + +// Relocation entry with explicit addend (info about how to relocate) +typedef struct { + Elf32_Addr r_offset; /* Address */ + Elf32_Word r_info; /* Relocation type and symbol index */ + Elf32_Sword r_addend; /* Addend */ +} Elf32_Rela; + +// Access macros for the relocation info +#define REL_TYPE(x) ((byte) (x)) /* Extract relocation type */ +#define REL_INDEX(x) ((x)>>8) /* Extract relocation index into symbol table */ + +//MIPS relocation types +#define R_MIPS_NONE 0 +#define R_MIPS_16 1 +#define R_MIPS_32 2 +#define R_MIPS_REL32 3 +#define R_MIPS_26 4 +#define R_MIPS_HI16 5 +#define R_MIPS_LO16 6 +#define R_MIPS_GPREL16 7 +#define R_MIPS_LITERAL 8 +#define R_MIPS_GOT16 9 +#define R_MIPS_PC16 10 +#define R_MIPS_CALL16 11 +#define R_MIPS_GPREL32 12 +#define R_MIPS_GOTHI16 13 +#define R_MIPS_GOTLO16 14 +#define R_MIPS_CALLHI16 15 +#define R_MIPS_CALLLO16 16 + +// ARM relocation types +#define R_ARM_NONE 0 +#define R_ARM_ABS32 2 +#define R_ARM_THM_CALL 10 +#define R_ARM_CALL 28 +#define R_ARM_JUMP24 29 +#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() { \ + uint32 __valgp; \ + __asm__ ("add %0, $gp, $0" : "=r"(__valgp) : ); \ + __valgp; \ +} + +#endif // defined(DYNAMIC_MODULES) && defined(USE_ELF_LOADER) + +#endif /* BACKENDS_ELF_H */ + diff --git a/backends/plugins/elf/mips-loader.cpp b/backends/plugins/elf/mips-loader.cpp new file mode 100644 index 0000000000..53ffc2f01b --- /dev/null +++ b/backends/plugins/elf/mips-loader.cpp @@ -0,0 +1,339 @@ +/* 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$ + * $Id$ + * + */ + +#include "common/scummsys.h" + +#if defined(DYNAMIC_MODULES) && defined(USE_ELF_LOADER) && defined(MIPS_TARGET) + +#include "backends/plugins/elf/mips-loader.h" + +#include "common/debug.h" + +#define DEBUG_NUM 2 + +bool MIPSDLObject::relocate(Elf32_Off offset, Elf32_Word size, byte *relSegment) { + Elf32_Rel *rel = 0; // relocation entry + + // Allocate memory for relocation table + if (!(rel = (Elf32_Rel *)malloc(size))) { + warning("elfloader: Out of memory."); + return false; + } + + // Read in our relocation table + if (!_file->seek(offset, SEEK_SET) || _file->read(rel, size) != size) { + warning("elfloader: Relocation table load failed."); + free(rel); + return false; + } + + // Treat each relocation entry. Loop over all of them + uint32 cnt = size / sizeof(*rel); + + debug(2, "elfloader: Loaded relocation table. %d entries. base address=%p", cnt, relSegment); + + Elf32_Addr adjustedMainSegment = Elf32_Addr(_segment) - _segmentVMA; // adjust for VMA offset + + bool seenHi16 = false; // For treating HI/LO16 commands + int32 firstHi16 = -1; // Mark the point of the first hi16 seen + Elf32_Addr ahl = 0; // Calculated addend + int32 a = 0; // Addend: taken from the target + + uint32 *lastTarget = 0; // For processing hi16 when lo16 arrives + uint32 relocation = 0; + uint debugRelocs[10] = { 0 }; // For debugging + uint extendedHi16 = 0; // Count extended hi16 treatments + Elf32_Addr lastHiSymVal = 0; + bool hi16InShorts = false; + + // Loop over relocation entries + for (uint32 i = 0; i < cnt; i++) { + // Get the symbol this relocation entry is referring to + Elf32_Sym *sym = _symtab + (REL_INDEX(rel[i].r_info)); + + // Get the target instruction in the code. + uint32 *target = (uint32 *)((byte *)relSegment + rel[i].r_offset); + + uint32 origTarget = *target; // Save for debugging + + // Act differently based on the type of relocation + switch (REL_TYPE(rel[i].r_info)) { + case R_MIPS_HI16: // Absolute addressing. + if (sym->st_shndx < SHN_LOPROC && // Only shift for plugin section (ie. has a real section index) + firstHi16 < 0) { // Only process first in block of HI16s + firstHi16 = i; // Keep the first Hi16 we saw + seenHi16 = true; + ahl = (*target & 0xffff) << 16; // Take lower 16 bits shifted up + + lastHiSymVal = sym->st_value; + hi16InShorts = ShortsMan.inGeneralSegment((char *)sym->st_value); // Fix for problem with switching btw segments + if (debugRelocs[0]++ < DEBUG_NUM) // Print only a set number + debug(8, "elfloader: R_MIPS_HI16: i=%d, offset=%x, ahl = %x, target = %x", + i, rel[i].r_offset, ahl, *target); + } + break; + + case R_MIPS_LO16: // Absolute addressing. Needs a HI16 to come before it + if (sym->st_shndx < SHN_LOPROC) { // Only shift for plugin section. (ie. has a real section index) + if (!seenHi16) { // We MUST have seen HI16 first + debug(8, "elfloader: R_MIPS_LO16 w/o preceding R_MIPS_HI16 at relocation %d!", i); + free(rel); + return false; + } + + // Fix: bug in gcc makes LO16s connect to wrong HI16s sometimes (shorts and regular segment) + // Note that we can check the entire shorts segment because the executable's shorts don't belong to this plugin section + // and will be screened out above + bool lo16InShorts = ShortsMan.inGeneralSegment((char *)sym->st_value); + + // Correct the bug by getting the proper value in ahl (taken from the current symbol) + if ((hi16InShorts && !lo16InShorts) || (!hi16InShorts && lo16InShorts)) { + ahl -= (lastHiSymVal & 0xffff0000); // We assume gcc meant the same offset + ahl += (sym->st_value & 0xffff0000); + } + + ahl &= 0xffff0000; // Clean lower 16 bits for repeated LO16s + a = *target & 0xffff; // Take lower 16 bits of the target + a = (a << 16) >> 16; // Sign extend them + ahl += a; // Add lower 16 bits. AHL is now complete + + // Fix: we can have LO16 access to the short segment sometimes + if (lo16InShorts) + relocation = ahl + _shortsSegment->getOffset(); // Add in the short segment offset + else // It's in the regular segment + relocation = ahl + adjustedMainSegment; // Add in the new offset for the segment + + if (firstHi16 >= 0) { // We haven't treated the HI16s yet so do it now + for (uint32 j = firstHi16; j < i; j++) { + if (REL_TYPE(rel[j].r_info) != R_MIPS_HI16) + continue; // Skip over non-Hi16s + + lastTarget = (uint32 *)((char *)relSegment + rel[j].r_offset); // get hi16 target + *lastTarget &= 0xffff0000; // Clear the lower 16 bits of the last target + *lastTarget |= (relocation >> 16) & 0xffff; // Take the upper 16 bits of the relocation + if (relocation & 0x8000) + (*lastTarget)++; // Subtle: we need to add 1 to the HI16 in this case + } + + firstHi16 = -1; // Reset so we'll know we treated it + } else { + extendedHi16++; + } + + *target &= 0xffff0000; // Clear the lower 16 bits of current target + *target |= relocation & 0xffff; // Take the lower 16 bits of the relocation + + if (debugRelocs[1]++ < DEBUG_NUM) + debug(8, "elfloader: R_MIPS_LO16: i=%d, offset=%x, a=%x, ahl = %x, " + "lastTarget = %x, origt = %x, target = %x", + i, rel[i].r_offset, a, ahl, *lastTarget, origTarget, *target); + + if (lo16InShorts && debugRelocs[2]++ < DEBUG_NUM) + debug(8, "elfloader: R_MIPS_LO16s: i=%d, offset=%x, a=%x, ahl = %x, " + "lastTarget = %x, origt = %x, target = %x", + i, rel[i].r_offset, a, ahl, *lastTarget, origTarget, *target); + } + break; + + case R_MIPS_26: // Absolute addressing (for jumps and branches only) + if (sym->st_shndx < SHN_LOPROC) { // Only relocate for main segment + a = *target & 0x03ffffff; // Get 26 bits' worth of the addend + a = (a << 6) >> 6; // Sign extend a + relocation = ((a << 2) + adjustedMainSegment) >> 2; // a already points to the target. Add our offset + *target &= 0xfc000000; // Clean lower 26 target bits + *target |= (relocation & 0x03ffffff); + + if (debugRelocs[3]++ < DEBUG_NUM) + debug(8, "elfloader: R_MIPS_26: i=%d, offset=%x, symbol=%d, stinfo=%x, " + "a=%x, origTarget=%x, target=%x", + i, rel[i].r_offset, REL_INDEX(rel[i].r_info), sym->st_info, a, origTarget, *target); + } else { + if (debugRelocs[4]++ < DEBUG_NUM) + debug(8, "elfloader: R_MIPS_26: i=%d, offset=%x, symbol=%d, stinfo=%x, " + "a=%x, origTarget=%x, target=%x", + i, rel[i].r_offset, REL_INDEX(rel[i].r_info), sym->st_info, a, origTarget, *target); + } + break; + + case R_MIPS_GPREL16: // GP Relative addressing + if (_shortsSegment->getOffset() != 0 && // Only relocate if we shift the shorts section + ShortsMan.inGeneralSegment((char *) sym->st_value)) { // Only relocate things in the plugin hole + a = *target & 0xffff; // Get 16 bits' worth of the addend + a = (a << 16) >> 16; // Sign extend it + + relocation = a + _shortsSegment->getOffset(); + + *target &= 0xffff0000; // Clear the lower 16 bits of the target + *target |= relocation & 0xffff; + + if (debugRelocs[5]++ < DEBUG_NUM) + debug(8, "elfloader: R_MIPS_GPREL16: i=%d, a=%x, gpVal=%x, origTarget=%x, " + "target=%x, offset=%x", + i, a, _gpVal, origTarget, *target, _shortsSegment->getOffset()); + } + + break; + + case R_MIPS_32: // Absolute addressing + if (sym->st_shndx < SHN_LOPROC) { // Only shift for plugin section. + a = *target; // Get full 32 bits of addend + + if (ShortsMan.inGeneralSegment((char *)sym->st_value)) // Check if we're in the shorts segment + relocation = a + _shortsSegment->getOffset(); // Shift by shorts offset + else // We're in the main section + relocation = a + adjustedMainSegment; // Shift by main offset + + *target = relocation; + + if (debugRelocs[6]++ < DEBUG_NUM) + debug(8, "elfloader: R_MIPS_32: i=%d, a=%x, origTarget=%x, target=%x", + i, a, origTarget, *target); + } + + break; + + default: + warning("elfloader: Unknown relocation type %x at relocation %d.", REL_TYPE(rel[i].r_info), i); + free(rel); + return false; + } + } + + debug(2, "elfloader: Done with relocation. extendedHi16=%d", extendedHi16); + + free(rel); + return true; +} + +bool MIPSDLObject::relocateRels(Elf32_Ehdr *ehdr, Elf32_Shdr *shdr) { + // Loop over sections, finding relocation sections + for (uint32 i = 0; i < ehdr->e_shnum; i++) { + Elf32_Shdr *curShdr = &(shdr[i]); + //Elf32_Shdr *linkShdr = &(shdr[curShdr->sh_info]); + + if (curShdr->sh_type == SHT_REL && // Check for a relocation section + curShdr->sh_entsize == sizeof(Elf32_Rel) && // Check for proper relocation size + int32(curShdr->sh_link) == _symtab_sect && // Check that the sh_link connects to our symbol table + curShdr->sh_info < ehdr->e_shnum && // Check that the relocated section exists + (shdr[curShdr->sh_info].sh_flags & SHF_ALLOC)) { // Check if relocated section resides in memory + if (!ShortsMan.inGeneralSegment((char *)shdr[curShdr->sh_info].sh_addr)) { // regular segment + if (!relocate(curShdr->sh_offset, curShdr->sh_size, _segment - _segmentVMA)) + return false; + } else { // In Shorts segment + if (!relocate(curShdr->sh_offset, curShdr->sh_size, (byte *)_shortsSegment->getOffset())) + return false; + } + } + } + + return true; +} + +void MIPSDLObject::relocateSymbols(ptrdiff_t offset) { + // Loop over symbols, add relocation offset + Elf32_Sym *s = _symtab; + + for (uint32 c = _symbol_cnt; c--; s++) { + // Make sure we don't relocate special valued symbols + if (s->st_shndx < SHN_LOPROC) { + if (!ShortsMan.inGeneralSegment((char *)s->st_value)) { + if (s->st_value < _segmentVMA) + s->st_value = _segmentVMA; // deal with symbols referring to sections, which start before the VMA + + s->st_value += offset; + + if (s->st_value < Elf32_Addr(_segment) || s->st_value > Elf32_Addr(_segment) + _segmentSize) + warning("elfloader: Symbol out of bounds! st_value = %x", s->st_value); + } else { // shorts section + s->st_value += _shortsSegment->getOffset(); + if (!_shortsSegment->inSegment((char *)s->st_value)) + warning("elfloader: Symbol out of bounds! st_value = %x", s->st_value); + } + } + } +} + +bool MIPSDLObject::loadSegment(Elf32_Phdr *phdr) { + byte *baseAddress = 0; + + // We need to take account of non-allocated segment for shorts + if (phdr->p_flags & PF_X) { // This is a relocated segment + // Attempt to allocate memory for segment + _segment = (byte *)allocSegment(phdr->p_align, phdr->p_memsz); + + if (!_segment) { + warning("elfloader: Out of memory."); + return false; + } + + debug(2, "elfloader: Allocated segment @ %p", _segment); + + // Get offset to load segment into + baseAddress = _segment; + _segmentSize = phdr->p_memsz; + _segmentVMA = phdr->p_vaddr; + + } else { // This is a shorts section. + _shortsSegment = ShortsMan.newSegment(phdr->p_memsz, (char *)phdr->p_vaddr); + + baseAddress = (byte *)_shortsSegment->getStart(); + debug(2, "elfloader: Shorts segment @ %p to %p. Segment wants to be at %x. Offset=%x", + _shortsSegment->getStart(), _shortsSegment->getEnd(), phdr->p_vaddr, + _shortsSegment->getOffset()); + } + + // Set .sbss segment to 0 if necessary + if (phdr->p_memsz > phdr->p_filesz) { + debug(2, "elfloader: Setting %p to %p to 0 for bss", baseAddress + phdr->p_filesz, + baseAddress + phdr->p_memsz); + memset(baseAddress + phdr->p_filesz, 0, phdr->p_memsz - phdr->p_filesz); + } + + debug(2, "elfloader: Reading the segment into memory"); + + // Read the segment into memory + if (!_file->seek(phdr->p_offset, SEEK_SET) || + _file->read(baseAddress, phdr->p_filesz) != phdr->p_filesz) { + warning("elfloader: Segment load failed."); + return false; + } + + debug(2, "elfloader: Segment has been read into memory"); + + return true; +} + +// Unload all objects from memory +void MIPSDLObject::unload() { + DLObject::unload(); + + if (_shortsSegment) { + ShortsMan.deleteSegment(_shortsSegment); + _shortsSegment = 0; + } +} + +#endif /* defined(DYNAMIC_MODULES) && defined(USE_ELF_LOADER) && defined(MIPS_TARGET) */ + diff --git a/backends/plugins/elf/mips-loader.h b/backends/plugins/elf/mips-loader.h new file mode 100644 index 0000000000..f8f31f1e7a --- /dev/null +++ b/backends/plugins/elf/mips-loader.h @@ -0,0 +1,59 @@ + +/* 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$ + * $Id$ + * + */ + +#ifndef BACKENDS_PLUGINS_MIPS_LOADER_H +#define BACKENDS_PLUGINS_MIPS_LOADER_H + +#include "common/scummsys.h" + +#if defined(DYNAMIC_MODULES) && defined(USE_ELF_LOADER) && defined(MIPS_TARGET) + +#include "backends/plugins/elf/elf-loader.h" +#include "backends/plugins/elf/shorts-segment-manager.h" + +class MIPSDLObject : public DLObject { +protected: + ShortSegmentManager::Segment *_shortsSegment; // For assigning shorts ranges + uint32 _gpVal; // Value of Global Pointer + + virtual bool relocate(Elf32_Off offset, Elf32_Word size, byte *relSegment); + virtual bool relocateRels(Elf32_Ehdr *ehdr, Elf32_Shdr *shdr); + virtual void relocateSymbols(ptrdiff_t offset); + virtual bool loadSegment(Elf32_Phdr *phdr); + virtual void unload(); + +public: + MIPSDLObject() : + DLObject() { + _shortsSegment = NULL; + _gpVal = 0; + } +}; + +#endif /* defined(DYNAMIC_MODULES) && defined(USE_ELF_LOADER) && defined(MIPS_TARGET) */ + +#endif /* BACKENDS_PLUGINS_MIPS_LOADER_H */ + diff --git a/backends/platform/psp/plugin.syms b/backends/plugins/elf/plugin.syms index 24ee1a19dc..70465ae976 100644 --- a/backends/platform/psp/plugin.syms +++ b/backends/plugins/elf/plugin.syms @@ -1,3 +1,4 @@ +PLUGIN_getBuildDate PLUGIN_getVersion PLUGIN_getType PLUGIN_getTypeVersion diff --git a/backends/plugins/elf/ppc-loader.cpp b/backends/plugins/elf/ppc-loader.cpp new file mode 100644 index 0000000000..ec6d442876 --- /dev/null +++ b/backends/plugins/elf/ppc-loader.cpp @@ -0,0 +1,129 @@ +/* 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$ + * $Id$ + * + */ + +#include "common/scummsys.h" + +#if defined(DYNAMIC_MODULES) && defined(USE_ELF_LOADER) && defined(PPC_TARGET) + +#include "backends/plugins/elf/elf-loader.h" +#include "backends/plugins/elf/ppc-loader.h" + +#include "common/debug.h" + +bool PPCDLObject::relocate(Elf32_Off offset, Elf32_Word size, byte *relSegment) { + Elf32_Rela *rel = NULL; + + if (!(rel = (Elf32_Rela *)malloc(size))) { + warning("elfloader: Out of memory."); + 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); + + uint32 *src; + uint32 value; + + for (uint32 i = 0; i < cnt; i++) { + // Get the symbol this relocation entry is referring to + Elf32_Sym *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", *src); + break; + case R_PPC_ADDR16_LO: + *(uint16 *)src = value; + debug(8, "elfloader: R_PPC_ADDR16_LO -> 0x%08x", *src); + break; + case R_PPC_ADDR16_HI: + *(uint16 *)src = value >> 16; + debug(8, "elfloader: R_PPC_ADDR16_HA -> 0x%08x", *src); + break; + case R_PPC_ADDR16_HA: + *(uint16 *)src = (value + 0x8000) >> 16; + debug(8, "elfloader: R_PPC_ADDR16_HA -> 0x%08x", *src); + break; + case R_PPC_REL24: + *src = (*src & ~0x03fffffc) | ((value - (uint32)src) & 0x03fffffc); + debug(8, "elfloader: R_PPC_REL24 -> 0x%08x", *src); + break; + case R_PPC_REL32: + *src = value - (uint32)src; + debug(8, "elfloader: R_PPC_REL32 -> 0x%08x", *src); + break; + default: + warning("elfloader: Unknown relocation type %d", REL_TYPE(rel[i].r_info)); + free(rel); + return false; + } + } + + free(rel); + return true; +} + +bool PPCDLObject::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!"); + 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(PPC_TARGET) */ + diff --git a/backends/plugins/elf/ppc-loader.h b/backends/plugins/elf/ppc-loader.h new file mode 100644 index 0000000000..f9340a6a7b --- /dev/null +++ b/backends/plugins/elf/ppc-loader.h @@ -0,0 +1,49 @@ +/* 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$ + * $Id$ + * + */ + +#ifndef BACKENDS_PLUGINS_PPC_LOADER_H +#define BACKENDS_PLUGINS_PPC_LOADER_H + +#include "common/scummsys.h" + +#if defined(DYNAMIC_MODULES) && defined(USE_ELF_LOADER) && defined(PPC_TARGET) + +#include "backends/plugins/elf/elf-loader.h" + +class PPCDLObject : public DLObject { +protected: + virtual bool relocate(Elf32_Off offset, Elf32_Word size, byte *relSegment); + virtual bool relocateRels(Elf32_Ehdr *ehdr, Elf32_Shdr *shdr); + +public: + PPCDLObject() : + DLObject() { + } +}; + +#endif /* defined(DYNAMIC_MODULES) && defined(USE_ELF_LOADER) && defined(PPC_TARGET) */ + +#endif /* BACKENDS_PLUGINS_PPC_LOADER_H */ + diff --git a/backends/plugins/elf/shorts-segment-manager.cpp b/backends/plugins/elf/shorts-segment-manager.cpp new file mode 100644 index 0000000000..17fe650c31 --- /dev/null +++ b/backends/plugins/elf/shorts-segment-manager.cpp @@ -0,0 +1,89 @@ +/* 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$ + * $Id$ + * + */ + +#include "common/scummsys.h" + +#if defined(DYNAMIC_MODULES) && defined(USE_ELF_LOADER) && defined(MIPS_TARGET) + +#include "backends/plugins/elf/shorts-segment-manager.h" + +#include "common/debug.h" + +extern char __plugin_hole_start; // Indicates start of hole in program file for shorts +extern char __plugin_hole_end; // Indicates end of hole in program file +extern char _gp[]; // Value of gp register + +DECLARE_SINGLETON(ShortSegmentManager); // For singleton + +ShortSegmentManager::ShortSegmentManager() { + _shortsStart = &__plugin_hole_start ; //shorts segment begins at the plugin hole we made when linking + _shortsEnd = &__plugin_hole_end; //and ends at the end of that hole. +} + +ShortSegmentManager::Segment *ShortSegmentManager::newSegment(uint32 size, char *origAddr) { + char *lastAddress = origAddr; + Common::List<Segment *>::iterator i; + + // Find a block that fits, starting from the beginning + for (i = _list.begin(); i != _list.end(); ++i) { + char *currAddress = (*i)->getStart(); + + if (uint32(currAddress) - uint32(lastAddress) >= size) + break; + + lastAddress = (*i)->getEnd(); + } + + if ((Elf32_Addr)lastAddress & 3) + lastAddress += 4 - ((Elf32_Addr)lastAddress & 3); // Round up to multiple of 4 + + if (lastAddress + size > _shortsEnd) { + warning("elfloader: No space in shorts segment for %x bytes. Last address is %p, max address is %p.", + size, lastAddress, _shortsEnd); + return 0; + } + + Segment *seg = new Segment(lastAddress, size, origAddr); // Create a new segment + + if (lastAddress + size > _highestAddress) + _highestAddress = lastAddress + size; // Keep track of maximum + + _list.insert(i, seg); + + debug(2, "elfloader: Shorts segment size %x allocated. End = %p. Remaining space = %x. Highest so far is %p.", + size, lastAddress + size, _shortsEnd - _list.back()->getEnd(), _highestAddress); + + return seg; +} + +void ShortSegmentManager::deleteSegment(ShortSegmentManager::Segment *seg) { + debug(2, "elfloader: Deleting shorts segment from %p to %p.", seg->getStart(), seg->getEnd()); + _list.remove(seg); + delete seg; +} + +#endif // defined(DYNAMIC_MODULES) && defined(USE_ELF_LOADER) && defined(MIPS_TARGET) + + diff --git a/backends/plugins/elf/shorts-segment-manager.h b/backends/plugins/elf/shorts-segment-manager.h new file mode 100644 index 0000000000..219648d91d --- /dev/null +++ b/backends/plugins/elf/shorts-segment-manager.h @@ -0,0 +1,117 @@ +/* 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$ + * $Id$ + * + */ + +#ifndef SHORTS_SEGMENT_MANAGER_H +#define SHORTS_SEGMENT_MANAGER_H + +#include "common/scummsys.h" + +#if defined(DYNAMIC_MODULES) && defined(USE_ELF_LOADER) && defined(MIPS_TARGET) + +#include "backends/plugins/elf/elf32.h" + +#include "common/singleton.h" +#include "common/list.h" + +#define ShortsMan ShortSegmentManager::instance() + +/** + * ShortSegmentManager + * + * Since MIPS is limited to 32 bits per instruction, loading data that's further away than 16 bits + * takes several instructions. Thus, small global data (which is likely to be accessed a lot from + * multiple locations) is often put into a GP-relative area (GP standing for the global pointer register) + * in MIPS processors. This class manages these segments of small global data, and is used by the + * member functions of MIPSDLObject, which query in information from this manager in order to deal with + * this segment during the loading/unloading of plugins. + * + * Since there's no true dynamic linker to change the GP register between plugins and the main engine, + * custom ld linker scripts for both the main executable and the plugins ensure the GP-area is in the + * same place for both. The ShortSegmentManager accesses this place via the symbols __plugin_hole_start + * and __plugin_hole_end, which are defined in those custom ld linker scripts. + */ +class ShortSegmentManager : public Common::Singleton<ShortSegmentManager> { +private: + char *_shortsStart; + char *_shortsEnd; + +public: + char *getShortsStart() { + return _shortsStart; + } + + // Returns whether or not an absolute address is in the GP-relative section. + bool inGeneralSegment(char *addr) { + return (addr >= _shortsStart && addr < _shortsEnd); + } + + class Segment { + private: + friend class ShortSegmentManager; + Segment(char *start, uint32 size, char *origAddr) : + _startAddress(start), + _size(size), + _origAddress(origAddr) { + } + + virtual ~Segment() { + } + + char *_startAddress; // Start of shorts segment in memory + uint32 _size; // Size of shorts segment + char *_origAddress; // Original address this segment was supposed to be at + + public: + char *getStart() { + return _startAddress; + } + + char *getEnd() { + return (_startAddress + _size); + } + + Elf32_Addr getOffset() { + return (Elf32_Addr)(_startAddress - _origAddress); + } + + bool inSegment(char *addr) { + return (addr >= _startAddress && addr <= _startAddress + _size); + } + }; + + Segment *newSegment(uint32 size, char *origAddr); + void deleteSegment(Segment *); + +private: + ShortSegmentManager(); + friend class Common::Singleton<ShortSegmentManager>; + Common::List<Segment *> _list; + char *_highestAddress; +}; + +#endif // defined(DYNAMIC_MODULES) && defined(USE_ELF_LOADER) && defined(MIPS_TARGET) + +#endif /* SHORTS_SEGMENT_MANAGER_H */ + diff --git a/backends/plugins/elf/version.cpp b/backends/plugins/elf/version.cpp new file mode 100644 index 0000000000..0277c6ae1c --- /dev/null +++ b/backends/plugins/elf/version.cpp @@ -0,0 +1,32 @@ +/* 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$ + * $Id$ + * + */ + +#include "backends/plugins/elf/version.h" + +#ifdef USE_ELF_LOADER +const char *gScummVMPluginBuildDate __attribute__((visibility("hidden"))) = + __DATE__ " " __TIME__ ; +#endif + diff --git a/backends/plugins/elf/version.h b/backends/plugins/elf/version.h new file mode 100644 index 0000000000..726204aeb7 --- /dev/null +++ b/backends/plugins/elf/version.h @@ -0,0 +1,35 @@ +/* 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$ + * $Id$ + */ + +#ifndef BACKENDS_PLUGINS_ELF_VERSION_H +#define BACKENDS_PLUGINS_ELF_VERSION_H + +#include "common/scummsys.h" + +#ifdef USE_ELF_LOADER +extern const char *gScummVMPluginBuildDate; +#endif + +#endif + diff --git a/backends/plugins/ps2/main_prog.ld b/backends/plugins/ps2/main_prog.ld new file mode 100644 index 0000000000..9dba69c50e --- /dev/null +++ b/backends/plugins/ps2/main_prog.ld @@ -0,0 +1,99 @@ +ENTRY(_start); + +SECTIONS { + .text 0x00100000: { + _ftext = . ; + *(.text) + *(.text.*) + *(.gnu.linkonce.t*) + KEEP(*(.init)) + KEEP(*(.fini)) + QUAD(0) + } + + PROVIDE(_etext = .); + PROVIDE(etext = .); + + .reginfo : { *(.reginfo) } + + /* Global/static constructors and deconstructors. */ + .ctors ALIGN(16): { + KEEP(*crtbegin*.o(.ctors)) + KEEP(*(EXCLUDE_FILE(*crtend*.o) .ctors)) + KEEP(*(SORT(.ctors.*))) + KEEP(*(.ctors)) + } + .dtors ALIGN(16): { + KEEP(*crtbegin*.o(.dtors)) + KEEP(*(EXCLUDE_FILE(*crtend*.o) .dtors)) + KEEP(*(SORT(.dtors.*))) + KEEP(*(.dtors)) + } + + /* Static data. */ + .rodata ALIGN(128): { + *(.rodata) + *(.rodata.*) + *(.gnu.linkonce.r*) + } + + .data ALIGN(128): { + _fdata = . ; + *(.data) + *(.data.*) + *(.gnu.linkonce.d*) + SORT(CONSTRUCTORS) + } + + .rdata ALIGN(128): { *(.rdata) } + .gcc_except_table ALIGN(128): { *(.gcc_except_table) } + + _gp = ALIGN(128) + 0x7ff0; + .lit4 ALIGN(128): { *(.lit4) } + .lit8 ALIGN(128): { *(.lit8) } + + .sdata ALIGN(128): { + *(.sdata) + *(.sdata.*) + *(.gnu.linkonce.s*) + } + + _edata = .; + PROVIDE(edata = .); + + /* Uninitialized data. */ + .sbss ALIGN(128) : { + _fbss = . ; + *(.sbss) + *(.sbss.*) + *(.gnu.linkonce.sb*) + *(.scommon) + } + + /*This "plugin hole" is so the plugins can all have global small data + in the same place.*/ + __plugin_hole_start = .; + . = _gp + 0x7ff0; + __plugin_hole_end = .; + + COMMON : + { + *(COMMON) + } + . = ALIGN(128); + + .bss ALIGN(128) : { + *(.bss) + *(.bss.*) + *(.gnu.linkonce.b*) + } + _end_bss = .; + + _end = . ; + PROVIDE(end = .); + + /* Symbols needed by crt0.s. */ + PROVIDE(_heap_size = -1); + PROVIDE(_stack = -1); + PROVIDE(_stack_size = 128 * 1024); +} diff --git a/backends/plugins/ps2/plugin.ld b/backends/plugins/ps2/plugin.ld new file mode 100644 index 0000000000..45efe4db7a --- /dev/null +++ b/backends/plugins/ps2/plugin.ld @@ -0,0 +1,94 @@ +/* PHDRS specifies ELF Program Headers (or segments) to the plugin linker */ +PHDRS { + plugin PT_LOAD ; /* Specifies that the plugin segment should be loaded from file */ + shorts PT_LOAD ; /* Specifies that the shorts segment should be loaded from file */ +} + +SECTIONS { + .text 0: { + _ftext = . ; + *(.text) + *(.text.*) + *(.gnu.linkonce.t*) + KEEP(*(.init)) + KEEP(*(.fini)) + QUAD(0) + } : plugin /*The ": plugin" tells the linker to assign this and + the following sections to the "plugin" segment*/ + PROVIDE(_etext = .); + PROVIDE(etext = .); + + .reginfo : { *(.reginfo) } + + /* Global/static constructors and deconstructors. */ + .ctors ALIGN(16): { + ___plugin_ctors = .; + KEEP(*(SORT(.ctors.*))) + KEEP(*(.ctors)) + ___plugin_ctors_end = .; + } + .dtors ALIGN(16): { + ___plugin_dtors = .; + KEEP(*(SORT(.dtors.*))) + KEEP(*(.dtors)) + ___plugin_dtors_end = .; + } + + /* Static data. */ + .rodata ALIGN(128): { + *(.rodata) + *(.rodata.*) + *(.gnu.linkonce.r*) + } + + .data ALIGN(128): { + _fdata = . ; + *(.data) + *(.data.*) + *(.gnu.linkonce.d*) + SORT(CONSTRUCTORS) + } + + .rdata ALIGN(128): { *(.rdata) } + .gcc_except_table ALIGN(128): { *(.gcc_except_table) } + + .bss ALIGN(128) : { + *(.bss) + *(.bss.*) + *(.gnu.linkonce.b*) + *(COMMON) + } + _end_bss = .; + + _end = . ; + PROVIDE(end = .); + + /* Symbols needed by crt0.s. */ + PROVIDE(_heap_size = -1); + PROVIDE(_stack = -1); + PROVIDE(_stack_size = 128 * 1024); + + /*We assign the output location counter to the plugin hole made + in main_prog.ld, then assign the small data sections to the shorts segment*/ + . = __plugin_hole_start; + .lit4 ALIGN(128): { *(.lit4) } : shorts + .lit8 ALIGN(128): { *(.lit8) } + + .sdata ALIGN(128): { + *(.sdata) + *(.sdata.*) + *(.gnu.linkonce.s*) + } + + _edata = .; + PROVIDE(edata = .); + + /* Uninitialized data. */ + .sbss ALIGN(128) : { + _fbss = . ; + *(.sbss) + *(.sbss.*) + *(.gnu.linkonce.sb*) + *(.scommon) + } +} diff --git a/backends/plugins/ps2/ps2-provider.cpp b/backends/plugins/ps2/ps2-provider.cpp new file mode 100644 index 0000000000..71e715ae50 --- /dev/null +++ b/backends/plugins/ps2/ps2-provider.cpp @@ -0,0 +1,72 @@ +/* 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$ + * $Id$ + * + */ + +#if defined(DYNAMIC_MODULES) && defined(__PLAYSTATION2__) + +#include "backends/plugins/ps2/ps2-provider.h" +#include "backends/plugins/elf/mips-loader.h" + +class PS2DLObject : public MIPSDLObject { +public: + PS2DLObject() : + MIPSDLObject() { + } + + virtual ~PS2DLObject() { + unload(); + } + +protected: + virtual void *allocSegment(size_t boundary, size_t size) const { + return memalign(boundary, size); + } + + virtual void freeSegment(void *segment) const { + free(segment); + } + + virtual void flushDataCache(void *, uint32) const { + FlushCache(0); + FlushCache(2); + } +}; + +class PS2Plugin : public ELFPlugin { +public: + PS2Plugin(const Common::String &filename) : + ELFPlugin(filename) { + } + + virtual DLObject *makeDLObject() { + return new PS2DLObject(); + } +}; + +Plugin *PS2PluginProvider::createPlugin(const Common::FSNode &node) const { + return new PS2Plugin(node.getPath()); +} + +#endif // defined(DYNAMIC_MODULES) && defined(__PLAYSTATION2__) + diff --git a/backends/plugins/ps2/ps2-provider.h b/backends/plugins/ps2/ps2-provider.h new file mode 100644 index 0000000000..3d4b4b0128 --- /dev/null +++ b/backends/plugins/ps2/ps2-provider.h @@ -0,0 +1,41 @@ +/* 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$ + * $Id$ + * + */ + +#if defined(DYNAMIC_MODULES) && defined(__PLAYSTATION2__) + +#ifndef BACKENDS_PLUGINS_PS2_PROVIDER_H +#define BACKENDS_PLUGINS_PS2_PROVIDER_H + +#include "backends/plugins/elf/elf-provider.h" + +class PS2PluginProvider : public ELFPluginProvider { +public: + Plugin *createPlugin(const Common::FSNode &node) const; +}; + +#endif // BACKENDS_PLUGINS_PS2_PROVIDER_H + +#endif // defined(DYNAMIC_MODULES) && defined(__PLAYSTATION2__) + diff --git a/backends/platform/psp/plugin.ld b/backends/plugins/psp/plugin.ld index 7534c15290..a4456d199d 100644 --- a/backends/platform/psp/plugin.ld +++ b/backends/plugins/psp/plugin.ld @@ -1,11 +1,12 @@ -OUTPUT_FORMAT("elf32-littlemips", "elf32-bigmips", - "elf32-littlemips") +OUTPUT_FORMAT("elf32-littlemips", "elf32-bigmips", "elf32-littlemips") OUTPUT_ARCH(mips:allegrex) + PHDRS { plugin PT_LOAD ; shorts PT_LOAD ; } + /* Do we need any of these for elf? __DYNAMIC = 0; */ SECTIONS @@ -208,7 +209,7 @@ SECTIONS .debug_varnames 0 : { *(.debug_varnames) } /DISCARD/ : { *(.comment) *(.pdr) } /DISCARD/ : { *(.note.GNU-stack) } - + . = __plugin_hole_start; .got : { *(.got.plt) *(.got) } : shorts /* We want the small data sections together, so single-instruction offsets @@ -234,6 +235,4 @@ SECTIONS PROVIDE (__sbss_end = .); PROVIDE (___sbss_end = .); } - - } diff --git a/backends/plugins/psp/psp-provider.cpp b/backends/plugins/psp/psp-provider.cpp index 5760424cbf..5bf9b0cc20 100644 --- a/backends/plugins/psp/psp-provider.cpp +++ b/backends/plugins/psp/psp-provider.cpp @@ -25,86 +25,51 @@ #if defined(DYNAMIC_MODULES) && defined(__PSP__) -#include "backends/plugins/psp/psp-provider.h" -#include "backends/plugins/dynamic-plugin.h" -#include "common/fs.h" +#include <psputils.h> +#include <psputilsforkernel.h> -#include "backends/platform/psp/psploader.h" +#include "backends/plugins/psp/psp-provider.h" +#include "backends/plugins/elf/mips-loader.h" -#include "backends/platform/psp/trace.h" +class PSPDLObject : public MIPSDLObject { +public: + PSPDLObject() : + MIPSDLObject() { + } + virtual ~PSPDLObject() { + unload(); + } -class PSPPlugin : public DynamicPlugin { protected: - void *_dlHandle; - Common::String _filename; - - virtual VoidFunc findSymbol(const char *symbol) { - void *func = dlsym(_dlHandle, symbol); - if (!func) - warning("Failed loading symbol '%s' from plugin '%s' (%s)", symbol, _filename.c_str(), dlerror()); - - // FIXME HACK: This is a HACK to circumvent a clash between the ISO C++ - // standard and POSIX: ISO C++ disallows casting between function pointers - // and data pointers, but dlsym always returns a void pointer. For details, - // see e.g. <http://www.trilithium.com/johan/2004/12/problem-with-dlsym/>. - assert(sizeof(VoidFunc) == sizeof(func)); - VoidFunc tmp; - memcpy(&tmp, &func, sizeof(VoidFunc)); - return tmp; + virtual void *allocSegment(size_t boundary, size_t size) const { + return memalign(boundary, size); } -public: - PSPPlugin(const Common::String &filename) - : _dlHandle(0), _filename(filename) {} - - ~PSPPlugin() { - if (_dlHandle) unloadPlugin(); + virtual void freeSegment(void *segment) const { + free(segment); } - bool loadPlugin() { - assert(!_dlHandle); - _dlHandle = dlopen(_filename.c_str(), RTLD_LAZY); - - if (!_dlHandle) { - warning("Failed loading plugin '%s' (%s)", _filename.c_str(), dlerror()); - return false; - } - - bool ret = DynamicPlugin::loadPlugin(); - - if (ret) - dlforgetsyms(_dlHandle); + virtual void flushDataCache(void *ptr, uint32 len) const { + sceKernelDcacheWritebackRange(ptr, len); + sceKernelIcacheInvalidateRange(ptr, len); + } +}; - return ret; +class PSPPlugin : public ELFPlugin { +public: + PSPPlugin(const Common::String &filename) : + ELFPlugin(filename) { } - void unloadPlugin() { - DynamicPlugin::unloadPlugin(); - if (_dlHandle) { - if (dlclose(_dlHandle) != 0) - warning("Failed unloading plugin '%s' (%s)", _filename.c_str(), dlerror()); - _dlHandle = 0; - } + virtual DLObject *makeDLObject() { + return new PSPDLObject(); } }; - -Plugin* PSPPluginProvider::createPlugin(const Common::FSNode &node) const { +Plugin *PSPPluginProvider::createPlugin(const Common::FSNode &node) const { return new PSPPlugin(node.getPath()); } -bool PSPPluginProvider::isPluginFilename(const Common::FSNode &node) const { - // Check the plugin suffix - Common::String filename = node.getName(); - PSP_DEBUG_PRINT("Testing name %s", filename.c_str()); - if (!filename.hasSuffix(".PLG") && !filename.hasSuffix(".plg")) { - PSP_DEBUG_PRINT(" fail.\n"); - return false; - } - - PSP_DEBUG_PRINT(" success!\n"); - return true; -} - #endif // defined(DYNAMIC_MODULES) && defined(__PSP__) + diff --git a/backends/plugins/psp/psp-provider.h b/backends/plugins/psp/psp-provider.h index d6c44c5a85..39e0d32caa 100644 --- a/backends/plugins/psp/psp-provider.h +++ b/backends/plugins/psp/psp-provider.h @@ -18,26 +18,24 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL$ - * $Id$ + * $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 $ * */ -#ifndef BACKENDS_PLUGINS_PSP_PSP_PROVIDER_H -#define BACKENDS_PLUGINS_PSP_PSP_PROVIDER_H - -#include "base/plugins.h" - #if defined(DYNAMIC_MODULES) && defined(__PSP__) -class PSPPluginProvider : public FilePluginProvider { -protected: - Plugin* createPlugin(const Common::FSNode &node) const; +#ifndef BACKENDS_PLUGINS_PSP_PSP_PROVIDER_H +#define BACKENDS_PLUGINS_PSP_PSP_PROVIDER_H - bool isPluginFilename(const Common::FSNode &node) const; +#include "backends/plugins/elf/elf-provider.h" +class PSPPluginProvider : public ELFPluginProvider { +public: + Plugin *createPlugin(const Common::FSNode &node) const; }; +#endif // BACKENDS_PLUGINS_PSP_PROVIDER_H + #endif // defined(DYNAMIC_MODULES) && defined(__PSP__) -#endif /* BACKENDS_PLUGINS_PSP_PSP_PROVIDER_H */ diff --git a/backends/plugins/wii/plugin.ld b/backends/plugins/wii/plugin.ld new file mode 100644 index 0000000000..61b90d3394 --- /dev/null +++ b/backends/plugins/wii/plugin.ld @@ -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); diff --git a/backends/plugins/wii/wii-provider.cpp b/backends/plugins/wii/wii-provider.cpp new file mode 100644 index 0000000000..25f54f02de --- /dev/null +++ b/backends/plugins/wii/wii-provider.cpp @@ -0,0 +1,75 @@ +/* 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$ + * $Id$ + * + */ + +#if defined(DYNAMIC_MODULES) && defined(__WII__) + +#include <malloc.h> +#include <ogc/cache.h> + +#include "backends/plugins/wii/wii-provider.h" +#include "backends/plugins/elf/ppc-loader.h" + +class WiiDLObject : public PPCDLObject { +public: + WiiDLObject() : + PPCDLObject() { + } + + virtual ~WiiDLObject() { + unload(); + } + +protected: + virtual void *allocSegment(size_t boundary, size_t size) const { + return memalign(boundary, size); + } + + virtual void freeSegment(void *segment) const { + free(segment); + } + + virtual void flushDataCache(void *ptr, uint32 len) const { + DCFlushRange(ptr, len); + ICInvalidateRange(ptr, len); + } +}; + +class WiiPlugin : public ELFPlugin { +public: + WiiPlugin(const Common::String &filename) : + ELFPlugin(filename) { + } + + virtual DLObject *makeDLObject() { + return new WiiDLObject(); + } +}; + +Plugin *WiiPluginProvider::createPlugin(const Common::FSNode &node) const { + return new WiiPlugin(node.getPath()); +} + +#endif // defined(DYNAMIC_MODULES) && defined(__WII__) + diff --git a/backends/plugins/wii/wii-provider.h b/backends/plugins/wii/wii-provider.h new file mode 100644 index 0000000000..4ec771490d --- /dev/null +++ b/backends/plugins/wii/wii-provider.h @@ -0,0 +1,41 @@ +/* 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$ + * $Id$ + * + */ + +#if defined(DYNAMIC_MODULES) && defined(__WII__) + +#ifndef BACKENDS_PLUGINS_WII_PROVIDER_H +#define BACKENDS_PLUGINS_WII_PROVIDER_H + +#include "backends/plugins/elf/elf-provider.h" + +class WiiPluginProvider : public ELFPluginProvider { +public: + Plugin *createPlugin(const Common::FSNode &node) const; +}; + +#endif // BACKENDS_PLUGINS_WII_PROVIDER_H + +#endif // defined(DYNAMIC_MODULES) && defined(__WII__) + |