From 86f4dbd956fa2b6622ceb8748427700373a1aceb Mon Sep 17 00:00:00 2001 From: Andre Heider Date: Sun, 5 Sep 2010 12:51:25 +0000 Subject: PLUGINS: Move all ELF loader related files to its own directory. svn-id: r52555 --- backends/module.mk | 12 +- backends/platform/ds/arm9/makefile | 4 +- backends/platform/ds/arm9/source/dsmain.cpp | 1 - backends/platform/ps2/Makefile.ps2 | 4 +- backends/platform/psp/Makefile | 4 +- backends/platform/psp/psp_main.cpp | 1 - backends/plugins/arm-loader.cpp | 140 -------- backends/plugins/arm-loader.h | 39 --- backends/plugins/ds/ds-provider.h | 4 +- backends/plugins/elf-loader.cpp | 445 ------------------------ backends/plugins/elf-loader.h | 83 ----- backends/plugins/elf-provider.cpp | 99 ------ backends/plugins/elf-provider.h | 75 ---- backends/plugins/elf/arm-loader.cpp | 140 ++++++++ backends/plugins/elf/arm-loader.h | 39 +++ backends/plugins/elf/elf-loader.cpp | 445 ++++++++++++++++++++++++ backends/plugins/elf/elf-loader.h | 83 +++++ backends/plugins/elf/elf-provider.cpp | 99 ++++++ backends/plugins/elf/elf-provider.h | 75 ++++ backends/plugins/elf/elf32.h | 252 ++++++++++++++ backends/plugins/elf/mips-loader.cpp | 334 ++++++++++++++++++ backends/plugins/elf/mips-loader.h | 50 +++ backends/plugins/elf/plugin.syms | 8 + backends/plugins/elf/ppc-loader.cpp | 128 +++++++ backends/plugins/elf/ppc-loader.h | 40 +++ backends/plugins/elf/shorts-segment-manager.cpp | 84 +++++ backends/plugins/elf/shorts-segment-manager.h | 103 ++++++ backends/plugins/elf32.h | 252 -------------- backends/plugins/mips-loader.cpp | 334 ------------------ backends/plugins/mips-loader.h | 50 --- backends/plugins/plugin.syms | 8 - backends/plugins/ppc-loader.cpp | 128 ------- backends/plugins/ppc-loader.h | 40 --- backends/plugins/ps2/ps2-provider.h | 4 +- backends/plugins/psp/psp-provider.h | 4 +- backends/plugins/shorts-segment-manager.cpp | 84 ----- backends/plugins/shorts-segment-manager.h | 103 ------ backends/plugins/wii/wii-provider.h | 4 +- 38 files changed, 1900 insertions(+), 1902 deletions(-) delete mode 100644 backends/plugins/arm-loader.cpp delete mode 100644 backends/plugins/arm-loader.h delete mode 100644 backends/plugins/elf-loader.cpp delete mode 100644 backends/plugins/elf-loader.h delete mode 100644 backends/plugins/elf-provider.cpp delete mode 100644 backends/plugins/elf-provider.h create mode 100644 backends/plugins/elf/arm-loader.cpp create mode 100644 backends/plugins/elf/arm-loader.h create mode 100644 backends/plugins/elf/elf-loader.cpp create mode 100644 backends/plugins/elf/elf-loader.h create mode 100644 backends/plugins/elf/elf-provider.cpp create mode 100644 backends/plugins/elf/elf-provider.h create mode 100644 backends/plugins/elf/elf32.h create mode 100644 backends/plugins/elf/mips-loader.cpp create mode 100644 backends/plugins/elf/mips-loader.h create mode 100644 backends/plugins/elf/plugin.syms create mode 100644 backends/plugins/elf/ppc-loader.cpp create mode 100644 backends/plugins/elf/ppc-loader.h create mode 100644 backends/plugins/elf/shorts-segment-manager.cpp create mode 100644 backends/plugins/elf/shorts-segment-manager.h delete mode 100644 backends/plugins/elf32.h delete mode 100644 backends/plugins/mips-loader.cpp delete mode 100644 backends/plugins/mips-loader.h delete mode 100644 backends/plugins/plugin.syms delete mode 100644 backends/plugins/ppc-loader.cpp delete mode 100644 backends/plugins/ppc-loader.h delete mode 100644 backends/plugins/shorts-segment-manager.cpp delete mode 100644 backends/plugins/shorts-segment-manager.h (limited to 'backends') diff --git a/backends/module.mk b/backends/module.mk index ab3d1efa47..eea7ec98d2 100644 --- a/backends/module.mk +++ b/backends/module.mk @@ -22,12 +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/ppc-loader.o \ - plugins/elf-provider.o \ + plugins/elf/elf-loader.o \ + plugins/elf/mips-loader.o \ + plugins/elf/shorts-segment-manager.o \ + plugins/elf/ppc-loader.o \ + plugins/elf/arm-loader.o \ + plugins/elf/elf-provider.o \ plugins/dc/dc-provider.o \ plugins/posix/posix-provider.o \ plugins/sdl/sdl-provider.o \ diff --git a/backends/platform/ds/arm9/makefile b/backends/platform/ds/arm9/makefile index 288ca206fc..b2512d788e 100644 --- a/backends/platform/ds/arm9/makefile +++ b/backends/platform/ds/arm9/makefile @@ -276,8 +276,8 @@ 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 +PLUGIN_EXTRA_DEPS = $(srcdir)/backends/plugins/ds/plugin.ld $(srcdir)/backends/plugins/elf/plugin.syms $(EXECUTABLE) +PLUGIN_LDFLAGS += -nostartfiles -Wl,-q,--target1-abs,--just-symbols,$(EXECUTABLE),-T$(srcdir)/backends/plugins/ds/plugin.ld,--retain-symbols-file,$(srcdir)/backends/plugins/elf/plugin.syms -lstdc++ -lc -mthumb-interwork -mno-fpu#-Wl,--gc-sections -mno-crt0 $(DEVKITPRO)/devkitARM/arm-eabi/lib/ds_arm9_crt0.o MKDIR = mkdir -p RM = rm -f diff --git a/backends/platform/ds/arm9/source/dsmain.cpp b/backends/platform/ds/arm9/source/dsmain.cpp index dc0b59e777..3e33b168ee 100644 --- a/backends/platform/ds/arm9/source/dsmain.cpp +++ b/backends/platform/ds/arm9/source/dsmain.cpp @@ -106,7 +106,6 @@ #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" diff --git a/backends/platform/ps2/Makefile.ps2 b/backends/platform/ps2/Makefile.ps2 index d5b0ae3e2a..7319fcb21d 100644 --- a/backends/platform/ps2/Makefile.ps2 +++ b/backends/platform/ps2/Makefile.ps2 @@ -88,9 +88,9 @@ 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_EXTRA_DEPS = $(srcdir)/backends/plugins/elf/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 +PLUGIN_LDFLAGS += -nostartfiles -Wl,-q,--just-symbols,elf/scummvm.elf,-T$(srcdir)/backends/plugins/ps2/plugin.ld,--retain-symbols-file,$(srcdir)/backends/plugins/elf/plugin.syms -lstdc++ -lc BACKEND := ps2 diff --git a/backends/platform/psp/Makefile b/backends/platform/psp/Makefile index 49455f6b97..96816348fd 100644 --- a/backends/platform/psp/Makefile +++ b/backends/platform/psp/Makefile @@ -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 = $(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 +PLUGIN_EXTRA_DEPS = $(srcdir)/backends/plugins/elf/plugin.syms scummvm-psp.elf +PLUGIN_LDFLAGS = -nostartfiles -Wl,-q,--just-symbols=scummvm-psp.org.elf,-T$(srcdir)/backends/plugins/psp/plugin.ld,--retain-symbols-file,$(srcdir)/backends/plugins/elf/plugin.syms -lstdc++ -lc # PSP-specific variables STRIP = psp-strip diff --git a/backends/platform/psp/psp_main.cpp b/backends/platform/psp/psp_main.cpp index dba9a8fc2b..41cf451323 100644 --- a/backends/platform/psp/psp_main.cpp +++ b/backends/platform/psp/psp_main.cpp @@ -37,7 +37,6 @@ #include #include #include -#include #include "backends/platform/psp/powerman.h" #include "backends/platform/psp/thread.h" diff --git a/backends/plugins/arm-loader.cpp b/backends/plugins/arm-loader.cpp deleted file mode 100644 index 5c71c7e433..0000000000 --- a/backends/plugins/arm-loader.cpp +++ /dev/null @@ -1,140 +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(ARM_TARGET) - -#include "backends/plugins/elf-loader.h" -#include "backends/plugins/arm-loader.h" - -#include "common/debug.h" - -/** - * Follow the instruction of a relocation section. - * - * @param DLFile SeekableReadStream of File - * @param fileOffset Offset into the File - * @param size Size of relocation section - * @param relSegment Base address of relocated segment in memory (memory offset) - */ -bool ARMDLObject::relocate(Common::SeekableReadStream* DLFile, unsigned long offset, unsigned long size, void *relSegment) { - Elf32_Rel *rel = 0; //relocation entry - - // Allocate memory for relocation table - if (!(rel = (Elf32_Rel *)malloc(size))) { - warning("elfloader: Out of memory."); - return false; - } - - // Read in our relocation table - if (!DLFile->seek(offset, SEEK_SET) || - DLFile->read(rel, size) != size) { - warning("elfloader: Relocation table load failed."); - free(rel); - return false; - } - - // Treat each relocation entry. Loop over all of them - int cnt = size / sizeof(*rel); - - debug(2, "elfloader: Loaded relocation table. %d entries. base address=%p", 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; - - debug(8, "elfloader: R_ARM_ABS32: i=%d, a=%x, origTarget=%x, target=%x", i, a, origTarget, *target); - } - break; - - case R_ARM_THM_CALL: - debug(8, "elfloader: R_ARM_THM_CALL: PC-relative jump, ld takes care of necessary relocation work for us."); - break; - - case R_ARM_CALL: - debug(8, "elfloader: R_ARM_CALL: PC-relative jump, ld takes care of necessary relocation work for us."); - break; - - case R_ARM_JUMP24: - debug(8, "elfloader: R_ARM_JUMP24: PC-relative jump, ld takes care of all relocation work for us."); - break; - - case R_ARM_V4BX: - debug(8, "elfloader: R_ARM_V4BX: No relocation calculation necessary."); - break; - - default: - warning("elfloader: Unknown relocation type %d.", REL_TYPE(rel[i].r_info)); - free(rel); - return false; - } - } - - free(rel); - return true; -} - -bool ARMDLObject::relocateRels(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) { - warning("elfloader: RELA entries not supported yet!"); - 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 deleted file mode 100644 index 24290d5c6d..0000000000 --- a/backends/plugins/arm-loader.h +++ /dev/null @@ -1,39 +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(ARM_TARGET) - -#include "backends/plugins/elf-loader.h" - -class ARMDLObject : public DLObject { -protected: - virtual bool relocate(Common::SeekableReadStream* DLFile, unsigned long offset, unsigned long size, void *relSegment); - virtual bool relocateRels(Common::SeekableReadStream* DLFile, Elf32_Ehdr *ehdr, Elf32_Shdr *shdr); - -public: - ARMDLObject() : DLObject() {} -}; - -#endif /* defined(DYNAMIC_MODULES) && defined(ARM_TARGET) */ diff --git a/backends/plugins/ds/ds-provider.h b/backends/plugins/ds/ds-provider.h index 0013145358..c856937172 100644 --- a/backends/plugins/ds/ds-provider.h +++ b/backends/plugins/ds/ds-provider.h @@ -25,8 +25,8 @@ #if defined(DYNAMIC_MODULES) && defined(__DS__) -#include "backends/plugins/elf-provider.h" -#include "backends/plugins/arm-loader.h" +#include "backends/plugins/elf/elf-provider.h" +#include "backends/plugins/elf/arm-loader.h" class DSPluginProvider : public ELFPluginProvider { class DSPlugin : public ELFPlugin { diff --git a/backends/plugins/elf-loader.cpp b/backends/plugins/elf-loader.cpp deleted file mode 100644 index e1a1b8cef6..0000000000 --- a/backends/plugins/elf-loader.cpp +++ /dev/null @@ -1,445 +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(ELF_LOADER_TARGET) - -#include -#include - -#ifdef __PSP__ -#include -#include -#endif - -#ifdef __DS__ -#include -#endif - -#ifdef __WII__ -#include -#include -#endif - -#include "backends/plugins/elf-loader.h" - -#include "common/debug.h" -#include "common/file.h" -#include "common/fs.h" - -/** - * Flushes the data cache (Platform Specific). - */ -static void flushDataCache(void *ptr, uint32 len) { -#ifdef __DS__ - DC_FlushRange(ptr, len); - IC_InvalidateRange(ptr, len); -#endif -#ifdef __PLAYSTATION2__ - (void) ptr; - (void) len; - FlushCache(0); - FlushCache(2); -#endif -#ifdef __PSP__ - sceKernelDcacheWritebackRange(ptr, len); - sceKernelIcacheInvalidateRange(ptr, len); -#endif -#ifdef __WII__ - DCFlushRange(ptr, len); - ICInvalidateRange(ptr, len); -#endif -} - -DLObject::DLObject() : - _segment(0), - _symtab(0), - _strtab(0), - _symbol_cnt(0), - _symtab_sect(-1), - _dtors_start(0), - _dtors_end(0), - _segmentSize(0), - _segmentOffset(0), - _segmentVMA(0) { -} - -DLObject::~DLObject() { - unload(); -} - -// Expel the symbol table from memory -void DLObject::discard_symtab() { - free(_symtab); - free(_strtab); - _symtab = 0; - _strtab = 0; - _symbol_cnt = 0; -} - -// Unload all objects from memory -void DLObject::unload() { - discard_symtab(); - free(_segment); - _segment = 0; -} - -bool DLObject::readElfHeader(Common::SeekableReadStream* DLFile, Elf32_Ehdr *ehdr) { - // Start reading the elf header. Check for errors and magic - if (DLFile->read(ehdr, sizeof(*ehdr)) != sizeof(*ehdr) || - memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) { - warning("elfloader: No ELF file."); - return false; - } - - if (ehdr->e_ident[EI_CLASS] != ELFCLASS32) { - warning("elfloader: Wrong ELF file class."); - return false; - } - - if (ehdr->e_ident[EI_DATA] != -#ifdef SCUMM_BIG_ENDIAN - ELFDATA2MSB -#else - ELFDATA2LSB -#endif - ) { - warning("elfloader: Wrong ELF file endianess."); - return false; - } - - if (ehdr->e_ident[EI_VERSION] != EV_CURRENT) { - warning("elfloader: Wrong ELF file version."); - return false; - } - - if (ehdr->e_type != ET_EXEC) { - warning("elfloader: No executable ELF file."); - return false; - } - - if (ehdr->e_machine != -#ifdef ARM_TARGET - EM_ARM -#endif -#ifdef MIPS_TARGET - EM_MIPS -#endif -#ifdef PPC_TARGET - EM_PPC -#endif - ) { - warning("elfloader: Wrong ELF file architecture."); - return false; - } - - if (ehdr->e_phentsize < sizeof(Elf32_Phdr) || // Check for size of program header - ehdr->e_shentsize != sizeof(Elf32_Shdr)) { // Check for size of section header - warning("elfloader: Invalid ELF structure sizes."); - return false; - } - - debug(2, "elfloader: phoff = %d, phentsz = %d, phnum = %d", - ehdr->e_phoff, ehdr->e_phentsize, ehdr->e_phnum); - - return true; -} - -bool DLObject::readProgramHeaders(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) || - DLFile->read(phdr, sizeof(*phdr)) != sizeof(*phdr)) { - warning("elfloader: Program header load failed."); - return false; - } - - // Check program header values - if (phdr->p_type != PT_LOAD || phdr->p_filesz > phdr->p_memsz) { - warning("elfloader: Invalid program header."); - return false; - } - - debug(2, "elfloader: offs = %x, filesz = %x, memsz = %x, align = %x", - phdr->p_offset, phdr->p_filesz, phdr->p_memsz, phdr->p_align); - - return true; -} - -bool DLObject::loadSegment(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 - debug(2, "elfloader: Extra mem is %x", extra); - - if (!(_segment = (char *)memalign(phdr->p_align, phdr->p_memsz + extra))) { - warning("elfloader: Out of memory."); - return false; - } - - debug(2, "elfloader: Allocated segment @ %p", _segment); - - // Get offset to load segment into - baseAddress = (char *)_segment; - _segmentSize = phdr->p_memsz + extra; - _segmentVMA = phdr->p_vaddr; - - // Set bss segment to 0 if necessary (assumes bss is at the end) - if (phdr->p_memsz > phdr->p_filesz) { - debug(2, "elfloader: Setting %p to %p to 0 for bss", baseAddress + phdr->p_filesz, baseAddress + phdr->p_memsz); - memset(baseAddress + phdr->p_filesz, 0, phdr->p_memsz - phdr->p_filesz); - } - - debug(2, "elfloader: Reading the segment into memory"); - - // Read the segment into memory - if (!DLFile->seek(phdr->p_offset, SEEK_SET) || - DLFile->read(baseAddress, phdr->p_filesz) != phdr->p_filesz) { - warning("elfloader: Segment load failed."); - return false; - } - - debug(2, "elfloader: Segment has been read into memory"); - - return true; -} - -Elf32_Shdr * DLObject::loadSectionHeaders(Common::SeekableReadStream* DLFile, Elf32_Ehdr *ehdr) { - Elf32_Shdr *shdr = 0; - - // Allocate memory for section headers - if (!(shdr = (Elf32_Shdr *)malloc(ehdr->e_shnum * sizeof(*shdr)))) { - warning("elfloader: Out of memory."); - return 0; - } - - // Read from file into section headers - if (!DLFile->seek(ehdr->e_shoff, SEEK_SET) || - DLFile->read(shdr, ehdr->e_shnum * sizeof(*shdr)) != - ehdr->e_shnum * sizeof(*shdr)) { - warning("elfloader: Section headers load failed."); - return 0; - } - - 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) { - warning("elfloader: No symbol table."); - return -1; - } - - debug(2, "elfloader: Symbol section at section %d, size %x", _symtab_sect, shdr[_symtab_sect].sh_size); - - // Allocate memory for symbol table - if (!(_symtab = malloc(shdr[_symtab_sect].sh_size))) { - warning("elfloader: Out of memory."); - return -1; - } - - // Read symbol table into memory - if (!DLFile->seek(shdr[_symtab_sect].sh_offset, SEEK_SET) || - DLFile->read(_symtab, shdr[_symtab_sect].sh_size) != - shdr[_symtab_sect].sh_size) { - warning("elfloader: Symbol table load failed."); - return -1; - } - - // Set number of symbols - _symbol_cnt = shdr[_symtab_sect].sh_size / sizeof(Elf32_Sym); - debug(2, "elfloader: Loaded %d symbols.", _symbol_cnt); - - return _symtab_sect; -} - -bool DLObject::loadStringTable(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))) { - warning("elfloader: Out of memory."); - return false; - } - - // Read string table into memory - if (!DLFile->seek(shdr[string_sect].sh_offset, SEEK_SET) || - DLFile->read(_strtab, shdr[string_sect].sh_size) != - shdr[string_sect].sh_size) { - warning("elfloader: Symbol table strings load failed."); - return false; - } - - return true; -} - -void DLObject::relocateSymbols(ptrdiff_t offset) { - // 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) { - s->st_value += offset; - if (s->st_value < (Elf32_Addr)_segment || s->st_value > (Elf32_Addr)_segment + _segmentSize) - warning("elfloader: Symbol out of bounds! st_value = %x", s->st_value); - } - } -} - -bool DLObject::load(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 - debug(2, "elfloader: Loading segment %d", i); - - if (readProgramHeaders(DLFile, &ehdr, &phdr, i) == false) - return false; - - if (!loadSegment(DLFile, &phdr)) - return false; - } - - if ((shdr = loadSectionHeaders(DLFile, &ehdr)) == 0) - ret = false; - - if (ret && ((_symtab_sect = loadSymbolTable(DLFile, &ehdr, shdr)) < 0)) - ret = false; - - if (ret && (loadStringTable(DLFile, shdr) == false)) - ret = false; - - if (ret) { - // Offset by our segment allocated address - _segmentOffset = ptrdiff_t(_segment) - phdr.p_vaddr; - relocateSymbols(_segmentOffset); - } - - 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; - - debug(2, "elfloader: open(\"%s\")", path); - - Common::FSNode file(path); - - if (!(DLFile = file.createReadStream())) { - warning("elfloader: %s not found.", path); - return false; - } - - debug(2, "elfloader: %s found!", path); - - /*Try to load and relocate*/ - if (!load(DLFile)) { - unload(); - return false; - } - - debug(2, "elfloader: Loaded!"); - - flushDataCache(_segment, _segmentSize); - - ctors_start = symbol("___plugin_ctors"); - ctors_end = symbol("___plugin_ctors_end"); - _dtors_start = symbol("___plugin_dtors"); - _dtors_end = symbol("___plugin_dtors_end"); - - if (!ctors_start || !ctors_end || !_dtors_start || !_dtors_end) { - warning("elfloader: Missing ctors/dtors."); - _dtors_start = _dtors_end = 0; - unload(); - return false; - } - - debug(2, "elfloader: Calling constructors."); - for (void (**f)(void) = (void (**)(void))ctors_start; f != ctors_end; f++) - (**f)(); - - debug(2, "elfloader: %s opened ok.", path); - - return true; -} - -bool DLObject::close() { - if (_dtors_start && _dtors_end) - for (void (**f)(void) = (void (**)(void))_dtors_start; f != _dtors_end; f++) - (**f)(); - _dtors_start = _dtors_end = 0; - unload(); - return true; -} - -void *DLObject::symbol(const char *name) { - debug(2, "elfloader: Symbol(\"%s\")", name); - - if (!_symtab || !_strtab || _symbol_cnt < 1) { - warning("elfloader: No symbol table loaded."); - return 0; - } - - Elf32_Sym *s = (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 - debug(2, "elfloader: => %p", (void*)s->st_value); - return (void*)s->st_value; - } - - // We didn't find the symbol - warning("elfloader: Symbol \"%s\" not found.", name); - return 0; -} - -#endif /* defined(DYNAMIC_MODULES) && defined(ELF_LOADER_TARGET) */ - diff --git a/backends/plugins/elf-loader.h b/backends/plugins/elf-loader.h deleted file mode 100644 index b5c0e1355d..0000000000 --- a/backends/plugins/elf-loader.h +++ /dev/null @@ -1,83 +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(ELF_LOADER_TARGET) - -#ifndef ELF_LOADER_H -#define ELF_LOADER_H - -#include - -#include "backends/plugins/dynamic-plugin.h" -#include "backends/plugins/elf32.h" - -#include "common/stream.h" - -/** - * DLObject - * - * Class that most directly handles operations on a plugin file - * (opening it for reading, loading/unloading it in memory, finding a specific symbol in the file, etc.) - * Subclasses have the same functionality, but implementations specific to different processors/platforms. - */ -class DLObject { -protected: - void *_segment, *_symtab; - char *_strtab; - int _symbol_cnt; - int _symtab_sect; - void *_dtors_start, *_dtors_end; - - uint32 _segmentSize; - ptrdiff_t _segmentOffset; - uint32 _segmentVMA; - - virtual void unload(); - 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(ptrdiff_t offset); - - virtual bool relocate(Common::SeekableReadStream* DLFile, unsigned long offset, unsigned long size, void *relSegment) = 0; - virtual bool relocateRels(Common::SeekableReadStream* DLFile, Elf32_Ehdr *ehdr, Elf32_Shdr *shdr) = 0; - -public: - DLObject(); - virtual ~DLObject(); - - bool open(const char *path); - bool close(); - void *symbol(const char *name); - void discard_symtab(); -}; - -#endif /* ELF_LOADER_H */ - -#endif /* defined(DYNAMIC_MODULES) && defined(ELF_LOADER_TARGET) */ diff --git a/backends/plugins/elf-provider.cpp b/backends/plugins/elf-provider.cpp deleted file mode 100644 index 997a43b653..0000000000 --- a/backends/plugins/elf-provider.cpp +++ /dev/null @@ -1,99 +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(ELF_LOADER_TARGET) - -#include "backends/plugins/elf-provider.h" -#include "backends/plugins/dynamic-plugin.h" - -#include "common/fs.h" - -DynamicPlugin::VoidFunc ELFPlugin::findSymbol(const char *symbol) { - void *func = 0; - - if (_dlHandle) - func = _dlHandle->symbol(symbol); - - if (!func) { - if (!_dlHandle) - warning("elfloader: Failed loading symbol '%s' from plugin '%s' (Handle is NULL)", symbol, _filename.c_str()); - else - warning("elfloader: Failed loading symbol '%s' from plugin '%s'", symbol, _filename.c_str()); - } - - // FIXME HACK: This is a HACK to circumvent a clash between the ISO C++ - // standard and POSIX: ISO C++ disallows casting between function pointers - // and data pointers, but dlsym always returns a void pointer. For details, - // see e.g. . - assert(sizeof(VoidFunc) == sizeof(func)); - VoidFunc tmp; - memcpy(&tmp, &func, sizeof(VoidFunc)); - return tmp; -} - -bool ELFPlugin::loadPlugin() { - assert(!_dlHandle); - DLObject *obj = makeDLObject(); - if (obj->open(_filename.c_str())) { - _dlHandle = obj; - } else { - delete obj; - _dlHandle = 0; - } - - if (!_dlHandle) { - warning("elfloader: Failed loading plugin '%s'", _filename.c_str()); - return false; - } - - bool ret = DynamicPlugin::loadPlugin(); - - if (ret && _dlHandle) - _dlHandle->discard_symtab(); - - return ret; -} - -void ELFPlugin::unloadPlugin() { - DynamicPlugin::unloadPlugin(); - if (_dlHandle) { - if (!_dlHandle->close()) { - warning("elfloader: Failed unloading plugin '%s'", _filename.c_str()); - } - delete _dlHandle; - _dlHandle = 0; - } -} - -bool ELFPluginProvider::isPluginFilename(const Common::FSNode &node) const { - // Check the plugin suffix - Common::String filename = node.getName(); - if (!filename.hasSuffix(".PLG") && !filename.hasSuffix(".plg") && !filename.hasSuffix(".PLUGIN") && !filename.hasSuffix(".plugin")) - return false; - - return true; -} - -#endif // defined(DYNAMIC_MODULES) && defined(ELF_LOADER_TARGET) diff --git a/backends/plugins/elf-provider.h b/backends/plugins/elf-provider.h deleted file mode 100644 index df9c503674..0000000000 --- a/backends/plugins/elf-provider.h +++ /dev/null @@ -1,75 +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(ELF_LOADER_TARGET) - -#ifndef BACKENDS_PLUGINS_ELF_PROVIDER_H -#define BACKENDS_PLUGINS_ELF_PROVIDER_H - -#include "backends/plugins/elf-loader.h" - -#include "common/fs.h" - -/** - * ELFPlugin - * - * Objects of this class are returned when the PluginManager calls - * getPlugins() on an ELFPluginProvider. An intermediary class for - * dealing with plugin files, ELFPlugin is responsible for creating/destroying - * a DLObject that handles the opening/loading/unloading of the plugin file whose - * path in the target backend's file system is "_filename". - */ -class ELFPlugin : public DynamicPlugin { -protected: - 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 /* BACKENDS_PLUGINS_ELF_PROVIDER_H */ - -#endif // defined(DYNAMIC_MODULES) && defined(ELF_LOADER_TARGET) diff --git a/backends/plugins/elf/arm-loader.cpp b/backends/plugins/elf/arm-loader.cpp new file mode 100644 index 0000000000..ab1129d34c --- /dev/null +++ b/backends/plugins/elf/arm-loader.cpp @@ -0,0 +1,140 @@ +/* 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/plugins/elf/elf-loader.h" +#include "backends/plugins/elf/arm-loader.h" + +#include "common/debug.h" + +/** + * Follow the instruction of a relocation section. + * + * @param DLFile SeekableReadStream of File + * @param fileOffset Offset into the File + * @param size Size of relocation section + * @param relSegment Base address of relocated segment in memory (memory offset) + */ +bool ARMDLObject::relocate(Common::SeekableReadStream* DLFile, unsigned long offset, unsigned long size, void *relSegment) { + Elf32_Rel *rel = 0; //relocation entry + + // Allocate memory for relocation table + if (!(rel = (Elf32_Rel *)malloc(size))) { + warning("elfloader: Out of memory."); + return false; + } + + // Read in our relocation table + if (!DLFile->seek(offset, SEEK_SET) || + DLFile->read(rel, size) != size) { + warning("elfloader: Relocation table load failed."); + free(rel); + return false; + } + + // Treat each relocation entry. Loop over all of them + int cnt = size / sizeof(*rel); + + debug(2, "elfloader: Loaded relocation table. %d entries. base address=%p", 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; + + debug(8, "elfloader: R_ARM_ABS32: i=%d, a=%x, origTarget=%x, target=%x", i, a, origTarget, *target); + } + break; + + case R_ARM_THM_CALL: + debug(8, "elfloader: R_ARM_THM_CALL: PC-relative jump, ld takes care of necessary relocation work for us."); + break; + + case R_ARM_CALL: + debug(8, "elfloader: R_ARM_CALL: PC-relative jump, ld takes care of necessary relocation work for us."); + break; + + case R_ARM_JUMP24: + debug(8, "elfloader: R_ARM_JUMP24: PC-relative jump, ld takes care of all relocation work for us."); + break; + + case R_ARM_V4BX: + debug(8, "elfloader: R_ARM_V4BX: No relocation calculation necessary."); + break; + + default: + warning("elfloader: Unknown relocation type %d.", REL_TYPE(rel[i].r_info)); + free(rel); + return false; + } + } + + free(rel); + return true; +} + +bool ARMDLObject::relocateRels(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) { + warning("elfloader: RELA entries not supported yet!"); + 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/elf/arm-loader.h b/backends/plugins/elf/arm-loader.h new file mode 100644 index 0000000000..52a3be5447 --- /dev/null +++ b/backends/plugins/elf/arm-loader.h @@ -0,0 +1,39 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 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/plugins/elf/elf-loader.h" + +class ARMDLObject : public DLObject { +protected: + virtual bool relocate(Common::SeekableReadStream* DLFile, unsigned long offset, unsigned long size, void *relSegment); + virtual bool relocateRels(Common::SeekableReadStream* DLFile, Elf32_Ehdr *ehdr, Elf32_Shdr *shdr); + +public: + ARMDLObject() : DLObject() {} +}; + +#endif /* defined(DYNAMIC_MODULES) && defined(ARM_TARGET) */ diff --git a/backends/plugins/elf/elf-loader.cpp b/backends/plugins/elf/elf-loader.cpp new file mode 100644 index 0000000000..5ce8af6295 --- /dev/null +++ b/backends/plugins/elf/elf-loader.cpp @@ -0,0 +1,445 @@ +/* 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 +#include + +#ifdef __PSP__ +#include +#include +#endif + +#ifdef __DS__ +#include +#endif + +#ifdef __WII__ +#include +#include +#endif + +#include "backends/plugins/elf/elf-loader.h" + +#include "common/debug.h" +#include "common/file.h" +#include "common/fs.h" + +/** + * Flushes the data cache (Platform Specific). + */ +static void flushDataCache(void *ptr, uint32 len) { +#ifdef __DS__ + DC_FlushRange(ptr, len); + IC_InvalidateRange(ptr, len); +#endif +#ifdef __PLAYSTATION2__ + (void) ptr; + (void) len; + FlushCache(0); + FlushCache(2); +#endif +#ifdef __PSP__ + sceKernelDcacheWritebackRange(ptr, len); + sceKernelIcacheInvalidateRange(ptr, len); +#endif +#ifdef __WII__ + DCFlushRange(ptr, len); + ICInvalidateRange(ptr, len); +#endif +} + +DLObject::DLObject() : + _segment(0), + _symtab(0), + _strtab(0), + _symbol_cnt(0), + _symtab_sect(-1), + _dtors_start(0), + _dtors_end(0), + _segmentSize(0), + _segmentOffset(0), + _segmentVMA(0) { +} + +DLObject::~DLObject() { + unload(); +} + +// Expel the symbol table from memory +void DLObject::discard_symtab() { + free(_symtab); + free(_strtab); + _symtab = 0; + _strtab = 0; + _symbol_cnt = 0; +} + +// Unload all objects from memory +void DLObject::unload() { + discard_symtab(); + free(_segment); + _segment = 0; +} + +bool DLObject::readElfHeader(Common::SeekableReadStream* DLFile, Elf32_Ehdr *ehdr) { + // Start reading the elf header. Check for errors and magic + if (DLFile->read(ehdr, sizeof(*ehdr)) != sizeof(*ehdr) || + memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) { + warning("elfloader: No ELF file."); + return false; + } + + if (ehdr->e_ident[EI_CLASS] != ELFCLASS32) { + warning("elfloader: Wrong ELF file class."); + return false; + } + + if (ehdr->e_ident[EI_DATA] != +#ifdef SCUMM_BIG_ENDIAN + ELFDATA2MSB +#else + ELFDATA2LSB +#endif + ) { + warning("elfloader: Wrong ELF file endianess."); + return false; + } + + if (ehdr->e_ident[EI_VERSION] != EV_CURRENT) { + warning("elfloader: Wrong ELF file version."); + return false; + } + + if (ehdr->e_type != ET_EXEC) { + warning("elfloader: No executable ELF file."); + return false; + } + + if (ehdr->e_machine != +#ifdef ARM_TARGET + EM_ARM +#endif +#ifdef MIPS_TARGET + EM_MIPS +#endif +#ifdef PPC_TARGET + EM_PPC +#endif + ) { + warning("elfloader: Wrong ELF file architecture."); + return false; + } + + if (ehdr->e_phentsize < sizeof(Elf32_Phdr) || // Check for size of program header + ehdr->e_shentsize != sizeof(Elf32_Shdr)) { // Check for size of section header + warning("elfloader: Invalid ELF structure sizes."); + return false; + } + + debug(2, "elfloader: phoff = %d, phentsz = %d, phnum = %d", + ehdr->e_phoff, ehdr->e_phentsize, ehdr->e_phnum); + + return true; +} + +bool DLObject::readProgramHeaders(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) || + DLFile->read(phdr, sizeof(*phdr)) != sizeof(*phdr)) { + warning("elfloader: Program header load failed."); + return false; + } + + // Check program header values + if (phdr->p_type != PT_LOAD || phdr->p_filesz > phdr->p_memsz) { + warning("elfloader: Invalid program header."); + return false; + } + + debug(2, "elfloader: offs = %x, filesz = %x, memsz = %x, align = %x", + phdr->p_offset, phdr->p_filesz, phdr->p_memsz, phdr->p_align); + + return true; +} + +bool DLObject::loadSegment(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 + debug(2, "elfloader: Extra mem is %x", extra); + + if (!(_segment = (char *)memalign(phdr->p_align, phdr->p_memsz + extra))) { + warning("elfloader: Out of memory."); + return false; + } + + debug(2, "elfloader: Allocated segment @ %p", _segment); + + // Get offset to load segment into + baseAddress = (char *)_segment; + _segmentSize = phdr->p_memsz + extra; + _segmentVMA = phdr->p_vaddr; + + // Set bss segment to 0 if necessary (assumes bss is at the end) + if (phdr->p_memsz > phdr->p_filesz) { + debug(2, "elfloader: Setting %p to %p to 0 for bss", baseAddress + phdr->p_filesz, baseAddress + phdr->p_memsz); + memset(baseAddress + phdr->p_filesz, 0, phdr->p_memsz - phdr->p_filesz); + } + + debug(2, "elfloader: Reading the segment into memory"); + + // Read the segment into memory + if (!DLFile->seek(phdr->p_offset, SEEK_SET) || + DLFile->read(baseAddress, phdr->p_filesz) != phdr->p_filesz) { + warning("elfloader: Segment load failed."); + return false; + } + + debug(2, "elfloader: Segment has been read into memory"); + + return true; +} + +Elf32_Shdr * DLObject::loadSectionHeaders(Common::SeekableReadStream* DLFile, Elf32_Ehdr *ehdr) { + Elf32_Shdr *shdr = 0; + + // Allocate memory for section headers + if (!(shdr = (Elf32_Shdr *)malloc(ehdr->e_shnum * sizeof(*shdr)))) { + warning("elfloader: Out of memory."); + return 0; + } + + // Read from file into section headers + if (!DLFile->seek(ehdr->e_shoff, SEEK_SET) || + DLFile->read(shdr, ehdr->e_shnum * sizeof(*shdr)) != + ehdr->e_shnum * sizeof(*shdr)) { + warning("elfloader: Section headers load failed."); + return 0; + } + + 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) { + warning("elfloader: No symbol table."); + return -1; + } + + debug(2, "elfloader: Symbol section at section %d, size %x", _symtab_sect, shdr[_symtab_sect].sh_size); + + // Allocate memory for symbol table + if (!(_symtab = malloc(shdr[_symtab_sect].sh_size))) { + warning("elfloader: Out of memory."); + return -1; + } + + // Read symbol table into memory + if (!DLFile->seek(shdr[_symtab_sect].sh_offset, SEEK_SET) || + DLFile->read(_symtab, shdr[_symtab_sect].sh_size) != + shdr[_symtab_sect].sh_size) { + warning("elfloader: Symbol table load failed."); + return -1; + } + + // Set number of symbols + _symbol_cnt = shdr[_symtab_sect].sh_size / sizeof(Elf32_Sym); + debug(2, "elfloader: Loaded %d symbols.", _symbol_cnt); + + return _symtab_sect; +} + +bool DLObject::loadStringTable(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))) { + warning("elfloader: Out of memory."); + return false; + } + + // Read string table into memory + if (!DLFile->seek(shdr[string_sect].sh_offset, SEEK_SET) || + DLFile->read(_strtab, shdr[string_sect].sh_size) != + shdr[string_sect].sh_size) { + warning("elfloader: Symbol table strings load failed."); + return false; + } + + return true; +} + +void DLObject::relocateSymbols(ptrdiff_t offset) { + // 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) { + s->st_value += offset; + if (s->st_value < (Elf32_Addr)_segment || s->st_value > (Elf32_Addr)_segment + _segmentSize) + warning("elfloader: Symbol out of bounds! st_value = %x", s->st_value); + } + } +} + +bool DLObject::load(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 + debug(2, "elfloader: Loading segment %d", i); + + if (readProgramHeaders(DLFile, &ehdr, &phdr, i) == false) + return false; + + if (!loadSegment(DLFile, &phdr)) + return false; + } + + if ((shdr = loadSectionHeaders(DLFile, &ehdr)) == 0) + ret = false; + + if (ret && ((_symtab_sect = loadSymbolTable(DLFile, &ehdr, shdr)) < 0)) + ret = false; + + if (ret && (loadStringTable(DLFile, shdr) == false)) + ret = false; + + if (ret) { + // Offset by our segment allocated address + _segmentOffset = ptrdiff_t(_segment) - phdr.p_vaddr; + relocateSymbols(_segmentOffset); + } + + 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; + + debug(2, "elfloader: open(\"%s\")", path); + + Common::FSNode file(path); + + if (!(DLFile = file.createReadStream())) { + warning("elfloader: %s not found.", path); + return false; + } + + debug(2, "elfloader: %s found!", path); + + /*Try to load and relocate*/ + if (!load(DLFile)) { + unload(); + return false; + } + + debug(2, "elfloader: Loaded!"); + + flushDataCache(_segment, _segmentSize); + + ctors_start = symbol("___plugin_ctors"); + ctors_end = symbol("___plugin_ctors_end"); + _dtors_start = symbol("___plugin_dtors"); + _dtors_end = symbol("___plugin_dtors_end"); + + if (!ctors_start || !ctors_end || !_dtors_start || !_dtors_end) { + warning("elfloader: Missing ctors/dtors."); + _dtors_start = _dtors_end = 0; + unload(); + return false; + } + + debug(2, "elfloader: Calling constructors."); + for (void (**f)(void) = (void (**)(void))ctors_start; f != ctors_end; f++) + (**f)(); + + debug(2, "elfloader: %s opened ok.", path); + + return true; +} + +bool DLObject::close() { + if (_dtors_start && _dtors_end) + for (void (**f)(void) = (void (**)(void))_dtors_start; f != _dtors_end; f++) + (**f)(); + _dtors_start = _dtors_end = 0; + unload(); + return true; +} + +void *DLObject::symbol(const char *name) { + debug(2, "elfloader: Symbol(\"%s\")", name); + + if (!_symtab || !_strtab || _symbol_cnt < 1) { + warning("elfloader: No symbol table loaded."); + return 0; + } + + Elf32_Sym *s = (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 + debug(2, "elfloader: => %p", (void*)s->st_value); + return (void*)s->st_value; + } + + // We didn't find the symbol + warning("elfloader: Symbol \"%s\" not found.", name); + return 0; +} + +#endif /* defined(DYNAMIC_MODULES) && defined(ELF_LOADER_TARGET) */ + diff --git a/backends/plugins/elf/elf-loader.h b/backends/plugins/elf/elf-loader.h new file mode 100644 index 0000000000..6413c46cea --- /dev/null +++ b/backends/plugins/elf/elf-loader.h @@ -0,0 +1,83 @@ +/* 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) + +#ifndef ELF_LOADER_H +#define ELF_LOADER_H + +#include + +#include "backends/plugins/elf/elf32.h" +#include "backends/plugins/dynamic-plugin.h" + +#include "common/stream.h" + +/** + * DLObject + * + * Class that most directly handles operations on a plugin file + * (opening it for reading, loading/unloading it in memory, finding a specific symbol in the file, etc.) + * Subclasses have the same functionality, but implementations specific to different processors/platforms. + */ +class DLObject { +protected: + void *_segment, *_symtab; + char *_strtab; + int _symbol_cnt; + int _symtab_sect; + void *_dtors_start, *_dtors_end; + + uint32 _segmentSize; + ptrdiff_t _segmentOffset; + uint32 _segmentVMA; + + virtual void unload(); + 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(ptrdiff_t offset); + + virtual bool relocate(Common::SeekableReadStream* DLFile, unsigned long offset, unsigned long size, void *relSegment) = 0; + virtual bool relocateRels(Common::SeekableReadStream* DLFile, Elf32_Ehdr *ehdr, Elf32_Shdr *shdr) = 0; + +public: + DLObject(); + virtual ~DLObject(); + + bool open(const char *path); + bool close(); + void *symbol(const char *name); + void discard_symtab(); +}; + +#endif /* ELF_LOADER_H */ + +#endif /* defined(DYNAMIC_MODULES) && defined(ELF_LOADER_TARGET) */ diff --git a/backends/plugins/elf/elf-provider.cpp b/backends/plugins/elf/elf-provider.cpp new file mode 100644 index 0000000000..9b42d4edd3 --- /dev/null +++ b/backends/plugins/elf/elf-provider.cpp @@ -0,0 +1,99 @@ +/* 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/elf-provider.h" +#include "backends/plugins/dynamic-plugin.h" + +#include "common/fs.h" + +DynamicPlugin::VoidFunc ELFPlugin::findSymbol(const char *symbol) { + void *func = 0; + + if (_dlHandle) + func = _dlHandle->symbol(symbol); + + if (!func) { + if (!_dlHandle) + warning("elfloader: Failed loading symbol '%s' from plugin '%s' (Handle is NULL)", symbol, _filename.c_str()); + else + warning("elfloader: Failed loading symbol '%s' from plugin '%s'", symbol, _filename.c_str()); + } + + // FIXME HACK: This is a HACK to circumvent a clash between the ISO C++ + // standard and POSIX: ISO C++ disallows casting between function pointers + // and data pointers, but dlsym always returns a void pointer. For details, + // see e.g. . + assert(sizeof(VoidFunc) == sizeof(func)); + VoidFunc tmp; + memcpy(&tmp, &func, sizeof(VoidFunc)); + return tmp; +} + +bool ELFPlugin::loadPlugin() { + assert(!_dlHandle); + DLObject *obj = makeDLObject(); + if (obj->open(_filename.c_str())) { + _dlHandle = obj; + } else { + delete obj; + _dlHandle = 0; + } + + if (!_dlHandle) { + warning("elfloader: Failed loading plugin '%s'", _filename.c_str()); + return false; + } + + bool ret = DynamicPlugin::loadPlugin(); + + if (ret && _dlHandle) + _dlHandle->discard_symtab(); + + return ret; +} + +void ELFPlugin::unloadPlugin() { + DynamicPlugin::unloadPlugin(); + if (_dlHandle) { + if (!_dlHandle->close()) { + warning("elfloader: Failed unloading plugin '%s'", _filename.c_str()); + } + delete _dlHandle; + _dlHandle = 0; + } +} + +bool ELFPluginProvider::isPluginFilename(const Common::FSNode &node) const { + // Check the plugin suffix + Common::String filename = node.getName(); + if (!filename.hasSuffix(".PLG") && !filename.hasSuffix(".plg") && !filename.hasSuffix(".PLUGIN") && !filename.hasSuffix(".plugin")) + return false; + + return true; +} + +#endif // defined(DYNAMIC_MODULES) && defined(ELF_LOADER_TARGET) diff --git a/backends/plugins/elf/elf-provider.h b/backends/plugins/elf/elf-provider.h new file mode 100644 index 0000000000..f06621f5b7 --- /dev/null +++ b/backends/plugins/elf/elf-provider.h @@ -0,0 +1,75 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#if defined(DYNAMIC_MODULES) && defined(ELF_LOADER_TARGET) + +#ifndef BACKENDS_PLUGINS_ELF_PROVIDER_H +#define BACKENDS_PLUGINS_ELF_PROVIDER_H + +#include "backends/plugins/elf/elf-loader.h" + +#include "common/fs.h" + +/** + * ELFPlugin + * + * Objects of this class are returned when the PluginManager calls + * getPlugins() on an ELFPluginProvider. An intermediary class for + * dealing with plugin files, ELFPlugin is responsible for creating/destroying + * a DLObject that handles the opening/loading/unloading of the plugin file whose + * path in the target backend's file system is "_filename". + */ +class ELFPlugin : public DynamicPlugin { +protected: + 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 /* BACKENDS_PLUGINS_ELF_PROVIDER_H */ + +#endif // defined(DYNAMIC_MODULES) && defined(ELF_LOADER_TARGET) diff --git a/backends/plugins/elf/elf32.h b/backends/plugins/elf/elf32.h new file mode 100644 index 0000000000..c83093fed7 --- /dev/null +++ b/backends/plugins/elf/elf32.h @@ -0,0 +1,252 @@ +/* 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: + * The contents of this file were gathered mainly from the SYSTEM V APPLICATION BINARY INTERFACE. + * Processor-specific things were garnered from processor-specific supplements to the abi. + */ + +typedef 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 4 + +/* 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" /* ELF Magic number */ + +#define EI_CLASS 4 /* File class byte index */ +#define ELFCLASS32 1 /* 32-bit objects */ + +#define EI_DATA 5 /* Data encoding byte index */ +#define ELFDATA2LSB 1 /* 2's complement, little endian */ +#define ELFDATA2MSB 2 /* 2's complement, big endian */ + +#define EI_VERSION 6 +#define EV_CURRENT 1 /* Current version */ + +// e_type values +#define ET_NONE 0 /* no file type */ +#define ET_REL 1 /* relocatable */ +#define ET_EXEC 2 /* executable */ +#define ET_DYN 3 /* shared object */ +#define ET_CORE 4 /* core file */ + +// e_machine values +#define EM_MIPS 8 +#define EM_PPC 20 +#define EM_ARM 40 + +// Program header (contains info about segment) +typedef struct { + Elf32_Word p_type; /* Segment type */ + Elf32_Off p_offset; /* Segment file offset */ + Elf32_Addr p_vaddr; /* Segment virtual address */ + Elf32_Addr p_paddr; /* Segment physical address */ + Elf32_Word p_filesz; /* Segment size in file */ + Elf32_Word p_memsz; /* Segment size in memory */ + Elf32_Word p_flags; /* Segment flags */ + Elf32_Word p_align; /* Segment alignment */ +} Elf32_Phdr; + +// p_type values +#define PT_NULL 0 /* ignored */ +#define PT_LOAD 1 /* loadable segment */ +#define PT_DYNAMIC 2 /* dynamic linking info */ +#define PT_INTERP 3 /* info about interpreter */ +#define PT_NOTE 4 /* note segment */ +#define PT_SHLIB 5 /* reserved */ +#define PT_PHDR 6 /* Program header table */ +#define PT_MIPS_REGINFO 0x70000000 /* Register usage info for MIPS */ +#define PT_ARM_ARCHEXT 0x70000000 /* Platform architecture compatibility info for ARM */ +#define PT_ARM_EXIDX 0x70000001 /* Exception unwind tables for ARM */ + +// p_flags value +#define PF_X 1 /* execute */ +#define PF_W 2 /* write */ +#define PF_R 4 /* read */ + +// Section header (contains info about section) +typedef struct { + Elf32_Word sh_name; /* Section name (string tbl index) */ + Elf32_Word sh_type; /* Section type */ + Elf32_Word sh_flags; /* Section flags */ + Elf32_Addr sh_addr; /* Section virtual addr at execution */ + Elf32_Off sh_offset; /* Section file offset */ + Elf32_Word sh_size; /* Section size in bytes */ + Elf32_Word sh_link; /* Link to another section */ + Elf32_Word sh_info; /* Additional section information */ + Elf32_Word sh_addralign; /* Section alignment */ + Elf32_Word sh_entsize; /* Entry size if section holds table */ +} Elf32_Shdr; + +// sh_type values +#define SHT_NULL 0 /* Inactive section */ +#define SHT_PROGBITS 1 /* Proprietary */ +#define SHT_SYMTAB 2 /* Symbol table */ +#define SHT_STRTAB 3 /* String table */ +#define SHT_RELA 4 /* Relocation entries with addend */ +#define SHT_HASH 5 /* Symbol hash table */ +#define SHT_DYNAMIC 6 /* Info for dynamic linking */ +#define SHT_NOTE 7 /* Note section */ +#define SHT_NOBITS 8 /* Occupies no space */ +#define SHT_REL 9 /* Relocation entries without addend */ +#define SHT_SHLIB 10 /* Reserved */ +#define SHT_DYNSYM 11 /* Minimal set of dynamic linking symbols */ +#define SHT_MIPS_LIBLSIT 0x70000000 /* Info about dynamic shared object libs for MIPS*/ +#define SHT_MIPS_CONFLICT 0x70000002 /* Conflicts btw executables and shared objects for MIPS */ +#define SHT_MIPS_GPTAB 0x70000003 /* Global pointer table for MIPS*/ +#define SHT_ARM_EXIDX 0x70000001 /* Exception Index table for ARM*/ +#define SHT_ARM_PREEMPTMAP 0x70000002 /* BPABI DLL dynamic linking pre-emption map for ARM */ +#define SHT_ARM_ATTRIBUTES 0x70000003 /* Object file compatibility attributes for ARM*/ + +// sh_flags values +#define SHF_WRITE 0 /* writable section */ +#define SHF_ALLOC 2 /* section occupies memory */ +#define SHF_EXECINSTR 4 /* machine instructions */ +#define SHF_MIPS_GPREL 0x10000000 /* Must be made part of global data area for MIPS */ + +// Symbol entry (contain info about a symbol) +typedef struct { + Elf32_Word st_name; /* Symbol name (string tbl index) */ + Elf32_Addr st_value; /* Symbol value */ + Elf32_Word st_size; /* Symbol size */ + 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 + +// PPC relocation types +#define R_PPC_ADDR32 1 +#define R_PPC_ADDR16_LO 4 +#define R_PPC_ADDR16_HI 5 +#define R_PPC_ADDR16_HA 6 +#define R_PPC_REL24 10 +#define R_PPC_REL32 26 + +// Mock function to get value of global pointer for MIPS +#define getGP() ({ \ + unsigned int __valgp; \ + __asm__ ("add %0, $gp, $0" : "=r"(__valgp) : ); \ + __valgp; \ +}) + +#endif /* BACKENDS_ELF_H */ diff --git a/backends/plugins/elf/mips-loader.cpp b/backends/plugins/elf/mips-loader.cpp new file mode 100644 index 0000000000..642ea0427a --- /dev/null +++ b/backends/plugins/elf/mips-loader.cpp @@ -0,0 +1,334 @@ +/* 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 "backends/plugins/elf/mips-loader.h" + +#include "common/debug.h" + +/** + * Follow the instruction of a relocation section. + * + * @param DLFile SeekableReadStream of File + * @param fileOffset 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 = 0; // relocation entry + + // Allocate memory for relocation table + if (!(rel = (Elf32_Rel *)malloc(size))) { + warning("elfloader: Out of memory."); + return false; + } + + // Read in our relocation table + if (!DLFile->seek(offset, SEEK_SET) || + DLFile->read(rel, size) != size) { + warning("elfloader: Relocation table load failed."); + free(rel); + return false; + } + + // Treat each relocation entry. Loop over all of them + int cnt = size / sizeof(*rel); + + debug(2, "elfloader: Loaded relocation table. %d entries. base address=%p", 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 + debug(8, "elfloader: R_MIPS_HI16: i=%d, offset=%x, ahl = %x, target = %x", + i, rel[i].r_offset, ahl, *target); + } + break; + + case R_MIPS_LO16: // Absolute addressing. Needs a HI16 to come before it + if (sym->st_shndx < SHN_LOPROC) { // Only shift for plugin section. (ie. has a real section index) + if (!seenHi16) { // We MUST have seen HI16 first + debug(8, "elfloader: R_MIPS_LO16 w/o preceding R_MIPS_HI16 at relocation %d!", i); + free(rel); + return false; + } + + // Fix: bug in gcc makes LO16s connect to wrong HI16s sometimes (shorts and regular segment) + // Note that we can check the entire shorts segment because the executable's shorts don't belong to this plugin section + // and will be screened out above + bool lo16InShorts = ShortsMan.inGeneralSegment((char *)sym->st_value); + + // Correct the bug by getting the proper value in ahl (taken from the current symbol) + if ((hi16InShorts && !lo16InShorts) || (!hi16InShorts && lo16InShorts)) { + ahl -= (lastHiSymVal & 0xffff0000); // We assume gcc meant the same offset + ahl += (sym->st_value & 0xffff0000); + } + + ahl &= 0xffff0000; // Clean lower 16 bits for repeated LO16s + a = *target & 0xffff; // Take lower 16 bits of the target + a = (a << 16) >> 16; // Sign extend them + ahl += a; // Add lower 16 bits. AHL is now complete + + // Fix: we can have LO16 access to the short segment sometimes + if (lo16InShorts) + relocation = ahl + _shortsSegment->getOffset(); // Add in the short segment offset + else // It's in the regular segment + relocation = ahl + (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) + debug(8, "elfloader: R_MIPS_LO16: i=%d, offset=%x, a=%x, ahl = %x, lastTarget = %x, origt = %x, target = %x", + i, rel[i].r_offset, a, ahl, *lastTarget, origTarget, *target); + if (lo16InShorts && debugRelocs[2]++ < DEBUG_NUM) + debug(8, "elfloader: R_MIPS_LO16s: i=%d, offset=%x, a=%x, ahl = %x, lastTarget = %x, origt = %x, target = %x", + i, rel[i].r_offset, a, ahl, *lastTarget, origTarget, *target); + } + break; + + case R_MIPS_26: // Absolute addressing (for jumps and branches only) + if (sym->st_shndx < SHN_LOPROC) { // Only relocate for main segment + a = *target & 0x03ffffff; // Get 26 bits' worth of the addend + a = (a << 6) >> 6; // Sign extend a + relocation = ((a << 2) + (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) + debug(8, "elfloader: R_MIPS_26: i=%d, offset=%x, symbol=%d, stinfo=%x, a=%x, origTarget=%x, target=%x", + i, rel[i].r_offset, REL_INDEX(rel[i].r_info), sym->st_info, a, origTarget, *target); + } else { + if (debugRelocs[4]++ < DEBUG_NUM) + debug(8, "elfloader: R_MIPS_26: i=%d, offset=%x, symbol=%d, stinfo=%x, a=%x, origTarget=%x, target=%x", + i, rel[i].r_offset, REL_INDEX(rel[i].r_info), sym->st_info, a, origTarget, *target); + } + break; + + case R_MIPS_GPREL16: // GP Relative addressing + if (_shortsSegment->getOffset() != 0 && // Only relocate if we shift the shorts section + ShortsMan.inGeneralSegment((char *)sym->st_value)) { // Only relocate things in the plugin hole + a = *target & 0xffff; // Get 16 bits' worth of the addend + a = (a << 16) >> 16; // Sign extend it + + relocation = a + _shortsSegment->getOffset(); + + *target &= 0xffff0000; // Clear the lower 16 bits of the target + *target |= relocation & 0xffff; + + if (debugRelocs[5]++ < DEBUG_NUM) + debug(8, "elfloader: R_MIPS_GPREL16: i=%d, a=%x, gpVal=%x, origTarget=%x, target=%x, offset=%x", + i, a, _gpVal, origTarget, *target, _shortsSegment->getOffset()); + } + + break; + + case R_MIPS_32: // Absolute addressing + if (sym->st_shndx < SHN_LOPROC) { // Only shift for plugin section. + a = *target; // Get full 32 bits of addend + + if (ShortsMan.inGeneralSegment((char *)sym->st_value)) // Check if we're in the shorts segment + relocation = a + _shortsSegment->getOffset(); // Shift by shorts offset + else // We're in the main section + relocation = a + (Elf32_Addr)_segment; // Shift by main offset + *target = relocation; + + if (debugRelocs[6]++ < DEBUG_NUM) + debug("8, elfloader: R_MIPS_32: i=%d, a=%x, origTarget=%x, target=%x", i, a, origTarget, *target); + } + break; + + default: + warning("elfloader: Unknown relocation type %x at relocation %d.", REL_TYPE(rel[i].r_info), i); + free(rel); + return false; + } + } + + debug(2, "elfloader: Done with relocation. extendedHi16=%d", extendedHi16); + + free(rel); + return true; +} + +bool MIPSDLObject::relocateRels(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) + warning("elfloader: Symbol out of bounds! st_value = %x", s->st_value); + } else { // shorts section + shortsCount++; + s->st_value += _shortsSegment->getOffset(); + if (!_shortsSegment->inSegment((char *)s->st_value)) + warning("elfloader: Symbol out of bounds! st_value = %x", s->st_value); + } + } + } +} + +bool MIPSDLObject::loadSegment(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 + debug(2, "elfloader: Extra mem is %x", 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))) { + warning("elfloader: Out of memory."); + return false; + } + debug(2, "elfloader: Allocated segment @ %p", _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(); + debug(2, "elfloader: Shorts segment @ %p to %p. Segment wants to be at %x. Offset=%x", + _shortsSegment->getStart(), _shortsSegment->getEnd(), phdr->p_vaddr, _shortsSegment->getOffset()); + } + + // Set bss segment to 0 if necessary (assumes bss is at the end) + if (phdr->p_memsz > phdr->p_filesz) { + debug(2, "elfloader: Setting %p to %p to 0 for bss", baseAddress + phdr->p_filesz, baseAddress + phdr->p_memsz); + memset(baseAddress + phdr->p_filesz, 0, phdr->p_memsz - phdr->p_filesz); + } + + debug(2, "elfloader: Reading the segment into memory"); + + // Read the segment into memory + if (!DLFile->seek(phdr->p_offset, SEEK_SET) || + DLFile->read(baseAddress, phdr->p_filesz) != phdr->p_filesz) { + warning("elfloader: Segment load failed."); + return false; + } + + debug(2, "elfloader: Segment has been read into memory"); + + return true; +} + +// Unload all objects from memory +void MIPSDLObject::unload() { + discard_symtab(); + free(_segment); + _segment = 0; + + if (_shortsSegment) { + ShortsMan.deleteSegment(_shortsSegment); + _shortsSegment = 0; + } +} + +#endif /* defined(DYNAMIC_MODULES) && defined(MIPS_TARGET) */ diff --git a/backends/plugins/elf/mips-loader.h b/backends/plugins/elf/mips-loader.h new file mode 100644 index 0000000000..a3210b5b12 --- /dev/null +++ b/backends/plugins/elf/mips-loader.h @@ -0,0 +1,50 @@ + +/* 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 "backends/plugins/elf/elf-loader.h" +#include "backends/plugins/elf/shorts-segment-manager.h" + +class MIPSDLObject : public DLObject { +protected: + ShortSegmentManager::Segment *_shortsSegment; // For assigning shorts ranges + unsigned int _gpVal; // Value of Global Pointer + + virtual bool relocate(Common::SeekableReadStream* DLFile, unsigned long offset, unsigned long size, void *relSegment); + virtual bool relocateRels(Common::SeekableReadStream* DLFile, Elf32_Ehdr *ehdr, Elf32_Shdr *shdr); + virtual void relocateSymbols(Elf32_Addr offset); + virtual bool loadSegment(Common::SeekableReadStream* DLFile, Elf32_Phdr *phdr); + virtual void unload(); + +public: + MIPSDLObject() : DLObject() { + _shortsSegment = NULL; + _gpVal = 0; + } +}; + +#endif /* defined(DYNAMIC_MODULES) && defined(MIPS_TARGET) */ diff --git a/backends/plugins/elf/plugin.syms b/backends/plugins/elf/plugin.syms new file mode 100644 index 0000000000..24ee1a19dc --- /dev/null +++ b/backends/plugins/elf/plugin.syms @@ -0,0 +1,8 @@ +PLUGIN_getVersion +PLUGIN_getType +PLUGIN_getTypeVersion +PLUGIN_getObject +___plugin_ctors +___plugin_ctors_end +___plugin_dtors +___plugin_dtors_end diff --git a/backends/plugins/elf/ppc-loader.cpp b/backends/plugins/elf/ppc-loader.cpp new file mode 100644 index 0000000000..21a9a6c8a0 --- /dev/null +++ b/backends/plugins/elf/ppc-loader.cpp @@ -0,0 +1,128 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL: https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/branches/gsoc2010-plugins/backends/plugins/arm-loader.cpp $ + * $Id: arm-loader.cpp 52058 2010-08-13 05:58:11Z toneman1138 $ + * + */ + +#if defined(DYNAMIC_MODULES) && defined(PPC_TARGET) + +#include "backends/plugins/elf/elf-loader.h" +#include "backends/plugins/elf/ppc-loader.h" + +#include "common/debug.h" + +bool PPCDLObject::relocate(Common::SeekableReadStream* DLFile, unsigned long offset, unsigned long size, void *relSegment) { + Elf32_Rela *rel = NULL; + + if (!(rel = (Elf32_Rela *)malloc(size))) { + warning("elfloader: Out of memory."); + return false; + } + + if (DLFile->seek(offset, SEEK_SET) < 0 || + DLFile->read(rel, size) != size) { + warning("elfloader: Relocation table load failed."); + free(rel); + return false; + } + + int cnt = size / sizeof(*rel); + + debug(2, "elfloader: Loaded relocation table. %d entries. base address=%p\n", cnt, relSegment); + + uint32 *src; + uint32 value; + + for (int i = 0; i < cnt; i++) { + // Get the symbol this relocation entry is referring to + Elf32_Sym *sym = (Elf32_Sym *)(_symtab) + (REL_INDEX(rel[i].r_info)); + + // Get the target instruction in the code + src = (uint32 *)((char *)relSegment + rel[i].r_offset - _segmentVMA); + value = sym->st_value + rel[i].r_addend; + + //debug(8, "elfloader: i=%05d %p +0x%04x: (0x%08x) 0x%08x ", i, src, rel[i].r_addend, sym->st_value, *src); + + switch (REL_TYPE(rel[i].r_info)) { + case R_PPC_ADDR32: + *src = value; + debug(8, "elfloader: R_PPC_ADDR32 -> 0x%08x\n", *src); + break; + case R_PPC_ADDR16_LO: + *((uint16 *) src) = value; + debug(8, "elfloader: R_PPC_ADDR16_LO -> 0x%08x\n", *src); + break; + case R_PPC_ADDR16_HI: + *(uint16 *) src = value >> 16; + debug(8, "elfloader: R_PPC_ADDR16_HA -> 0x%08x\n", *src); + break; + case R_PPC_ADDR16_HA: + *(uint16 *) src = (value + 0x8000) >> 16; + debug(8, "elfloader: R_PPC_ADDR16_HA -> 0x%08x\n", *src); + break; + case R_PPC_REL24: + *src = (*src & ~0x03fffffc) | ((value - (uint32) src) & 0x03fffffc); + debug(8, "elfloader: R_PPC_REL24 -> 0x%08x\n", *src); + break; + case R_PPC_REL32: + *src = value - (uint32) src; + debug(8, "elfloader: R_PPC_REL32 -> 0x%08x\n", *src); + break; + default: + warning("elfloader: Unknown relocation type %d\n", REL_TYPE(rel[i].r_info)); + free(rel); + return false; + } + } + + free(rel); + return true; +} + +bool PPCDLObject::relocateRels(Common::SeekableReadStream* DLFile, Elf32_Ehdr *ehdr, Elf32_Shdr *shdr) { + for (int i = 0; i < ehdr->e_shnum; i++) { + Elf32_Shdr *curShdr = &(shdr[i]); + + if ((curShdr->sh_type == SHT_REL) && + curShdr->sh_entsize == sizeof(Elf32_Rel) && + (int)curShdr->sh_link == _symtab_sect && + curShdr->sh_info < ehdr->e_shnum && + (shdr[curShdr->sh_info].sh_flags & SHF_ALLOC)) { + warning("elfloader: REL entries not supported!\n"); + return false; + } + + if ((curShdr->sh_type == SHT_RELA) && + curShdr->sh_entsize == sizeof(Elf32_Rela) && + (int)curShdr->sh_link == _symtab_sect && + curShdr->sh_info < ehdr->e_shnum && + (shdr[curShdr->sh_info].sh_flags & SHF_ALLOC)) { + if (!relocate(DLFile, curShdr->sh_offset, curShdr->sh_size, _segment)) + return false; + } + } + + return true; +} + +#endif /* defined(DYNAMIC_MODULES) && defined(PPC_TARGET) */ + diff --git a/backends/plugins/elf/ppc-loader.h b/backends/plugins/elf/ppc-loader.h new file mode 100644 index 0000000000..13043924bb --- /dev/null +++ b/backends/plugins/elf/ppc-loader.h @@ -0,0 +1,40 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL: https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/branches/gsoc2010-plugins/backends/plugins/arm-loader.h $ + * $Id: arm-loader.h 52053 2010-08-13 02:58:52Z toneman1138 $ + * + */ + +#if defined(DYNAMIC_MODULES) && defined(PPC_TARGET) + +#include "backends/plugins/elf/elf-loader.h" + +class PPCDLObject : public DLObject { +protected: + virtual bool relocate(Common::SeekableReadStream* DLFile, unsigned long offset, unsigned long size, void *relSegment); + virtual bool relocateRels(Common::SeekableReadStream* DLFile, Elf32_Ehdr *ehdr, Elf32_Shdr *shdr); + +public: + PPCDLObject() : DLObject() {} +}; + +#endif /* defined(DYNAMIC_MODULES) && defined(PPC_TARGET) */ + diff --git a/backends/plugins/elf/shorts-segment-manager.cpp b/backends/plugins/elf/shorts-segment-manager.cpp new file mode 100644 index 0000000000..612ef19bbe --- /dev/null +++ b/backends/plugins/elf/shorts-segment-manager.cpp @@ -0,0 +1,84 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#if defined(DYNAMIC_MODULES) && defined(MIPS_TARGET) + +#include "backends/plugins/elf/shorts-segment-manager.h" + +#include "common/debug.h" + +extern char __plugin_hole_start; // Indicates start of hole in program file for shorts +extern char __plugin_hole_end; // Indicates end of hole in program file +extern char _gp[]; // Value of gp register + +DECLARE_SINGLETON(ShortSegmentManager); // For singleton + +ShortSegmentManager::ShortSegmentManager() { + _shortsStart = &__plugin_hole_start ; //shorts segment begins at the plugin hole we made when linking + _shortsEnd = &__plugin_hole_end; //and ends at the end of that hole. +} + +ShortSegmentManager::Segment *ShortSegmentManager::newSegment(int size, char *origAddr) { + char *lastAddress = origAddr; + Common::List::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) { + warning("elfloader: No space in shorts segment for %x bytes. Last address is %p, max address is %p.", + size, lastAddress, _shortsEnd); + return 0; + } + + Segment *seg = new Segment(lastAddress, size, origAddr); // Create a new segment + + if (lastAddress + size > _highestAddress) + _highestAddress = lastAddress + size; // Keep track of maximum + + _list.insert(i, seg); + + debug(2, "elfloader: Shorts segment size %x allocated. End = %p. Remaining space = %x. Highest so far is %p.", + size, lastAddress + size, _shortsEnd - _list.back()->getEnd(), _highestAddress); + + return seg; +} + +void ShortSegmentManager::deleteSegment(ShortSegmentManager::Segment *seg) { + debug(2, "elfloader: Deleting shorts segment from %p to %p.", seg->getStart(), seg->getEnd()); + _list.remove(seg); + delete seg; +} + +#endif /* DYNAMIC_MODULES && MIPS_TARGET */ diff --git a/backends/plugins/elf/shorts-segment-manager.h b/backends/plugins/elf/shorts-segment-manager.h new file mode 100644 index 0000000000..b3650562ed --- /dev/null +++ b/backends/plugins/elf/shorts-segment-manager.h @@ -0,0 +1,103 @@ +/* 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) + +#ifndef SHORTS_SEGMENT_MANAGER_H +#define SHORTS_SEGMENT_MANAGER_H + +#include "backends/plugins/elf/elf32.h" + +#include "common/singleton.h" +#include "common/list.h" + +#define ShortsMan ShortSegmentManager::instance() + +/** + * ShortSegmentManager + * + * Since MIPS is limited to 32 bits per instruction, loading data that's further away than 16 bits + * takes several instructions. Thus, small global data (which is likely to be accessed a lot from + * multiple locations) is often put into a GP-relative area (GP standing for the global pointer register) + * in MIPS processors. This class manages these segments of small global data, and is used by the + * member functions of MIPSDLObject, which query in information from this manager in order to deal with + * this segment during the loading/unloading of plugins. + * + * Since there's no true dynamic linker to change the GP register between plugins and the main engine, + * custom ld linker scripts for both the main executable and the plugins ensure the GP-area is in the + * same place for both. The ShortSegmentManager accesses this place via the symbols __plugin_hole_start + * and __plugin_hole_end, which are defined in those custom ld linker scripts. + */ +class ShortSegmentManager : public Common::Singleton { +private: + char *_shortsStart; + char *_shortsEnd; + +public: + char *getShortsStart() { + return _shortsStart; + } + + // Returns whether or not an absolute address is in the GP-relative section. + bool inGeneralSegment(char *addr) { + return ((char *)addr >= _shortsStart && (char *)addr < _shortsEnd); + } + + class Segment { + private: + friend class ShortSegmentManager; + Segment(char *start, int size, char *origAddr) : _startAddress(start), _size(size), _origAddress(origAddr) {} + ~Segment() {} + char *_startAddress; // Start of shorts segment in memory + int _size; // Size of shorts segment + char *_origAddress; // Original address this segment was supposed to be at + public: + char *getStart() { + return _startAddress; + } + char *getEnd() { + return (_startAddress + _size); + } + Elf32_Addr getOffset() { + return (Elf32_Addr)(_startAddress - _origAddress); + } + bool inSegment(char *addr) { + return ((char *)addr >= _startAddress && (char *)addr <= _startAddress + _size); + } + }; + + Segment *newSegment(int size, char *origAddr); + void deleteSegment(Segment *); + +private: + ShortSegmentManager(); + friend class Common::Singleton; + Common::List _list; + char *_highestAddress; +}; + +#endif /* SHORTS_SEGMENT_MANAGER_H */ + +#endif /* defined(DYNAMIC_MODULES) && defined(MIPS_TARGET) */ diff --git a/backends/plugins/elf32.h b/backends/plugins/elf32.h deleted file mode 100644 index c83093fed7..0000000000 --- a/backends/plugins/elf32.h +++ /dev/null @@ -1,252 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - * - */ - -#ifndef BACKENDS_ELF_H -#define BACKENDS_ELF_H - -/** - * ELF stuff: - * The contents of this file were gathered mainly from the SYSTEM V APPLICATION BINARY INTERFACE. - * Processor-specific things were garnered from processor-specific supplements to the abi. - */ - -typedef 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 4 - -/* 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" /* ELF Magic number */ - -#define EI_CLASS 4 /* File class byte index */ -#define ELFCLASS32 1 /* 32-bit objects */ - -#define EI_DATA 5 /* Data encoding byte index */ -#define ELFDATA2LSB 1 /* 2's complement, little endian */ -#define ELFDATA2MSB 2 /* 2's complement, big endian */ - -#define EI_VERSION 6 -#define EV_CURRENT 1 /* Current version */ - -// e_type values -#define ET_NONE 0 /* no file type */ -#define ET_REL 1 /* relocatable */ -#define ET_EXEC 2 /* executable */ -#define ET_DYN 3 /* shared object */ -#define ET_CORE 4 /* core file */ - -// e_machine values -#define EM_MIPS 8 -#define EM_PPC 20 -#define EM_ARM 40 - -// Program header (contains info about segment) -typedef struct { - Elf32_Word p_type; /* Segment type */ - Elf32_Off p_offset; /* Segment file offset */ - Elf32_Addr p_vaddr; /* Segment virtual address */ - Elf32_Addr p_paddr; /* Segment physical address */ - Elf32_Word p_filesz; /* Segment size in file */ - Elf32_Word p_memsz; /* Segment size in memory */ - Elf32_Word p_flags; /* Segment flags */ - Elf32_Word p_align; /* Segment alignment */ -} Elf32_Phdr; - -// p_type values -#define PT_NULL 0 /* ignored */ -#define PT_LOAD 1 /* loadable segment */ -#define PT_DYNAMIC 2 /* dynamic linking info */ -#define PT_INTERP 3 /* info about interpreter */ -#define PT_NOTE 4 /* note segment */ -#define PT_SHLIB 5 /* reserved */ -#define PT_PHDR 6 /* Program header table */ -#define PT_MIPS_REGINFO 0x70000000 /* Register usage info for MIPS */ -#define PT_ARM_ARCHEXT 0x70000000 /* Platform architecture compatibility info for ARM */ -#define PT_ARM_EXIDX 0x70000001 /* Exception unwind tables for ARM */ - -// p_flags value -#define PF_X 1 /* execute */ -#define PF_W 2 /* write */ -#define PF_R 4 /* read */ - -// Section header (contains info about section) -typedef struct { - Elf32_Word sh_name; /* Section name (string tbl index) */ - Elf32_Word sh_type; /* Section type */ - Elf32_Word sh_flags; /* Section flags */ - Elf32_Addr sh_addr; /* Section virtual addr at execution */ - Elf32_Off sh_offset; /* Section file offset */ - Elf32_Word sh_size; /* Section size in bytes */ - Elf32_Word sh_link; /* Link to another section */ - Elf32_Word sh_info; /* Additional section information */ - Elf32_Word sh_addralign; /* Section alignment */ - Elf32_Word sh_entsize; /* Entry size if section holds table */ -} Elf32_Shdr; - -// sh_type values -#define SHT_NULL 0 /* Inactive section */ -#define SHT_PROGBITS 1 /* Proprietary */ -#define SHT_SYMTAB 2 /* Symbol table */ -#define SHT_STRTAB 3 /* String table */ -#define SHT_RELA 4 /* Relocation entries with addend */ -#define SHT_HASH 5 /* Symbol hash table */ -#define SHT_DYNAMIC 6 /* Info for dynamic linking */ -#define SHT_NOTE 7 /* Note section */ -#define SHT_NOBITS 8 /* Occupies no space */ -#define SHT_REL 9 /* Relocation entries without addend */ -#define SHT_SHLIB 10 /* Reserved */ -#define SHT_DYNSYM 11 /* Minimal set of dynamic linking symbols */ -#define SHT_MIPS_LIBLSIT 0x70000000 /* Info about dynamic shared object libs for MIPS*/ -#define SHT_MIPS_CONFLICT 0x70000002 /* Conflicts btw executables and shared objects for MIPS */ -#define SHT_MIPS_GPTAB 0x70000003 /* Global pointer table for MIPS*/ -#define SHT_ARM_EXIDX 0x70000001 /* Exception Index table for ARM*/ -#define SHT_ARM_PREEMPTMAP 0x70000002 /* BPABI DLL dynamic linking pre-emption map for ARM */ -#define SHT_ARM_ATTRIBUTES 0x70000003 /* Object file compatibility attributes for ARM*/ - -// sh_flags values -#define SHF_WRITE 0 /* writable section */ -#define SHF_ALLOC 2 /* section occupies memory */ -#define SHF_EXECINSTR 4 /* machine instructions */ -#define SHF_MIPS_GPREL 0x10000000 /* Must be made part of global data area for MIPS */ - -// Symbol entry (contain info about a symbol) -typedef struct { - Elf32_Word st_name; /* Symbol name (string tbl index) */ - Elf32_Addr st_value; /* Symbol value */ - Elf32_Word st_size; /* Symbol size */ - 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 - -// PPC relocation types -#define R_PPC_ADDR32 1 -#define R_PPC_ADDR16_LO 4 -#define R_PPC_ADDR16_HI 5 -#define R_PPC_ADDR16_HA 6 -#define R_PPC_REL24 10 -#define R_PPC_REL32 26 - -// Mock function to get value of global pointer for MIPS -#define getGP() ({ \ - unsigned int __valgp; \ - __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 deleted file mode 100644 index 729c8f4224..0000000000 --- a/backends/plugins/mips-loader.cpp +++ /dev/null @@ -1,334 +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(MIPS_TARGET) - -#include "backends/plugins/mips-loader.h" - -#include "common/debug.h" - -/** - * Follow the instruction of a relocation section. - * - * @param DLFile SeekableReadStream of File - * @param fileOffset 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 = 0; // relocation entry - - // Allocate memory for relocation table - if (!(rel = (Elf32_Rel *)malloc(size))) { - warning("elfloader: Out of memory."); - return false; - } - - // Read in our relocation table - if (!DLFile->seek(offset, SEEK_SET) || - DLFile->read(rel, size) != size) { - warning("elfloader: Relocation table load failed."); - free(rel); - return false; - } - - // Treat each relocation entry. Loop over all of them - int cnt = size / sizeof(*rel); - - debug(2, "elfloader: Loaded relocation table. %d entries. base address=%p", 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 - debug(8, "elfloader: R_MIPS_HI16: i=%d, offset=%x, ahl = %x, target = %x", - i, rel[i].r_offset, ahl, *target); - } - break; - - case R_MIPS_LO16: // Absolute addressing. Needs a HI16 to come before it - if (sym->st_shndx < SHN_LOPROC) { // Only shift for plugin section. (ie. has a real section index) - if (!seenHi16) { // We MUST have seen HI16 first - debug(8, "elfloader: R_MIPS_LO16 w/o preceding R_MIPS_HI16 at relocation %d!", i); - free(rel); - return false; - } - - // Fix: bug in gcc makes LO16s connect to wrong HI16s sometimes (shorts and regular segment) - // Note that we can check the entire shorts segment because the executable's shorts don't belong to this plugin section - // and will be screened out above - bool lo16InShorts = ShortsMan.inGeneralSegment((char *)sym->st_value); - - // Correct the bug by getting the proper value in ahl (taken from the current symbol) - if ((hi16InShorts && !lo16InShorts) || (!hi16InShorts && lo16InShorts)) { - ahl -= (lastHiSymVal & 0xffff0000); // We assume gcc meant the same offset - ahl += (sym->st_value & 0xffff0000); - } - - ahl &= 0xffff0000; // Clean lower 16 bits for repeated LO16s - a = *target & 0xffff; // Take lower 16 bits of the target - a = (a << 16) >> 16; // Sign extend them - ahl += a; // Add lower 16 bits. AHL is now complete - - // Fix: we can have LO16 access to the short segment sometimes - if (lo16InShorts) - relocation = ahl + _shortsSegment->getOffset(); // Add in the short segment offset - else // It's in the regular segment - relocation = ahl + (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) - debug(8, "elfloader: R_MIPS_LO16: i=%d, offset=%x, a=%x, ahl = %x, lastTarget = %x, origt = %x, target = %x", - i, rel[i].r_offset, a, ahl, *lastTarget, origTarget, *target); - if (lo16InShorts && debugRelocs[2]++ < DEBUG_NUM) - debug(8, "elfloader: R_MIPS_LO16s: i=%d, offset=%x, a=%x, ahl = %x, lastTarget = %x, origt = %x, target = %x", - i, rel[i].r_offset, a, ahl, *lastTarget, origTarget, *target); - } - break; - - case R_MIPS_26: // Absolute addressing (for jumps and branches only) - if (sym->st_shndx < SHN_LOPROC) { // Only relocate for main segment - a = *target & 0x03ffffff; // Get 26 bits' worth of the addend - a = (a << 6) >> 6; // Sign extend a - relocation = ((a << 2) + (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) - debug(8, "elfloader: R_MIPS_26: i=%d, offset=%x, symbol=%d, stinfo=%x, a=%x, origTarget=%x, target=%x", - i, rel[i].r_offset, REL_INDEX(rel[i].r_info), sym->st_info, a, origTarget, *target); - } else { - if (debugRelocs[4]++ < DEBUG_NUM) - debug(8, "elfloader: R_MIPS_26: i=%d, offset=%x, symbol=%d, stinfo=%x, a=%x, origTarget=%x, target=%x", - i, rel[i].r_offset, REL_INDEX(rel[i].r_info), sym->st_info, a, origTarget, *target); - } - break; - - case R_MIPS_GPREL16: // GP Relative addressing - if (_shortsSegment->getOffset() != 0 && // Only relocate if we shift the shorts section - ShortsMan.inGeneralSegment((char *)sym->st_value)) { // Only relocate things in the plugin hole - a = *target & 0xffff; // Get 16 bits' worth of the addend - a = (a << 16) >> 16; // Sign extend it - - relocation = a + _shortsSegment->getOffset(); - - *target &= 0xffff0000; // Clear the lower 16 bits of the target - *target |= relocation & 0xffff; - - if (debugRelocs[5]++ < DEBUG_NUM) - debug(8, "elfloader: R_MIPS_GPREL16: i=%d, a=%x, gpVal=%x, origTarget=%x, target=%x, offset=%x", - i, a, _gpVal, origTarget, *target, _shortsSegment->getOffset()); - } - - break; - - case R_MIPS_32: // Absolute addressing - if (sym->st_shndx < SHN_LOPROC) { // Only shift for plugin section. - a = *target; // Get full 32 bits of addend - - if (ShortsMan.inGeneralSegment((char *)sym->st_value)) // Check if we're in the shorts segment - relocation = a + _shortsSegment->getOffset(); // Shift by shorts offset - else // We're in the main section - relocation = a + (Elf32_Addr)_segment; // Shift by main offset - *target = relocation; - - if (debugRelocs[6]++ < DEBUG_NUM) - debug("8, elfloader: R_MIPS_32: i=%d, a=%x, origTarget=%x, target=%x", i, a, origTarget, *target); - } - break; - - default: - warning("elfloader: Unknown relocation type %x at relocation %d.", REL_TYPE(rel[i].r_info), i); - free(rel); - return false; - } - } - - debug(2, "elfloader: Done with relocation. extendedHi16=%d", extendedHi16); - - free(rel); - return true; -} - -bool MIPSDLObject::relocateRels(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) - warning("elfloader: Symbol out of bounds! st_value = %x", s->st_value); - } else { // shorts section - shortsCount++; - s->st_value += _shortsSegment->getOffset(); - if (!_shortsSegment->inSegment((char *)s->st_value)) - warning("elfloader: Symbol out of bounds! st_value = %x", s->st_value); - } - } - } -} - -bool MIPSDLObject::loadSegment(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 - debug(2, "elfloader: Extra mem is %x", 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))) { - warning("elfloader: Out of memory."); - return false; - } - debug(2, "elfloader: Allocated segment @ %p", _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(); - debug(2, "elfloader: Shorts segment @ %p to %p. Segment wants to be at %x. Offset=%x", - _shortsSegment->getStart(), _shortsSegment->getEnd(), phdr->p_vaddr, _shortsSegment->getOffset()); - } - - // Set bss segment to 0 if necessary (assumes bss is at the end) - if (phdr->p_memsz > phdr->p_filesz) { - debug(2, "elfloader: Setting %p to %p to 0 for bss", baseAddress + phdr->p_filesz, baseAddress + phdr->p_memsz); - memset(baseAddress + phdr->p_filesz, 0, phdr->p_memsz - phdr->p_filesz); - } - - debug(2, "elfloader: Reading the segment into memory"); - - // Read the segment into memory - if (!DLFile->seek(phdr->p_offset, SEEK_SET) || - DLFile->read(baseAddress, phdr->p_filesz) != phdr->p_filesz) { - warning("elfloader: Segment load failed."); - return false; - } - - debug(2, "elfloader: Segment has been read into memory"); - - return true; -} - -// Unload all objects from memory -void MIPSDLObject::unload() { - discard_symtab(); - free(_segment); - _segment = 0; - - if (_shortsSegment) { - ShortsMan.deleteSegment(_shortsSegment); - _shortsSegment = 0; - } -} - -#endif /* defined(DYNAMIC_MODULES) && defined(MIPS_TARGET) */ diff --git a/backends/plugins/mips-loader.h b/backends/plugins/mips-loader.h deleted file mode 100644 index 98bda5263f..0000000000 --- a/backends/plugins/mips-loader.h +++ /dev/null @@ -1,50 +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(MIPS_TARGET) - -#include "backends/plugins/elf-loader.h" -#include "backends/plugins/shorts-segment-manager.h" - -class MIPSDLObject : public DLObject { -protected: - ShortSegmentManager::Segment *_shortsSegment; // For assigning shorts ranges - unsigned int _gpVal; // Value of Global Pointer - - virtual bool relocate(Common::SeekableReadStream* DLFile, unsigned long offset, unsigned long size, void *relSegment); - virtual bool relocateRels(Common::SeekableReadStream* DLFile, Elf32_Ehdr *ehdr, Elf32_Shdr *shdr); - virtual void relocateSymbols(Elf32_Addr offset); - virtual bool loadSegment(Common::SeekableReadStream* DLFile, Elf32_Phdr *phdr); - virtual void unload(); - -public: - MIPSDLObject() : DLObject() { - _shortsSegment = NULL; - _gpVal = 0; - } -}; - -#endif /* defined(DYNAMIC_MODULES) && defined(MIPS_TARGET) */ diff --git a/backends/plugins/plugin.syms b/backends/plugins/plugin.syms deleted file mode 100644 index 24ee1a19dc..0000000000 --- a/backends/plugins/plugin.syms +++ /dev/null @@ -1,8 +0,0 @@ -PLUGIN_getVersion -PLUGIN_getType -PLUGIN_getTypeVersion -PLUGIN_getObject -___plugin_ctors -___plugin_ctors_end -___plugin_dtors -___plugin_dtors_end diff --git a/backends/plugins/ppc-loader.cpp b/backends/plugins/ppc-loader.cpp deleted file mode 100644 index dcd5fceff1..0000000000 --- a/backends/plugins/ppc-loader.cpp +++ /dev/null @@ -1,128 +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: https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/branches/gsoc2010-plugins/backends/plugins/arm-loader.cpp $ - * $Id: arm-loader.cpp 52058 2010-08-13 05:58:11Z toneman1138 $ - * - */ - -#if defined(DYNAMIC_MODULES) && defined(PPC_TARGET) - -#include "backends/plugins/elf-loader.h" -#include "backends/plugins/ppc-loader.h" - -#include "common/debug.h" - -bool PPCDLObject::relocate(Common::SeekableReadStream* DLFile, unsigned long offset, unsigned long size, void *relSegment) { - Elf32_Rela *rel = NULL; - - if (!(rel = (Elf32_Rela *)malloc(size))) { - warning("elfloader: Out of memory."); - return false; - } - - if (DLFile->seek(offset, SEEK_SET) < 0 || - DLFile->read(rel, size) != size) { - warning("elfloader: Relocation table load failed."); - free(rel); - return false; - } - - int cnt = size / sizeof(*rel); - - debug(2, "elfloader: Loaded relocation table. %d entries. base address=%p\n", cnt, relSegment); - - uint32 *src; - uint32 value; - - for (int i = 0; i < cnt; i++) { - // Get the symbol this relocation entry is referring to - Elf32_Sym *sym = (Elf32_Sym *)(_symtab) + (REL_INDEX(rel[i].r_info)); - - // Get the target instruction in the code - src = (uint32 *)((char *)relSegment + rel[i].r_offset - _segmentVMA); - value = sym->st_value + rel[i].r_addend; - - //debug(8, "elfloader: i=%05d %p +0x%04x: (0x%08x) 0x%08x ", i, src, rel[i].r_addend, sym->st_value, *src); - - switch (REL_TYPE(rel[i].r_info)) { - case R_PPC_ADDR32: - *src = value; - debug(8, "elfloader: R_PPC_ADDR32 -> 0x%08x\n", *src); - break; - case R_PPC_ADDR16_LO: - *((uint16 *) src) = value; - debug(8, "elfloader: R_PPC_ADDR16_LO -> 0x%08x\n", *src); - break; - case R_PPC_ADDR16_HI: - *(uint16 *) src = value >> 16; - debug(8, "elfloader: R_PPC_ADDR16_HA -> 0x%08x\n", *src); - break; - case R_PPC_ADDR16_HA: - *(uint16 *) src = (value + 0x8000) >> 16; - debug(8, "elfloader: R_PPC_ADDR16_HA -> 0x%08x\n", *src); - break; - case R_PPC_REL24: - *src = (*src & ~0x03fffffc) | ((value - (uint32) src) & 0x03fffffc); - debug(8, "elfloader: R_PPC_REL24 -> 0x%08x\n", *src); - break; - case R_PPC_REL32: - *src = value - (uint32) src; - debug(8, "elfloader: R_PPC_REL32 -> 0x%08x\n", *src); - break; - default: - warning("elfloader: Unknown relocation type %d\n", REL_TYPE(rel[i].r_info)); - free(rel); - return false; - } - } - - free(rel); - return true; -} - -bool PPCDLObject::relocateRels(Common::SeekableReadStream* DLFile, Elf32_Ehdr *ehdr, Elf32_Shdr *shdr) { - for (int i = 0; i < ehdr->e_shnum; i++) { - Elf32_Shdr *curShdr = &(shdr[i]); - - if ((curShdr->sh_type == SHT_REL) && - curShdr->sh_entsize == sizeof(Elf32_Rel) && - (int)curShdr->sh_link == _symtab_sect && - curShdr->sh_info < ehdr->e_shnum && - (shdr[curShdr->sh_info].sh_flags & SHF_ALLOC)) { - warning("elfloader: REL entries not supported!\n"); - return false; - } - - if ((curShdr->sh_type == SHT_RELA) && - curShdr->sh_entsize == sizeof(Elf32_Rela) && - (int)curShdr->sh_link == _symtab_sect && - curShdr->sh_info < ehdr->e_shnum && - (shdr[curShdr->sh_info].sh_flags & SHF_ALLOC)) { - if (!relocate(DLFile, curShdr->sh_offset, curShdr->sh_size, _segment)) - return false; - } - } - - return true; -} - -#endif /* defined(DYNAMIC_MODULES) && defined(PPC_TARGET) */ - diff --git a/backends/plugins/ppc-loader.h b/backends/plugins/ppc-loader.h deleted file mode 100644 index 14d1f16720..0000000000 --- a/backends/plugins/ppc-loader.h +++ /dev/null @@ -1,40 +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: https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/branches/gsoc2010-plugins/backends/plugins/arm-loader.h $ - * $Id: arm-loader.h 52053 2010-08-13 02:58:52Z toneman1138 $ - * - */ - -#if defined(DYNAMIC_MODULES) && defined(PPC_TARGET) - -#include "backends/plugins/elf-loader.h" - -class PPCDLObject : public DLObject { -protected: - virtual bool relocate(Common::SeekableReadStream* DLFile, unsigned long offset, unsigned long size, void *relSegment); - virtual bool relocateRels(Common::SeekableReadStream* DLFile, Elf32_Ehdr *ehdr, Elf32_Shdr *shdr); - -public: - PPCDLObject() : DLObject() {} -}; - -#endif /* defined(DYNAMIC_MODULES) && defined(PPC_TARGET) */ - diff --git a/backends/plugins/ps2/ps2-provider.h b/backends/plugins/ps2/ps2-provider.h index 809b88920a..00ddb4647e 100644 --- a/backends/plugins/ps2/ps2-provider.h +++ b/backends/plugins/ps2/ps2-provider.h @@ -25,8 +25,8 @@ #if defined(DYNAMIC_MODULES) && defined(__PLAYSTATION2__) -#include "backends/plugins/elf-provider.h" -#include "backends/plugins/mips-loader.h" +#include "backends/plugins/elf/elf-provider.h" +#include "backends/plugins/elf/mips-loader.h" class PS2PluginProvider : public ELFPluginProvider { class PS2Plugin : public ELFPlugin { diff --git a/backends/plugins/psp/psp-provider.h b/backends/plugins/psp/psp-provider.h index b7934179bf..18623e448c 100644 --- a/backends/plugins/psp/psp-provider.h +++ b/backends/plugins/psp/psp-provider.h @@ -28,8 +28,8 @@ #ifndef BACKENDS_PLUGINS_PSP_PSP_PROVIDER_H #define BACKENDS_PLUGINS_PSP_PSP_PROVIDER_H -#include "backends/plugins/elf-provider.h" -#include "backends/plugins/mips-loader.h" +#include "backends/plugins/elf/elf-provider.h" +#include "backends/plugins/elf/mips-loader.h" class PSPPluginProvider : public ELFPluginProvider { class PSPPlugin : public ELFPlugin { diff --git a/backends/plugins/shorts-segment-manager.cpp b/backends/plugins/shorts-segment-manager.cpp deleted file mode 100644 index 17af17aa45..0000000000 --- a/backends/plugins/shorts-segment-manager.cpp +++ /dev/null @@ -1,84 +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(MIPS_TARGET) - -#include "backends/plugins/shorts-segment-manager.h" - -#include "common/debug.h" - -extern char __plugin_hole_start; // Indicates start of hole in program file for shorts -extern char __plugin_hole_end; // Indicates end of hole in program file -extern char _gp[]; // Value of gp register - -DECLARE_SINGLETON(ShortSegmentManager); // For singleton - -ShortSegmentManager::ShortSegmentManager() { - _shortsStart = &__plugin_hole_start ; //shorts segment begins at the plugin hole we made when linking - _shortsEnd = &__plugin_hole_end; //and ends at the end of that hole. -} - -ShortSegmentManager::Segment *ShortSegmentManager::newSegment(int size, char *origAddr) { - char *lastAddress = origAddr; - Common::List::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) { - warning("elfloader: No space in shorts segment for %x bytes. Last address is %p, max address is %p.", - size, lastAddress, _shortsEnd); - return 0; - } - - Segment *seg = new Segment(lastAddress, size, origAddr); // Create a new segment - - if (lastAddress + size > _highestAddress) - _highestAddress = lastAddress + size; // Keep track of maximum - - _list.insert(i, seg); - - debug(2, "elfloader: Shorts segment size %x allocated. End = %p. Remaining space = %x. Highest so far is %p.", - size, lastAddress + size, _shortsEnd - _list.back()->getEnd(), _highestAddress); - - return seg; -} - -void ShortSegmentManager::deleteSegment(ShortSegmentManager::Segment *seg) { - debug(2, "elfloader: Deleting shorts segment from %p to %p.", seg->getStart(), seg->getEnd()); - _list.remove(seg); - delete seg; -} - -#endif /* DYNAMIC_MODULES && MIPS_TARGET */ diff --git a/backends/plugins/shorts-segment-manager.h b/backends/plugins/shorts-segment-manager.h deleted file mode 100644 index bf583c021a..0000000000 --- a/backends/plugins/shorts-segment-manager.h +++ /dev/null @@ -1,103 +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(MIPS_TARGET) - -#ifndef SHORTS_SEGMENT_MANAGER_H -#define SHORTS_SEGMENT_MANAGER_H - -#include "backends/plugins/elf32.h" - -#include "common/singleton.h" -#include "common/list.h" - -#define ShortsMan ShortSegmentManager::instance() - -/** - * ShortSegmentManager - * - * Since MIPS is limited to 32 bits per instruction, loading data that's further away than 16 bits - * takes several instructions. Thus, small global data (which is likely to be accessed a lot from - * multiple locations) is often put into a GP-relative area (GP standing for the global pointer register) - * in MIPS processors. This class manages these segments of small global data, and is used by the - * member functions of MIPSDLObject, which query in information from this manager in order to deal with - * this segment during the loading/unloading of plugins. - * - * Since there's no true dynamic linker to change the GP register between plugins and the main engine, - * custom ld linker scripts for both the main executable and the plugins ensure the GP-area is in the - * same place for both. The ShortSegmentManager accesses this place via the symbols __plugin_hole_start - * and __plugin_hole_end, which are defined in those custom ld linker scripts. - */ -class ShortSegmentManager : public Common::Singleton { -private: - char *_shortsStart; - char *_shortsEnd; - -public: - char *getShortsStart() { - return _shortsStart; - } - - // Returns whether or not an absolute address is in the GP-relative section. - bool inGeneralSegment(char *addr) { - return ((char *)addr >= _shortsStart && (char *)addr < _shortsEnd); - } - - class Segment { - private: - friend class ShortSegmentManager; - Segment(char *start, int size, char *origAddr) : _startAddress(start), _size(size), _origAddress(origAddr) {} - ~Segment() {} - char *_startAddress; // Start of shorts segment in memory - int _size; // Size of shorts segment - char *_origAddress; // Original address this segment was supposed to be at - public: - char *getStart() { - return _startAddress; - } - char *getEnd() { - return (_startAddress + _size); - } - Elf32_Addr getOffset() { - return (Elf32_Addr)(_startAddress - _origAddress); - } - bool inSegment(char *addr) { - return ((char *)addr >= _startAddress && (char *)addr <= _startAddress + _size); - } - }; - - Segment *newSegment(int size, char *origAddr); - void deleteSegment(Segment *); - -private: - ShortSegmentManager(); - friend class Common::Singleton; - Common::List _list; - char *_highestAddress; -}; - -#endif /* SHORTS_SEGMENT_MANAGER_H */ - -#endif /* defined(DYNAMIC_MODULES) && defined(MIPS_TARGET) */ diff --git a/backends/plugins/wii/wii-provider.h b/backends/plugins/wii/wii-provider.h index a299ff4add..deb143b02a 100644 --- a/backends/plugins/wii/wii-provider.h +++ b/backends/plugins/wii/wii-provider.h @@ -25,8 +25,8 @@ #if defined(DYNAMIC_MODULES) && defined(__WII__) -#include "backends/plugins/elf-provider.h" -#include "backends/plugins/ppc-loader.h" +#include "backends/plugins/elf/elf-provider.h" +#include "backends/plugins/elf/ppc-loader.h" class WiiPluginProvider : public ELFPluginProvider { class WiiPlugin : public ELFPlugin { -- cgit v1.2.3