diff options
Diffstat (limited to 'backends')
55 files changed, 2576 insertions, 1010 deletions
diff --git a/backends/fs/psp/psp-stream.h b/backends/fs/psp/psp-stream.h index 9fd1ad0470..673630b685 100644 --- a/backends/fs/psp/psp-stream.h +++ b/backends/fs/psp/psp-stream.h @@ -35,39 +35,25 @@   */  class PSPIoStream : public StdioStream, public Suspendable {  protected: -	Common::String _path; -	int _fileSize; -	bool _writeMode;	// for resuming in the right mode -	int _physicalPos;	// position in the real file -	int _pos;			// position. Sometimes virtual -	bool _inCache;		// whether we're in cache (virtual) mode -	bool _eos;			// EOS flag -	 +	Common::String _path;			/* Need to maintain for reopening after suspend */ +	bool _writeMode;				/* "" */ +	int _pos;						/* "" */ +	mutable int _ferror;			/* Save file ferror */ +	mutable bool _feof;						/* and eof */ +  	enum {  		SuspendError = 2,  		ResumeError = 3  	}; -	enum { -		CACHE_SIZE = 1024, -		MIN_READ_SIZE = 1024	// reading less than 1024 takes exactly the same time as 1024 -	}; -	 -	// For caching -	char *_cache; -	int _cacheStartOffset;		// starting offset of the cache. -1 when cache is invalid -	 -	mutable int _ferror;		// file error state -	int _errorSuspend;			// for debugging +	int _errorSuspend;  	mutable int _errorSource; + +	// Error checking  	int _errorPos;  	void * _errorHandle;  	int _suspendCount; -	bool synchronizePhysicalPos();		// synchronize the physical and virtual positions -	bool isOffsetInCache(uint32 pos);	// check if an offset is found in cache -	bool isCacheValid() { return _cacheStartOffset != -1; } -	  public:  	/** diff --git a/backends/module.mk b/backends/module.mk index e0a3f4c683..c0457d8062 100644 --- a/backends/module.mk +++ b/backends/module.mk @@ -22,6 +22,12 @@ MODULE_OBJS := \  	midi/timidity.o \  	midi/dmedia.o \  	midi/windows.o \ +	plugins/elf-loader.o \ +	plugins/mips-loader.o \ +	plugins/shorts-segment-manager.o \ +	plugins/arm-loader.o \ +	plugins/elf-provider.o \ +	plugins/dc/dc-provider.o \  	plugins/posix/posix-provider.o \  	plugins/sdl/sdl-provider.o \  	plugins/win32/win32-provider.o \ @@ -43,7 +49,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 +61,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) diff --git a/backends/platform/ds/arm7/source/main.cpp b/backends/platform/ds/arm7/source/main.cpp index bcaaf8e936..75f7012ed0 100644 --- a/backends/platform/ds/arm7/source/main.cpp +++ b/backends/platform/ds/arm7/source/main.cpp @@ -40,7 +40,7 @@  #include <system.h>  #include <stdlib.h>  #include <string.h> -#include <registers_alt.h>		// Needed for SOUND_CR +#include <registers_alt.h>	// Needed for SOUND_CR  #include <NDS/scummvm_ipc.h>  //////////////////////////////////////////////////////////////////////  #ifdef USE_DEBUGGER @@ -592,7 +592,7 @@ int main(int argc, char ** argv) {    IPC->reset = false; - //fifoInit(); +  //fifoInit();    for (int r = 0; r < 8; r++) {  	IPC->adpcm.arm7Buffer[r] = (u8 *) malloc(512); diff --git a/backends/platform/ds/arm9/makefile b/backends/platform/ds/arm9/makefile index eedf75c256..c9a665c442 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 = 1 +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,9 +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.	  	else  		ifdef DS_BUILD_I @@ -75,7 +76,7 @@ else  			ifdef DS_BUILD_K  			else -		#		USE_MAD = 1 +				#USE_MAD = 1  			endif  		endif  	endif @@ -112,7 +113,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 +121,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 +188,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 +237,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_FANCY_THEMES -DVECTOR_RENDERER_FORMAT=1555 -DDISABLE_DOSBOX_OPL -DDISABLE_DEFAULT_SAVEFILEMANAGER -DARM +DEFINES += -D__DS__ -DNDS -DARM9 -DNONSTANDARD_PORT -DDISABLE_FANCY_THEMES -DVECTOR_RENDERER_FORMAT=1555 -DDISABLE_DOSBOX_OPL -DDISABLE_DEFAULT_SAVEFILEMANAGER -DELF_LOADER_TARGET -DARM -DARM_TARGET#-DNEW_PLUGIN_DESIGN_FIRST_REFINEMENT  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 +253,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 +266,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/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/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,12 +352,13 @@ 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 + +ndsall: plugins +	make -f makefile scummvm.nds scummvm.ds.gba  include $(srcdir)/Makefile.common @@ -354,11 +367,10 @@ semiclean:  clean:  	$(RM) $(OBJS) $(EXECUTABLE) -	rm -fr $(BUILD) +	rm -rf *.h engines plugins scummvm.nds scummvm.ds.gba  dist : SCUMMVM.BIN plugins plugin_dist -  #---------------------------------------------------------------------------------  # canned command sequence for binary data  #--------------------------------------------------------------------------------- @@ -400,13 +412,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 95bfdfe40a..4c7d6b89ae 100644 --- a/backends/platform/ds/arm9/source/dsmain.cpp +++ b/backends/platform/ds/arm9/source/dsmain.cpp @@ -105,6 +105,8 @@  #endif  #include "engine.h" +#include "backends/plugins/ds/ds-provider.h" +#include "backends/plugins/elf-provider.h"  #include "backends/fs/ds/ds-fs.h"  #include "base/version.h"  #include "common/util.h" @@ -3213,6 +3215,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); diff --git a/backends/platform/ds/arm9/source/fat/io_nmmc.c b/backends/platform/ds/arm9/source/fat/io_nmmc.c index 6c996f5de1..261096a27b 100644 --- a/backends/platform/ds/arm9/source/fat/io_nmmc.c +++ b/backends/platform/ds/arm9/source/fat/io_nmmc.c @@ -170,7 +170,7 @@ bool NMMC_IsInserted(void)	{  	Neo_EnableMMC( true );		// Open SPI port to MMC card  	Neo_SendMMCCommand(MMC_SEND_CSD, 0); -	if( Neo_CheckMMCResponse( 0x00, 0xFF ) == false )	{				// Make sure no errors occurred +	if( Neo_CheckMMCResponse( 0x00, 0xFF ) == false )	{				// Make sure no errors occured  		Neo_EnableMMC( false );  		return false;  	} @@ -227,14 +227,14 @@ bool NMMC_StartUp(void) {  	// Set block length  	Neo_SendMMCCommand(MMC_SET_BLOCKLEN, BYTE_PER_READ ); -	if( Neo_CheckMMCResponse( 0x00, 0xFF ) == false )	{				// Make sure no errors occurred +	if( Neo_CheckMMCResponse( 0x00, 0xFF ) == false )	{				// Make sure no errors occured  		Neo_EnableMMC( false );  		return false;  	}  	// Check if we can use a higher SPI frequency  	Neo_SendMMCCommand(MMC_SEND_CSD, 0); -	if( Neo_CheckMMCResponse( 0x00, 0xFF ) == false )	{				// Make sure no errors occurred +	if( Neo_CheckMMCResponse( 0x00, 0xFF ) == false )	{				// Make sure no errors occured  		Neo_EnableMMC( false );  		return false;  	} @@ -268,7 +268,7 @@ bool NMMC_WriteSectors (u32 sector, u8 numSecs, void* buffer)  	Neo_EnableMMC( true );												// Open SPI port to MMC card  	Neo_SendMMCCommand( 25, sector ); -	if( Neo_CheckMMCResponse( 0x00, 0xFF ) == false )	{				// Make sure no errors occurred +	if( Neo_CheckMMCResponse( 0x00, 0xFF ) == false )	{				// Make sure no errors occured  		Neo_EnableMMC( false );  		return false;  	} @@ -318,7 +318,7 @@ bool NMMC_ReadSectors (u32 sector, u8 numSecs, void* buffer)  	while (totalSecs--) {  		Neo_SendMMCCommand(MMC_READ_BLOCK, sector ); -		if( Neo_CheckMMCResponse( 0x00, 0xFF ) == false )	{			// Make sure no errors occurred +		if( Neo_CheckMMCResponse( 0x00, 0xFF ) == false )	{			// Make sure no errors occured  			Neo_EnableMMC( false );  			return false;  		} diff --git a/backends/platform/gp2x/graphics.cpp b/backends/platform/gp2x/graphics.cpp index 4a3c668c52..1888cbe47c 100644 --- a/backends/platform/gp2x/graphics.cpp +++ b/backends/platform/gp2x/graphics.cpp @@ -1405,6 +1405,7 @@ void OSystem_GP2X::drawMouse() {  	SDL_Rect zoomdst;  	SDL_Rect dst;  	int scale; +	int width, height;  	int hotX, hotY;  	int tmpScreenWidth, tmpScreenHeight; @@ -1425,12 +1426,16 @@ void OSystem_GP2X::drawMouse() {  	if (!_overlayVisible) {  		scale = _videoMode.scaleFactor; +		width = _videoMode.screenWidth; +		height = _videoMode.screenHeight;  		dst.w = _mouseCurState.vW;  		dst.h = _mouseCurState.vH;  		hotX = _mouseCurState.vHotX;  		hotY = _mouseCurState.vHotY;  	} else {  		scale = 1; +		width = _videoMode.overlayWidth; +		height = _videoMode.overlayHeight;  		dst.w = _mouseCurState.rW;  		dst.h = _mouseCurState.rH;  		hotX = _mouseCurState.rHotX; diff --git a/backends/platform/gp2xwiz/gp2xwiz-graphics.cpp b/backends/platform/gp2xwiz/gp2xwiz-graphics.cpp index f6ad226d42..921558131a 100644 --- a/backends/platform/gp2xwiz/gp2xwiz-graphics.cpp +++ b/backends/platform/gp2xwiz/gp2xwiz-graphics.cpp @@ -149,6 +149,7 @@ void OSystem_GP2XWIZ::drawMouse() {  	SDL_Rect dst;  	int scale; +	int width, height;  	int hotX, hotY;  	if (_videoMode.mode == GFX_HALF && !_overlayVisible){ @@ -161,12 +162,16 @@ void OSystem_GP2XWIZ::drawMouse() {  	if (!_overlayVisible) {  		scale = _videoMode.scaleFactor; +		width = _videoMode.screenWidth; +		height = _videoMode.screenHeight;  		dst.w = _mouseCurState.vW;  		dst.h = _mouseCurState.vH;  		hotX = _mouseCurState.vHotX;  		hotY = _mouseCurState.vHotY;  	} else {  		scale = 1; +		width = _videoMode.overlayWidth; +		height = _videoMode.overlayHeight;  		dst.w = _mouseCurState.rW;  		dst.h = _mouseCurState.rH;  		hotX = _mouseCurState.rHotX; diff --git a/backends/platform/gp2xwiz/gp2xwiz-main.cpp b/backends/platform/gp2xwiz/gp2xwiz-main.cpp index 394c3090c3..8c95a94639 100644 --- a/backends/platform/gp2xwiz/gp2xwiz-main.cpp +++ b/backends/platform/gp2xwiz/gp2xwiz-main.cpp @@ -42,7 +42,6 @@  #include "base/main.h"  #include "backends/saves/default/default-saves.h" -  #include "backends/timer/default/default-timer.h"  #include "sound/mixer_intern.h" @@ -64,7 +63,7 @@ int main(int argc, char *argv[]) {  #ifdef DYNAMIC_MODULES  	PluginManager::instance().addPluginProvider(new POSIXPluginProvider()); -#endif +#endif /* DYNAMIC_MODULES */  	// Invoke the actual ScummVM main entry point:  	int res = scummvm_main(argc, argv); diff --git a/backends/platform/gp2xwiz/module.mk b/backends/platform/gp2xwiz/module.mk index edf2f2a717..c76238f679 100644 --- a/backends/platform/gp2xwiz/module.mk +++ b/backends/platform/gp2xwiz/module.mk @@ -4,7 +4,8 @@ MODULE_OBJS := \  	gp2xwiz-events.o \  	gp2xwiz-graphics.o \  	gp2xwiz-hw.o \ -	gp2xwiz-main.o +	gp2xwiz-main.o \ +	gp2xwiz-loader.o  # We don't use rules.mk but rather manually update OBJS and MODULE_DIRS.  MODULE_OBJS := $(addprefix $(MODULE)/, $(MODULE_OBJS)) diff --git a/backends/platform/linuxmoto/linuxmoto-graphics.cpp b/backends/platform/linuxmoto/linuxmoto-graphics.cpp index a39416ebc4..d66d41dfab 100644 --- a/backends/platform/linuxmoto/linuxmoto-graphics.cpp +++ b/backends/platform/linuxmoto/linuxmoto-graphics.cpp @@ -168,6 +168,7 @@ void OSystem_LINUXMOTO::drawMouse() {  	SDL_Rect dst;  	int scale; +	int width, height;  	int hotX, hotY;  	if (_videoMode.mode == GFX_HALF && !_overlayVisible) { @@ -180,12 +181,16 @@ void OSystem_LINUXMOTO::drawMouse() {  	if (!_overlayVisible) {  		scale = _videoMode.scaleFactor; +		width = _videoMode.screenWidth; +		height = _videoMode.screenHeight;  		dst.w = _mouseCurState.vW;  		dst.h = _mouseCurState.vH;  		hotX = _mouseCurState.vHotX;  		hotY = _mouseCurState.vHotY;  	} else {  		scale = 1; +		width = _videoMode.overlayWidth; +		height = _videoMode.overlayHeight;  		dst.w = _mouseCurState.rW;  		dst.h = _mouseCurState.rH;  		hotX = _mouseCurState.rHotX; diff --git a/backends/platform/ps2/Makefile.ps2 b/backends/platform/ps2/Makefile.ps2 index d2a8d210e4..f836bd3eaa 100644 --- a/backends/platform/ps2/Makefile.ps2 +++ b/backends/platform/ps2/Makefile.ps2 @@ -1,22 +1,45 @@  # $Header: Exp $   include $(PS2SDK)/Defs.make -PS2_EXTRA = /works/devel/ps2/sdk-extra +PS2_EXTRA = /home/tony/GSOC/ps2/sdk-extra  PS2_EXTRA_INCS = /zlib/include /libmad/ee/include /SjPcm/ee/src /tremor  PS2_EXTRA_LIBS = /zlib/lib /libmad/ee/lib /SjPcm/ee/lib /tremor/tremor -ENABLED=STATIC_PLUGIN +# Set to 1 to enable, 0 to disable dynamic modules +DYNAMIC_MODULES = 1 +# Set to 1 to enable, 0 to disable more detailed printing of gcc commands +VERBOSE_BUILD=0 + +# Test for dynamic plugins +ifeq ($(DYNAMIC_MODULES),1) +ENABLED = DYNAMIC_PLUGIN +DEFINES = -DDYNAMIC_MODULES +PRE_OBJS_FLAGS = -Wl,--whole-archive +POST_OBJS_FLAGS = -Wl,--no-whole-archive +else +ENABLED = STATIC_PLUGIN +endif + +#control build +DISABLE_SCALERS = true +DISABLE_HQ_SCALERS = true  ENABLE_SCUMM = $(ENABLED)  ENABLE_SCUMM_7_8 = $(ENABLED)  ENABLE_HE = $(ENABLED)  ENABLE_AGI = $(ENABLED)  ENABLE_AGOS = $(ENABLED) +ENABLE_AGOS2 = $(ENABLED)  ENABLE_CINE = $(ENABLED)  ENABLE_CRUISE = $(ENABLED) +ENABLE_DRACI = $(ENABLED)  ENABLE_DRASCULA = $(ENABLED)  ENABLE_GOB = $(ENABLED) +ENABLE_GROOVIE = $(ENABLED) +# ENABLE_GROOVIE2 = $(ENABLED) +ENABLE_IHNM = $(ENABLED)  ENABLE_KYRA = $(ENABLED) +# ENABLE_LOL = $(ENABLED)  ENABLE_LURE = $(ENABLED)  # ENABLE_M4 = $(ENABLED)  ENABLE_MADE = $(ENABLED) @@ -24,16 +47,18 @@ ENABLE_PARALLACTION = $(ENABLED)  ENABLE_QUEEN = $(ENABLED)  ENABLE_SAGA = $(ENABLED)  ENABLE_SAGA2 = $(ENABLED) -ENABLE_IHNM = $(ENABLED) +ENABLE_SCI = $(ENABLED) +# ENABLE_SCI32 = $(ENABLED)  ENABLE_SKY = $(ENABLED)  ENABLE_SWORD1 = $(ENABLED)  ENABLE_SWORD2 = $(ENABLED) -# ENABLE_TINSEL = $(ENABLED) +ENABLE_TEENAGENT = $(ENABLED) +ENABLE_TINSEL = $(ENABLED)  ENABLE_TOUCHE = $(ENABLED) +ENABLE_TUCKER = $(ENABLED)  HAVE_GCC3 = true - -CC		= ee-gcc +CC      = ee-gcc  CXX     = ee-g++  AS      = ee-gcc  LD      = ee-gcc @@ -42,51 +67,62 @@ RANLIB  = ee-ranlib  STRIP   = ee-strip  MKDIR   = mkdir -p  RM      = rm -f +RM_REC  = rm -rf +MODULE_DIRS = ./  srcdir = ../../..  VPATH = $(srcdir)  INCDIR = ../../../ -# DEPDIR = .deps +DEPDIR = .deps -DEFINES  = -DUSE_VORBIS -DUSE_TREMOR -DUSE_MAD -DUSE_ZLIB -DFORCE_RTL -D_EE -D__PLAYSTATION2__ -O2 -Wall -Wno-multichar +TARGET = elf/scummvm.elf +DEFINES += -DUSE_VORBIS -DUSE_TREMOR -DUSE_MAD -DUSE_ZLIB -DFORCE_RTL -DDISABLE_SAVEGAME_SORTING -D_EE -D__PLAYSTATION2__ -G2 -O2 -Wall -Wno-multichar -fno-rtti -fno-exceptions -DNO_ADAPTOR +DEFINES += -DELF_LOADER_TARGET -DMIPS_TARGET#-DNEW_PLUGIN_DESIGN_FIRST_REFINEMENT  INCLUDES  = $(addprefix -I$(PS2_EXTRA),$(PS2_EXTRA_INCS))   INCLUDES += -I $(PS2SDK)/ee/include -I $(PS2SDK)/common/include -I ./common -I . -I $(srcdir) -I $(srcdir)/engines -TARGET = elf/scummvm.elf +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 = $(srcdir)/backends/plugins/plugin.syms elf/scummvm.elf +PLUGIN_LDFLAGS += -mno-crt0 $(PS2SDK)/ee/startup/crt0.o +PLUGIN_LDFLAGS += -nostartfiles -Wl,-q,--just-symbols,elf/scummvm.elf,-T$(srcdir)/backends/plugins/ps2/plugin.ld,--retain-symbols-file,$(srcdir)/backends/plugins/plugin.syms -lstdc++ -lc -OBJS := backends/platform/ps2/DmaPipe.o \ -    backends/platform/ps2/Gs2dScreen.o \ -    backends/platform/ps2/irxboot.o \ -	backends/platform/ps2/ps2input.o \ -	backends/platform/ps2/ps2pad.o \ -	backends/platform/ps2/savefilemgr.o \ -    backends/platform/ps2/fileio.o \ -    backends/platform/ps2/asyncfio.o \ -	backends/platform/ps2/icon.o \ -    backends/platform/ps2/cd.o \ -    backends/platform/ps2/eecodyvdfs.o \ -    backends/platform/ps2/rpckbd.o \ -    backends/platform/ps2/systemps2.o \ -    backends/platform/ps2/ps2mutex.o \ -    backends/platform/ps2/ps2time.o \ -	backends/platform/ps2/ps2debug.o -     -MODULE_DIRS += .  BACKEND := ps2  include $(srcdir)/Makefile.common -LDFLAGS += -mno-crt0 $(PS2SDK)/ee/startup/crt0.o -T $(PS2SDK)/ee/startup/linkfile  +LDFLAGS = -mno-crt0 $(PS2SDK)/ee/startup/crt0.o -T $(srcdir)/backends/plugins/ps2/main_prog.ld  LDFLAGS += -L $(PS2SDK)/ee/lib -L . -LDFLAGS += $(addprefix -L$(PS2_EXTRA),$(PS2_EXTRA_LIBS))  +LDFLAGS += $(addprefix -L$(PS2_EXTRA),$(PS2_EXTRA_LIBS))  LDFLAGS += -lmc -lpad -lmouse -lhdd -lpoweroff -lsjpcm -lmad -ltremor -lz -lm -lc -lfileXio -lkernel -lstdc++  -LDFLAGS += -s  + +OBJS := $(srcdir)/backends/platform/ps2/DmaPipe.o \ +	$(srcdir)/backends/platform/ps2/Gs2dScreen.o \ +	$(srcdir)/backends/platform/ps2/irxboot.o \ +	$(srcdir)/backends/platform/ps2/ps2input.o \ +	$(srcdir)/backends/platform/ps2/ps2pad.o \ +	$(srcdir)/backends/platform/ps2/savefilemgr.o \ +	$(srcdir)/backends/platform/ps2/fileio.o \ +	$(srcdir)/backends/platform/ps2/asyncfio.o \ +	$(srcdir)/backends/platform/ps2/icon.o \ +	$(srcdir)/backends/platform/ps2/cd.o \ +	$(srcdir)/backends/platform/ps2/eecodyvdfs.o \ +	$(srcdir)/backends/platform/ps2/rpckbd.o \ +	$(srcdir)/backends/platform/ps2/systemps2.o \ +	$(srcdir)/backends/platform/ps2/ps2mutex.o \ +	$(srcdir)/backends/platform/ps2/ps2time.o \ +	$(srcdir)/backends/platform/ps2/ps2debug.o + +include $(srcdir)/Makefile.common  all: $(TARGET)  $(TARGET): $(OBJS) -	$(LD) $^ $(LDFLAGS) -o $@ +	$(LD) $(PRE_OBJS_FLAGS) $(OBJS) $(POST_OBJS_FLAGS) $(LDFLAGS) -o $@ diff --git a/backends/platform/ps2/elf32.h b/backends/platform/ps2/elf32.h new file mode 100644 index 0000000000..616cc4b4d2 --- /dev/null +++ b/backends/platform/ps2/elf32.h @@ -0,0 +1,209 @@ +/* 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 + +/* ELF stuff */ + +typedef unsigned short Elf32_Half, Elf32_Section; +typedef unsigned int Elf32_Word, Elf32_Addr, Elf32_Off; +typedef signed int  Elf32_Sword; +typedef Elf32_Half Elf32_Versym; + +#define EI_NIDENT (16) +#define SELFMAG         6 + +/* ELF File format structures. Look up ELF structure for more details */ + +// ELF header (contains info about the file) +typedef struct { +	unsigned char 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\1\1"	/* ELF Magic number */ + +// 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 + + +// 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 */ + +// 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 */ +#define SHT_MIPS_CONFLICT	0x70000002	/* Conflicts btw executables and shared objects */ +#define SHT_MIPS_GPTAB		0x70000003	/* Global pointer table */ + +// 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 */ + + +// 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 */ +	unsigned char st_info;                /* Symbol type and binding */ +	unsigned char 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 (info about how to relocate) +typedef struct { +	Elf32_Addr    r_offset;               /* Address */ +	Elf32_Word    r_info;                 /* Relocation type and symbol index */ +} Elf32_Rel; + +// Access macros for the relocation info +#define REL_TYPE(x)		((x)&0xFF)			/* 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 + +// Mock function to get value of global pointer +#define getGP()	({	\ +	unsigned int __valgp;	\ +	__asm__ ("add %0, $gp, $0" : "=r"(__valgp) : ); \ +	__valgp; \ +}) + +#endif /* BACKENDS_ELF_H */ diff --git a/backends/platform/ps2/module.mk b/backends/platform/ps2/module.mk index bf95a5501d..a12d10771f 100644 --- a/backends/platform/ps2/module.mk +++ b/backends/platform/ps2/module.mk @@ -16,7 +16,8 @@ MODULE_OBJS := \      systemps2.o \      ps2mutex.o \      ps2time.o \ -	ps2debug.o +	ps2debug.o \ +	ps2loader.o  # We don't use rules.mk but rather manually update OBJS and MODULE_DIRS.  MODULE_OBJS := $(addprefix $(MODULE)/, $(MODULE_OBJS)) diff --git a/backends/platform/ps2/systemps2.cpp b/backends/platform/ps2/systemps2.cpp index 7659d5194d..357404c5c4 100644 --- a/backends/platform/ps2/systemps2.cpp +++ b/backends/platform/ps2/systemps2.cpp @@ -59,6 +59,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" @@ -105,7 +107,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); @@ -130,8 +131,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); @@ -337,6 +341,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 617ef7c8cc..9c011220b8 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 -DELF_LOADER_TARGET -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/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/plugin.syms -lstdc++ -lc  # PSP-specific variables  STRIP   = psp-strip @@ -125,8 +125,7 @@ endif  # PSP LIBS  PSPLIBS =  -lpspprof -lpspvfpu -lpspdebug -lpspgu -lpspge -lpspdisplay -lpspctrl -lpspsdk \ -	-lpsputility -lpspuser -lpsppower -lpsphprm -lpspsdk -lpsprtc -lpspaudio -lpspaudiocodec \ -	-lpspkernel +	-lpsputility -lpspuser -lpsppower -lpsphprm -lpspsdk -lpsprtc -lpspaudio -lpspkernel  # Add in PSPSDK includes and libraries.  LIBS     += -lpng -lz -lstdc++ -lc -lm $(PSPLIBS) @@ -150,6 +149,7 @@ OBJS := powerman.o \  	mp3.o \  	tests.o +  BACKEND := psp  # Include common Scummvm makefile diff --git a/backends/platform/psp/audio.cpp b/backends/platform/psp/audio.cpp index e540733162..14691befee 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 eeba598fed..07f70cec7d 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 71b505ec7c..6360772c96 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 5037543f12..544e5a1b25 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 1f7320902c..72f252faae 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 4fe7cb3f92..2a91ce455a 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/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/thread.cpp b/backends/platform/psp/thread.cpp index 916b1e553b..e757c2f575 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 de1c10a2aa..44394af40a 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/samsungtv/main.cpp b/backends/platform/samsungtv/main.cpp index 2c025b750c..a6b8376912 100644 --- a/backends/platform/samsungtv/main.cpp +++ b/backends/platform/samsungtv/main.cpp @@ -43,7 +43,7 @@ extern "C" int Game_Main(char *path, char *) {  	// Invoke the actual ScummVM main entry point:  	int res = scummvm_main(0, 0); -	((OSystem_SDL *)g_system)->deinit(); +	g_system->quit();	// TODO: Consider removing / replacing this!  	return res;  } diff --git a/backends/platform/sdl/graphics.cpp b/backends/platform/sdl/graphics.cpp index a97a153f3c..aec90d1352 100644 --- a/backends/platform/sdl/graphics.cpp +++ b/backends/platform/sdl/graphics.cpp @@ -1693,6 +1693,7 @@ void OSystem_SDL::drawMouse() {  	SDL_Rect dst;  	int scale; +	int width, height;  	int hotX, hotY;  	dst.x = _mouseCurState.x; @@ -1700,12 +1701,16 @@ void OSystem_SDL::drawMouse() {  	if (!_overlayVisible) {  		scale = _videoMode.scaleFactor; +		width = _videoMode.screenWidth; +		height = _videoMode.screenHeight;  		dst.w = _mouseCurState.vW;  		dst.h = _mouseCurState.vH;  		hotX = _mouseCurState.vHotX;  		hotY = _mouseCurState.vHotY;  	} else {  		scale = 1; +		width = _videoMode.overlayWidth; +		height = _videoMode.overlayHeight;  		dst.w = _mouseCurState.rW;  		dst.h = _mouseCurState.rH;  		hotX = _mouseCurState.rHotX; diff --git a/backends/platform/sdl/main.cpp b/backends/platform/sdl/main.cpp index 52bbb59165..ef95a6d256 100644 --- a/backends/platform/sdl/main.cpp +++ b/backends/platform/sdl/main.cpp @@ -64,7 +64,7 @@ int main(int argc, char *argv[]) {  	// Invoke the actual ScummVM main entry point:  	int res = scummvm_main(argc, argv); -	((OSystem_SDL *)g_system)->deinit(); +	g_system->quit();	// TODO: Consider removing / replacing this!  	return res;  } diff --git a/backends/platform/sdl/sdl.cpp b/backends/platform/sdl/sdl.cpp index 6686249416..5c50a43daf 100644 --- a/backends/platform/sdl/sdl.cpp +++ b/backends/platform/sdl/sdl.cpp @@ -483,7 +483,7 @@ bool OSystem_SDL::getFeatureState(Feature f) {  	}  } -void OSystem_SDL::deinit() { +void OSystem_SDL::quit() {  	if (_cdrom) {  		SDL_CDStop(_cdrom);  		SDL_CDClose(_cdrom); @@ -505,14 +505,10 @@ void OSystem_SDL::deinit() {  	SDL_Quit(); -	// Event Manager requires save manager for storing +	// Even Manager requires save manager for storing  	// recorded events  	delete getEventManager();  	delete _savefile; -} - -void OSystem_SDL::quit() { -	deinit();  #if !defined(SAMSUNGTV)  	exit(0); diff --git a/backends/platform/sdl/sdl.h b/backends/platform/sdl/sdl.h index 5c901ba711..ace07f349e 100644 --- a/backends/platform/sdl/sdl.h +++ b/backends/platform/sdl/sdl.h @@ -202,8 +202,6 @@ public:  	// Quit  	virtual void quit(); // overloaded by CE backend -	void deinit(); -  	virtual void getTimeAndDate(TimeDate &t) const;  	virtual Common::TimerManager *getTimerManager(); diff --git a/backends/plugins/arm-loader.cpp b/backends/plugins/arm-loader.cpp new file mode 100644 index 0000000000..7e8269220b --- /dev/null +++ b/backends/plugins/arm-loader.cpp @@ -0,0 +1,169 @@ +/* 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(ARM_TARGET) + +#include "backends/fs/ds/ds-fs.h" +#include "elf-loader.h" +#include "dsmain.h" +#include "arm-loader.h" + +#define __DEBUG_PLUGINS__ + +#ifdef __DEBUG_PLUGINS__ +#define DBG(x,...) consolePrintf(x, ## __VA_ARGS__) +#else +#define DBG(x,...) +#endif + +#define seterror(x,...) consolePrintf(x, ## __VA_ARGS__) + +/** + * Follow the instruction of a relocation section. + * + * @param DLFile 	 SeekableReadStream of File + * @param offset 	 Offset into the File + * @param size   	 Size of relocation section + * + */ +bool ARMDLObject::relocate(Common::SeekableReadStream* DLFile, unsigned long offset, unsigned long size, void *relSegment) { +	Elf32_Rel *rel = NULL; //relocation entry + +	// Allocate memory for relocation table +	if (!(rel = (Elf32_Rel *)malloc(size))) { +		seterror("Out of memory."); +		return false; +	} + +	// Read in our relocation table +	if (DLFile->seek(offset, SEEK_SET) < 0 || +	        DLFile->read(rel, size) != (ssize_t)size) { +		seterror("Relocation table load failed."); +		free(rel); +		return false; +	} + +	// Treat each relocation entry. Loop over all of them +	int cnt = size / sizeof(*rel); + +	DBG("Loaded relocation table. %d entries. base address=%p\n", cnt, relSegment); + +	int a = 0; +	unsigned int relocation = 0; + +	// 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); + +		unsigned int 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; + +				DBG("R_ARM_ABS32: i=%d, a=%x, origTarget=%x, target=%x\n", i, a, origTarget, *target); +			} +			break; + +		case R_ARM_THM_CALL: +			DBG("R_ARM_THM_CALL: PC-relative jump, ld takes care of necessary relocation work for us.\n"); +			break; + +		case R_ARM_CALL: +			DBG("R_ARM_CALL: PC-relative jump, ld takes care of necessary relocation work for us.\n"); +			break; + +		case R_ARM_JUMP24: +			DBG("R_ARM_JUMP24: PC-relative jump, ld takes care of all relocation work for us.\n"); +			break; + +		case R_ARM_TARGET1: +			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; + +				DBG("R_ARM_TARGET1: i=%d, a=%x, origTarget=%x, target=%x\n", i, a, origTarget, *target); +				DBG("Make sure --target1-abs is a flag to LD!\n"); +			} +			break; + +		case R_ARM_V4BX: +			DBG("R_ARM_V4BX: No relocation calculation necessary.\n"); +			break; + +		default: +			seterror("Unknown relocation type %d.", REL_TYPE(rel[i].r_info)); +			free(rel); +			return false; +		} + +	} + +	free(rel); +	return true; +} + +bool ARMDLObject::relocateRels(Common::SeekableReadStream* DLFile, Elf32_Ehdr *ehdr, Elf32_Shdr *shdr) { + +	// Loop over sections, finding relocation sections +	for (int 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 +		        (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 (curShdr->sh_type == SHT_RELA) { +				seterror("RELA entries not supported yet!\n"); +				return false; +			} + +			if (!relocate(DLFile, curShdr->sh_offset, curShdr->sh_size, _segment)) { +				return false; +			} + +		} +	} + +	return true; +} + +#endif /* defined(DYNAMIC_MODULES) && defined(ARM_TARGET) */ diff --git a/backends/plugins/arm-loader.h b/backends/plugins/arm-loader.h new file mode 100644 index 0000000000..7f7a1f7f4b --- /dev/null +++ b/backends/plugins/arm-loader.h @@ -0,0 +1,37 @@ +/* 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/fs/ds/ds-fs.h" +#include "elf-loader.h" +#include "dsmain.h" + +class ARMDLObject : public DLObject { +protected: +    bool relocate(Common::SeekableReadStream* DLFile, unsigned long offset, unsigned long size, void *relSegment); +    bool relocateRels(Common::SeekableReadStream* DLFile, Elf32_Ehdr *ehdr, Elf32_Shdr *shdr); + +public: +    ARMDLObject() : DLObject() {} +}; diff --git a/backends/plugins/ds/ds-provider.cpp b/backends/plugins/ds/ds-provider.cpp new file mode 100644 index 0000000000..7365a2e6e9 --- /dev/null +++ b/backends/plugins/ds/ds-provider.cpp @@ -0,0 +1,45 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#if defined(DYNAMIC_MODULES) && defined(__DS__) + +#include "backends/plugins/arm-loader.h" +#include "backends/plugins/elf-provider.h" +#include "backends/plugins/ds/ds-provider.h" + + +class DSPlugin : public ELFPlugin { +public: +	DSPlugin(const Common::String &filename) : ELFPlugin(filename) {} + +	DLObject *makeDLObject() { return new ARMDLObject(); } +}; + +Plugin* DSPluginProvider::createPlugin(const Common::FSNode &node) const { +	return new DSPlugin(node.getPath()); +} + +#endif // defined(DYNAMIC_MODULES) && defined(ELF_LOADER_TARGET) + diff --git a/backends/plugins/ds/ds-provider.h b/backends/plugins/ds/ds-provider.h new file mode 100644 index 0000000000..462c3e3b63 --- /dev/null +++ b/backends/plugins/ds/ds-provider.h @@ -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-provider.h" + +class DSPluginProvider : public ELFPluginProvider { +	Plugin* createPlugin(const Common::FSNode &node) const; +}; + + diff --git a/backends/plugins/ds/plugin.ld b/backends/plugins/ds/plugin.ld new file mode 100644 index 0000000000..2b2bca9745 --- /dev/null +++ b/backends/plugins/ds/plugin.ld @@ -0,0 +1,218 @@ +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/elf-loader.cpp b/backends/plugins/elf-loader.cpp new file mode 100644 index 0000000000..9787c880ae --- /dev/null +++ b/backends/plugins/elf-loader.cpp @@ -0,0 +1,413 @@ +/* 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(ELF_LOADER_TARGET) + +#include <string.h> +#include <stdarg.h> +#include <stdio.h> +#include <malloc.h>	// for memalign() (Linux specific) +#include <unistd.h> +#include <sys/fcntl.h> +#include <sys/_default_fcntl.h>	// FIXME: Why do we need this DevKitPro specific header? + +#include "common/file.h" +#include "common/fs.h" +#include "elf-loader.h" + +#ifdef __PSP__ +#include "backends/platform/psp/powerman.h" +#include "psputils.h" +#endif + +#ifdef __DS__ +#include <nds.h> +#endif + +#define __DEBUG_PLUGINS__ + +#ifdef __DEBUG_PLUGINS__ +#define DBG(x,...) printf(x, ## __VA_ARGS__) +#else +#define DBG(x,...) +#endif + +#define seterror(x,...) printf(x, ## __VA_ARGS__) + +/** + * Flushes the data cache (Platform Specific). + */ +static void flushDataCache() { +#ifdef __DS__ +  DC_FlushAll(); +#endif +#ifdef __PLAYSTATION2__ +  FlushCache(0); +  FlushCache(2); +#endif +#ifdef __PSP__ +  sceKernelDcacheWritebackAll(); +#endif +} + +// Expel the symbol table from memory +void DLObject::discard_symtab() { +	free(_symtab); +	free(_strtab); +	_symtab = NULL; +	_strtab = NULL; +	_symbol_cnt = 0; +} + +// Unload all objects from memory +void DLObject::unload() { +	discard_symtab(); +	free(_segment); +	_segment = NULL; +} + +bool DLObject::readElfHeader(Common::SeekableReadStream* DLFile, Elf32_Ehdr *ehdr) { + +	// Start reading the elf header. Check for errors +	if (DLFile->read(ehdr, sizeof(*ehdr)) != sizeof(*ehdr) || +	        memcmp(ehdr->e_ident, ELFMAG, SELFMAG) ||			// Check MAGIC +	        ehdr->e_type != ET_EXEC ||							// Check for executable +#ifdef ARM_TARGET +	        ehdr->e_machine != EM_ARM ||						// Check for ARM machine type +#endif +#ifdef MIPS_TARGET +	        ehdr->e_machine != EM_MIPS ||						// Check for MIPS machine type +#endif +	        ehdr->e_phentsize < sizeof(Elf32_Phdr)	 ||			// Check for size of program header +	        ehdr->e_shentsize != sizeof(Elf32_Shdr)) {			// Check for size of section header +		seterror("Invalid file type."); +		return false; +	} + +	DBG("phoff = %d, phentsz = %d, phnum = %d\n", +	    ehdr->e_phoff, ehdr->e_phentsize, ehdr->e_phnum); + +	return true; +} + +bool DLObject::readProgramHeaders(Common::SeekableReadStream* DLFile, Elf32_Ehdr *ehdr, Elf32_Phdr *phdr, int num) { + +	// Read program header +	if (DLFile->seek(ehdr->e_phoff + sizeof(*phdr)*num, SEEK_SET) < 0 || +	    DLFile->read(phdr, sizeof(*phdr)) != sizeof(*phdr)) { +		seterror("Program header load failed."); +		return false; +	} + +	// Check program header values +	if (phdr->p_type != PT_LOAD  || phdr->p_filesz > phdr->p_memsz) { +		seterror("Invalid program header."); +		return false; +	} + +	DBG("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(Common::SeekableReadStream* DLFile, Elf32_Phdr *phdr) { + +	char *baseAddress = 0; + +	// Attempt to allocate memory for segment +	int extra = phdr->p_vaddr % phdr->p_align;	// Get extra length TODO: check logic here +	DBG("extra mem is %x\n", extra); + +	if (!(_segment = (char *)memalign(phdr->p_align, phdr->p_memsz + extra))) { +		seterror("Out of memory.\n"); +		return false; +	} + +	DBG("allocated segment @ %p\n", _segment); + +	// Get offset to load segment into +	baseAddress = (char *)_segment + phdr->p_vaddr; +	_segmentSize = phdr->p_memsz + extra; + +	// Set bss segment to 0 if necessary (assumes bss is at the end) +	if (phdr->p_memsz > phdr->p_filesz) { +		DBG("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); +	} + +	DBG("Reading the segment into memory\n"); + +	// Read the segment into memory +	if (DLFile->seek(phdr->p_offset, SEEK_SET) < 0 || +	        DLFile->read(baseAddress, phdr->p_filesz) != (ssize_t)phdr->p_filesz) { +		seterror("Segment load failed."); +		return false; +	} + +	DBG("Segment has been read into memory\n"); + +	return true; +} + +Elf32_Shdr * DLObject::loadSectionHeaders(Common::SeekableReadStream* DLFile, Elf32_Ehdr *ehdr) { + +	Elf32_Shdr *shdr = NULL; + +	// Allocate memory for section headers +	if (!(shdr = (Elf32_Shdr *)malloc(ehdr->e_shnum * sizeof(*shdr)))) { +		seterror("Out of memory."); +		return NULL; +	} + +	// Read from file into section headers +	if (DLFile->seek(ehdr->e_shoff, SEEK_SET) < 0 || +	        DLFile->read(shdr, ehdr->e_shnum * sizeof(*shdr)) != +	        (ssize_t)(ehdr->e_shnum * sizeof(*shdr))) { +		seterror("Section headers load failed."); +		return NULL; +	} + +	return shdr; +} + +int DLObject::loadSymbolTable(Common::SeekableReadStream* DLFile, Elf32_Ehdr *ehdr, Elf32_Shdr *shdr) { + +	// Loop over sections, looking for symbol table linked to a string table +	for (int 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) { +		seterror("No symbol table."); +		return -1; +	} + +	DBG("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))) { +		seterror("Out of memory."); +		return -1; +	} + +	// Read symbol table into memory +	if (DLFile->seek(shdr[_symtab_sect].sh_offset, SEEK_SET) < 0 || +	        DLFile->read(_symtab, shdr[_symtab_sect].sh_size) != +	        (ssize_t)shdr[_symtab_sect].sh_size) { +		seterror("Symbol table load failed."); +		return -1; +	} + +	// Set number of symbols +	_symbol_cnt = shdr[_symtab_sect].sh_size / sizeof(Elf32_Sym); +	DBG("Loaded %d symbols.\n", _symbol_cnt); + +	return _symtab_sect; + +} + +bool DLObject::loadStringTable(Common::SeekableReadStream* DLFile, Elf32_Shdr *shdr) { + +	int string_sect = shdr[_symtab_sect].sh_link; + +	// Allocate memory for string table +	if (!(_strtab = (char *)malloc(shdr[string_sect].sh_size))) { +		seterror("Out of memory."); +		return false; +	} + +	// Read string table into memory +	if (DLFile->seek(shdr[string_sect].sh_offset, SEEK_SET) < 0 || +	        DLFile->read(_strtab, shdr[string_sect].sh_size) != +	        (ssize_t)shdr[string_sect].sh_size) { +		seterror("Symbol table strings load failed."); +		return false; +	} + +	return true; +} + +void DLObject::relocateSymbols(Elf32_Addr offset) { + +	int mainCount = 0; +	int shortsCount= 0; + +	// 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) { +				mainCount++; +				s->st_value += offset; +				if (s->st_value < (Elf32_Addr)_segment || s->st_value > (Elf32_Addr)_segment + _segmentSize) +					seterror("Symbol out of bounds! st_value = %x\n", s->st_value); +		} +	} +} + +bool DLObject::load(Common::SeekableReadStream* DLFile) { +	Elf32_Ehdr ehdr; +	Elf32_Phdr phdr; +	Elf32_Shdr *shdr; +	bool ret = true; + +	if (readElfHeader(DLFile, &ehdr) == false) { +		return false; +	} + +	for (int i = 0; i < ehdr.e_phnum; i++) {	//Load our segments + +		DBG("Loading segment %d\n", i); + +		if (readProgramHeaders(DLFile, &ehdr, &phdr, i) == false) +			return false; + +		if (!loadSegment(DLFile, &phdr)) +			return false; +	} + +	if ((shdr = loadSectionHeaders(DLFile, &ehdr)) == NULL) +		ret = false; + +	if (ret && ((_symtab_sect = loadSymbolTable(DLFile, &ehdr, shdr)) < 0)) +		ret = false; + +	if (ret && (loadStringTable(DLFile, shdr) == false)) +		ret = false; + +	if (ret) +		relocateSymbols((Elf32_Addr)_segment);	// Offset by our segment allocated address + +	if (ret && (relocateRels(DLFile, &ehdr, shdr) == false)) +		ret = false; + +	free(shdr); + +	return ret; + +} + +bool DLObject::open(const char *path) { + +	Common::SeekableReadStream* DLFile; +	void *ctors_start, *ctors_end; + +#ifdef __PSP__ +	PowerMan.beginCriticalSection(); +#endif + +	DBG("open(\"%s\")\n", path); + +	Common::FSNode file(path); + +	if (!(DLFile = file.createReadStream())) { +		seterror("%s not found.", path); +		return false; +	} + +	DBG("%s found!\n", path); + +	/*Try to load and relocate*/ +	if (!load(DLFile)) { +		unload(); +		return false; +	} + +	DBG("loaded!/n"); + +#ifdef __PSP__ +	PowerMan.endCriticalSection(); +#endif + +	flushDataCache(); + +	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) { +		seterror("Missing ctors/dtors."); +		_dtors_start = _dtors_end = NULL; +		unload(); +		return false; +	} + +	DBG(("Calling constructors.\n")); +	for (void (**f)(void) = (void (**)(void))ctors_start; f != ctors_end; f++) +		(**f)(); + +	DBG(("%s opened ok.\n", path)); + +	return true; +} + +bool DLObject::close() { +	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) { +	DBG(("symbol(\"%s\")\n", name)); + +	if (_symtab == NULL || _strtab == NULL || _symbol_cnt < 1) { +		seterror("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) && +		       !strcmp(name, _strtab + s->st_name)) { + +			// We found the symbol +			DBG("=> %p\n", (void*)s->st_value); +			return (void*)s->st_value; +		} + +	// We didn't find the symbol +	seterror("Symbol \"%s\" not found.", name); +	return NULL; +} + +#endif /* defined(DYNAMIC_MODULES) && defined(ELF_LOADER_TARGET) */ + diff --git a/backends/plugins/elf-loader.h b/backends/plugins/elf-loader.h new file mode 100644 index 0000000000..1d30aa0c3b --- /dev/null +++ b/backends/plugins/elf-loader.h @@ -0,0 +1,67 @@ +/* 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 ELF_LOADER_H +#define ELF_LOADER_H + +#include "elf32.h" +#include "common/stream.h" +#include "backends/plugins/dynamic-plugin.h" + +class DLObject { +protected: +    void *_segment, *_symtab; +    char *_strtab; +    int _symbol_cnt; +    int _symtab_sect; +    void *_dtors_start, *_dtors_end; + +    int _segmentSize; + +    //void seterror(const char *fmt, ...); +    virtual void unload(); +    virtual bool relocate(Common::SeekableReadStream* DLFile, unsigned long offset, unsigned long size, void *relSegment) = 0; +    bool load(Common::SeekableReadStream* DLFile); + +    bool readElfHeader(Common::SeekableReadStream* DLFile, Elf32_Ehdr *ehdr); +    bool readProgramHeaders(Common::SeekableReadStream* DLFile, Elf32_Ehdr *ehdr, Elf32_Phdr *phdr, int num); +    virtual bool loadSegment(Common::SeekableReadStream* DLFile, Elf32_Phdr *phdr); +    Elf32_Shdr *loadSectionHeaders(Common::SeekableReadStream* DLFile, Elf32_Ehdr *ehdr); +    int loadSymbolTable(Common::SeekableReadStream* DLFile, Elf32_Ehdr *ehdr, Elf32_Shdr *shdr); +    bool loadStringTable(Common::SeekableReadStream* DLFile, Elf32_Shdr *shdr); +    virtual void relocateSymbols(Elf32_Addr offset); +    virtual bool relocateRels(Common::SeekableReadStream* DLFile, Elf32_Ehdr *ehdr, Elf32_Shdr *shdr) = 0; + +public: +    bool open(const char *path); +    bool close(); +    void *symbol(const char *name); +    void discard_symtab(); + +	DLObject() : _segment(NULL), _symtab(NULL), _strtab(NULL), _symbol_cnt(0), +				 _symtab_sect(-1), _dtors_start(NULL), _dtors_end(NULL), _segmentSize(0) {} +}; + +#endif /* ELF_LOADER_H */ diff --git a/backends/plugins/elf-provider.cpp b/backends/plugins/elf-provider.cpp new file mode 100644 index 0000000000..e6edd4c578 --- /dev/null +++ b/backends/plugins/elf-provider.cpp @@ -0,0 +1,105 @@ +/* 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(ELF_LOADER_TARGET) + +#include "backends/plugins/elf-provider.h" +#include "backends/plugins/dynamic-plugin.h" +#include "common/fs.h" + +#include "backends/plugins/elf-loader.h" + +DynamicPlugin::VoidFunc ELFPlugin::findSymbol(const char *symbol) { +	void *func; +	bool handleNull; +	if (_dlHandle == NULL) { +		func = NULL; +		handleNull = true; +	} else { +		func = _dlHandle->symbol(symbol); +	} +	if (!func) { +		if (handleNull) { +			warning("Failed loading symbol '%s' from plugin '%s' (Handle is NULL)", symbol, _filename.c_str()); +		} else { +			warning("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 = NULL; +		} + +		if (!_dlHandle) { +			warning("Failed loading plugin '%s'", _filename.c_str()); +			return false; +		} + +		bool ret = DynamicPlugin::loadPlugin(); + +		if (ret && _dlHandle) { +			_dlHandle->discard_symtab(); +		} + +		return ret; +}; + +void ELFPlugin::unloadPlugin() { +	DynamicPlugin::unloadPlugin(); +	if (_dlHandle) { +		if (!_dlHandle->close()) { +			warning("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(ELF_LOADER_TARGET) diff --git a/backends/plugins/elf-provider.h b/backends/plugins/elf-provider.h new file mode 100644 index 0000000000..e0382c3e45 --- /dev/null +++ b/backends/plugins/elf-provider.h @@ -0,0 +1,70 @@ +/* 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 "base/plugins.h" +#include "backends/plugins/dynamic-plugin.h" +#include "common/fs.h" + +#include "backends/plugins/elf-loader.h" + +#if defined(DYNAMIC_MODULES) && defined(ELF_LOADER_TARGET) + +class ELFPlugin : public DynamicPlugin { +protected: +	DLObject *_dlHandle; +	Common::String _filename; + +	virtual VoidFunc findSymbol(const char *symbol); + +public: +	ELFPlugin(const Common::String &filename) +		: _dlHandle(0), _filename(filename) {} + +	~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(ELF_LOADER_TARGET) + +#endif /* BACKENDS_PLUGINS_ELF_PROVIDER_H */ diff --git a/backends/plugins/elf32.h b/backends/plugins/elf32.h new file mode 100644 index 0000000000..5dec1d2e58 --- /dev/null +++ b/backends/plugins/elf32.h @@ -0,0 +1,229 @@ +/* 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 + +/* ELF stuff */ + +typedef unsigned short Elf32_Half, Elf32_Section; +typedef unsigned int Elf32_Word, Elf32_Addr, Elf32_Off; +typedef signed int  Elf32_Sword; +typedef Elf32_Half Elf32_Versym; + +#define EI_NIDENT (16) +#define SELFMAG         6 + +/* ELF File format structures. Look up ELF structure for more details */ + +// ELF header (contains info about the file) +typedef struct { +	unsigned char 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\1\1"	/* ELF Magic number */ + +// 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_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 */ +	unsigned char st_info;                /* Symbol type and binding */ +	unsigned char 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)		((unsigned char) (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 + +// Mock function to get value of global pointer for MIPS +#define getGP()	({	\ +	unsigned int __valgp;	\ +	__asm__ ("add %0, $gp, $0" : "=r"(__valgp) : ); \ +	__valgp; \ +}) + +#endif /* BACKENDS_ELF_H */ diff --git a/backends/plugins/mips-loader.cpp b/backends/plugins/mips-loader.cpp new file mode 100644 index 0000000000..7b59a2cffa --- /dev/null +++ b/backends/plugins/mips-loader.cpp @@ -0,0 +1,351 @@ +/* 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(MIPS_TARGET) + +#include "mips-loader.h" + +#define __DEBUG_PLUGINS__ + +#ifdef __DEBUG_PLUGINS__ +#define DBG(x,...) printf(x, ## __VA_ARGS__) +#else +#define DBG(x,...) +#endif + +#define seterror(x,...) printf(x, ## __VA_ARGS__) + +/** + * Follow the instruction of a relocation section. + * + * @param DLFile 	 SeekableReadStream of File + * @param offset 	 Offset into the File + * @param size   	 Size of relocation section + * @param relSegment Base address of relocated segment in memory (memory offset) + * + */ +bool MIPSDLObject::relocate(Common::SeekableReadStream* DLFile, unsigned long offset, unsigned long size, void *relSegment) { +	Elf32_Rel *rel = NULL;	// relocation entry + +	// Allocate memory for relocation table +	if (!(rel = (Elf32_Rel *)malloc(size))) { +		seterror("Out of memory."); +		return false; +	} + +	// Read in our relocation table +	if (DLFile->seek(offset, SEEK_SET) < 0 || +	        DLFile->read(rel, size) != (ssize_t)size) { +		seterror("Relocation table load failed."); +		free(rel); +		return false; +	} + +	// Treat each relocation entry. Loop over all of them +	int cnt = size / sizeof(*rel); + +	DBG("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); + +		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 +					DBG("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 +					seterror("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) +					DBG("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) +					DBG("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) +					DBG("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) +					DBG("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) +					DBG("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) +					DBG("R_MIPS_32: i=%d, a=%x, origTarget=%x, target=%x\n", i, a, origTarget, *target); +			} +			break; + +		default: +			seterror("Unknown relocation type %x at relocation %d.\n", REL_TYPE(rel[i].r_info), i); +			free(rel); +			return false; +		} +	} + +	DBG("Done with relocation. extendedHi16=%d\n\n", extendedHi16); + +	free(rel); +	return true; +} + +bool MIPSDLObject::relocateRels(Common::SeekableReadStream* DLFile, Elf32_Ehdr *ehdr, Elf32_Shdr *shdr) { + +	// 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(DLFile, curShdr->sh_offset, curShdr->sh_size, _segment)) { +					return false; +				} +			} else { 	// In Shorts segment +				if (!relocate(DLFile, curShdr->sh_offset, curShdr->sh_size, (void *)_shortsSegment->getOffset())) { +					return false; +				} +			} + +		} +	} + +	return true; +} + +void MIPSDLObject::relocateSymbols(Elf32_Addr offset) { + +	int mainCount = 0; +	int shortsCount= 0; + +	// 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)) { +				mainCount++; +				s->st_value += offset; +				if (s->st_value < (Elf32_Addr)_segment || s->st_value > (Elf32_Addr)_segment + _segmentSize) +					seterror("Symbol out of bounds! st_value = %x\n", s->st_value); +			} else {	// shorts section +				shortsCount++; +				s->st_value += _shortsSegment->getOffset(); +				if (!_shortsSegment->inSegment((char *)s->st_value)) +					seterror("Symbol out of bounds! st_value = %x\n", s->st_value); +			} + +		} +	} +} + +bool MIPSDLObject::loadSegment(Common::SeekableReadStream* DLFile, Elf32_Phdr *phdr) { + +	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 +		DBG("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))) { +			seterror("Out of memory.\n"); +			return false; +		} +		DBG("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(); +		DBG("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) { +		DBG("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); +	} + +	DBG("Reading the segment into memory\n"); + +	// Read the segment into memory +	if (DLFile->seek(phdr->p_offset, SEEK_SET) < 0 || +	        DLFile->read(baseAddress, phdr->p_filesz) != (ssize_t)phdr->p_filesz) { +		seterror("Segment load failed."); +		return false; +	} + +	DBG("Segment has been read into memory\n"); + +	return true; +} + +// Unload all objects from memory +void MIPSDLObject::unload() { +	discard_symtab(); +	free(_segment); +	_segment = NULL; + +	if (_shortsSegment) { +		ShortsMan.deleteSegment(_shortsSegment); +		_shortsSegment = NULL; +	} +} + +#endif /* defined(DYNAMIC_MODULES) && defined(MIPS_TARGET) */ diff --git a/backends/plugins/mips-loader.h b/backends/plugins/mips-loader.h new file mode 100644 index 0000000000..eb22e368f4 --- /dev/null +++ b/backends/plugins/mips-loader.h @@ -0,0 +1,46 @@ + +/* 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 "elf-loader.h" +#include "shorts-segment-manager.h" + +class MIPSDLObject : public DLObject { +protected: +	ShortSegmentManager::Segment *_shortsSegment;			// For assigning shorts ranges +	unsigned int _gpVal;									// Value of Global Pointer + +	bool relocate(Common::SeekableReadStream* DLFile, unsigned long offset, unsigned long size, void *relSegment); +    bool relocateRels(Common::SeekableReadStream* DLFile, Elf32_Ehdr *ehdr, Elf32_Shdr *shdr); +    void relocateSymbols(Elf32_Addr offset); +    bool loadSegment(Common::SeekableReadStream* DLFile, Elf32_Phdr *phdr); +    void unload(); + +public: +    MIPSDLObject() : DLObject() { +		_shortsSegment = NULL; +		_gpVal = 0; +    } +}; diff --git a/backends/platform/psp/plugin.syms b/backends/plugins/plugin.syms index 24ee1a19dc..24ee1a19dc 100644 --- a/backends/platform/psp/plugin.syms +++ b/backends/plugins/plugin.syms 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..9879413b98 --- /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..096c6d4050 --- /dev/null +++ b/backends/plugins/ps2/ps2-provider.cpp @@ -0,0 +1,44 @@ +/* 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/mips-loader.h" +#include "backends/plugins/elf-provider.h" +#include "backends/plugins/ps2/ps2-provider.h" + + +class PS2Plugin : public ELFPlugin { +public: +	PS2Plugin(const Common::String &filename) : ELFPlugin(filename) {} + +	DLObject *makeDLObject() { return new MIPSDLObject(); } +}; + +Plugin* PS2PluginProvider::createPlugin(const Common::FSNode &node) const { +	return new PS2Plugin(node.getPath()); +} + +#endif // defined(DYNAMIC_MODULES) && defined(ELF_LOADER_TARGET) diff --git a/backends/plugins/ps2/ps2-provider.h b/backends/plugins/ps2/ps2-provider.h new file mode 100644 index 0000000000..28a2321c29 --- /dev/null +++ b/backends/plugins/ps2/ps2-provider.h @@ -0,0 +1,31 @@ +/* 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-provider.h" + +class PS2PluginProvider : public ELFPluginProvider { +	Plugin* createPlugin(const Common::FSNode &node) const; +}; + diff --git a/backends/platform/psp/plugin.ld b/backends/plugins/psp/plugin.ld index db4df45264..db4df45264 100644 --- a/backends/platform/psp/plugin.ld +++ b/backends/plugins/psp/plugin.ld diff --git a/backends/plugins/psp/psp-provider.cpp b/backends/plugins/psp/psp-provider.cpp index 5760424cbf..99aa33c123 100644 --- a/backends/plugins/psp/psp-provider.cpp +++ b/backends/plugins/psp/psp-provider.cpp @@ -25,86 +25,20 @@  #if defined(DYNAMIC_MODULES) && defined(__PSP__) +#include "backends/plugins/mips-loader.h" +#include "backends/plugins/elf-provider.h"  #include "backends/plugins/psp/psp-provider.h" -#include "backends/plugins/dynamic-plugin.h" -#include "common/fs.h" -#include "backends/platform/psp/psploader.h" - -#include "backends/platform/psp/trace.h" - - -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; -	} +class PSPPlugin : public ELFPlugin {  public: -	PSPPlugin(const Common::String &filename) -		: _dlHandle(0), _filename(filename) {} - -	~PSPPlugin() { -		if (_dlHandle) unloadPlugin(); -	} - -	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; -		} +	PSPPlugin(const Common::String &filename) : ELFPlugin(filename) {} -		bool ret = DynamicPlugin::loadPlugin(); - -		if (ret) -			dlforgetsyms(_dlHandle); - -		return ret; -	} - -	void unloadPlugin() { -		DynamicPlugin::unloadPlugin(); -		if (_dlHandle) { -			if (dlclose(_dlHandle) != 0) -				warning("Failed unloading plugin '%s' (%s)", _filename.c_str(), dlerror()); -			_dlHandle = 0; -		} -	} +	DLObject *makeDLObject() { return new MIPSDLObject(); }  }; -  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..c4debc7997 100644 --- a/backends/plugins/psp/psp-provider.h +++ b/backends/plugins/psp/psp-provider.h @@ -26,16 +26,12 @@  #ifndef BACKENDS_PLUGINS_PSP_PSP_PROVIDER_H  #define BACKENDS_PLUGINS_PSP_PSP_PROVIDER_H -#include "base/plugins.h" +#include "backends/plugins/elf-provider.h"  #if defined(DYNAMIC_MODULES) && defined(__PSP__) -class PSPPluginProvider : public FilePluginProvider { -protected: +class PSPPluginProvider : public ELFPluginProvider {  	Plugin* createPlugin(const Common::FSNode &node) const; - -	bool isPluginFilename(const Common::FSNode &node) const; -  };  #endif // defined(DYNAMIC_MODULES) && defined(__PSP__) diff --git a/backends/plugins/shorts-segment-manager.cpp b/backends/plugins/shorts-segment-manager.cpp new file mode 100644 index 0000000000..2376759919 --- /dev/null +++ b/backends/plugins/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$ + * + */ + +#if defined(DYNAMIC_MODULES) && defined(MIPS_TARGET) + +#include "shorts-segment-manager.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 + +#ifdef DEBUG_PLUGINS +#define DBG(x,...) printf(x, ## __VA_ARGS__) +#else +#define DBG(x,...) +#endif + +#define seterror(x,...) printf(x, ## __VA_ARGS__) + +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(int 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 ((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) { +		seterror("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); + +	DBG("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) { +	DBG("Deleting shorts segment from %p to %p.\n\n", seg->getStart(), seg->getEnd()); +	_list.remove(seg); +	delete seg; +} + +#endif /* DYNAMIC_MODULES && MIPS_TARGET */ diff --git a/backends/platform/psp/psploader.h b/backends/plugins/shorts-segment-manager.h index 13dcf6ef98..54a13d88e1 100644 --- a/backends/platform/psp/psploader.h +++ b/backends/plugins/shorts-segment-manager.h @@ -23,17 +23,21 @@   *   */ -#ifndef PSPLOADER_H -#define PSPLOADER_H +#ifndef SHORTS_SEGMENT_MANAGER_H +#define SHORTS_SEGMENT_MANAGER_H -#include "elf32.h" -#include "common/list.h"  #include "common/singleton.h" +#include "common/list.h" +#include "elf32.h" -#define MAXDLERRLEN 80 - -#define ShortsMan	ShortSegmentManager::instance() +#define ShortsMan ShortSegmentManager::instance() +/** + * Manages the segments of small data put in the gp-relative area for MIPS processors, + * and lets these segments be handled differently in the ELF loader. + * Since there's no true dynamic linker to change the GP register between plugins and the main engine, + * custom linker scripts ensure the GP-area is in the same place for both. + */  class ShortSegmentManager : public Common::Singleton<ShortSegmentManager> {  private:  	char *_shortsStart; @@ -43,6 +47,8 @@ public:  	char *getShortsStart() {  		return _shortsStart;  	} + +	// Returns whether or not an absolute address is in the GP-relative section.  	bool inGeneralSegment(char *addr) {  		return ((char *)addr >= _shortsStart && (char *)addr < _shortsEnd);  	} @@ -80,58 +86,4 @@ private:  	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 */ +#endif /* SHORTS_SEGMENT_MANAGER_H */ diff --git a/backends/saves/default/default-saves.cpp b/backends/saves/default/default-saves.cpp index 1ab898d2d6..55aa469309 100644 --- a/backends/saves/default/default-saves.cpp +++ b/backends/saves/default/default-saves.cpp @@ -131,11 +131,11 @@ bool DefaultSaveFileManager::removeSavefile(const Common::String &filename) {  	// There is a nicely portable workaround, too: Make this method overloadable.  	if (remove(file.getPath().c_str()) != 0) {  #ifndef _WIN32_WCE -		if (errno == EACCES) +	  	if (errno == EACCES)  			setError(Common::kWritePermissionDenied, "Search or write permission denied: "+file.getName());  		if (errno == ENOENT) -			setError(Common::kPathDoesNotExist, "removeSavefile: '"+file.getName()+"' does not exist or path is invalid"); +		setError(Common::kPathDoesNotExist, "removeSavefile: '"+file.getName()+"' does not exist or path is invalid");  #endif  		return false;  	} else {  | 
