diff options
Diffstat (limited to 'backends/plugins/elf')
-rw-r--r-- | backends/plugins/elf/arm-loader.cpp | 140 | ||||
-rw-r--r-- | backends/plugins/elf/arm-loader.h | 39 | ||||
-rw-r--r-- | backends/plugins/elf/elf-loader.cpp | 445 | ||||
-rw-r--r-- | backends/plugins/elf/elf-loader.h | 83 | ||||
-rw-r--r-- | backends/plugins/elf/elf-provider.cpp | 99 | ||||
-rw-r--r-- | backends/plugins/elf/elf-provider.h | 75 | ||||
-rw-r--r-- | backends/plugins/elf/elf32.h | 252 | ||||
-rw-r--r-- | backends/plugins/elf/mips-loader.cpp | 334 | ||||
-rw-r--r-- | backends/plugins/elf/mips-loader.h | 50 | ||||
-rw-r--r-- | backends/plugins/elf/plugin.syms | 8 | ||||
-rw-r--r-- | backends/plugins/elf/ppc-loader.cpp | 128 | ||||
-rw-r--r-- | backends/plugins/elf/ppc-loader.h | 40 | ||||
-rw-r--r-- | backends/plugins/elf/shorts-segment-manager.cpp | 84 | ||||
-rw-r--r-- | backends/plugins/elf/shorts-segment-manager.h | 103 |
14 files changed, 1880 insertions, 0 deletions
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 <string.h> +#include <stdarg.h> + +#ifdef __PSP__ +#include <psputils.h> +#include <psputilsforkernel.h> +#endif + +#ifdef __DS__ +#include <nds.h> +#endif + +#ifdef __WII__ +#include <malloc.h> +#include <ogc/cache.h> +#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 <stddef.h> + +#include "backends/plugins/elf/elf32.h" +#include "backends/plugins/dynamic-plugin.h" + +#include "common/stream.h" + +/** + * DLObject + * + * Class that most directly handles operations on a plugin file + * (opening it for reading, loading/unloading it in memory, finding a specific symbol in the file, etc.) + * Subclasses have the same functionality, but implementations specific to different processors/platforms. + */ +class DLObject { +protected: + 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. <http://www.trilithium.com/johan/2004/12/problem-with-dlsym/>. + assert(sizeof(VoidFunc) == sizeof(func)); + VoidFunc tmp; + memcpy(&tmp, &func, sizeof(VoidFunc)); + return tmp; +} + +bool ELFPlugin::loadPlugin() { + assert(!_dlHandle); + DLObject *obj = makeDLObject(); + if (obj->open(_filename.c_str())) { + _dlHandle = obj; + } else { + delete obj; + _dlHandle = 0; + } + + if (!_dlHandle) { + warning("elfloader: Failed loading plugin '%s'", _filename.c_str()); + return false; + } + + 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<Segment *>::iterator i; + + // Find a block that fits, starting from the beginning + for (i = _list.begin(); i != _list.end(); ++i) { + char *currAddress = (*i)->getStart(); + + if ((int)(currAddress - lastAddress) >= size) break; + + lastAddress = (*i)->getEnd(); + } + + if ((Elf32_Addr)lastAddress & 3) + lastAddress += 4 - ((Elf32_Addr)lastAddress & 3); // Round up to multiple of 4 + + if (lastAddress + size > _shortsEnd) { + 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<ShortSegmentManager> { +private: + char *_shortsStart; + char *_shortsEnd; + +public: + char *getShortsStart() { + return _shortsStart; + } + + // Returns whether or not an absolute address is in the GP-relative section. + bool inGeneralSegment(char *addr) { + return ((char *)addr >= _shortsStart && (char *)addr < _shortsEnd); + } + + class Segment { + private: + friend class ShortSegmentManager; + Segment(char *start, int size, char *origAddr) : _startAddress(start), _size(size), _origAddress(origAddr) {} + ~Segment() {} + char *_startAddress; // Start of shorts segment in memory + int _size; // Size of shorts segment + char *_origAddress; // Original address this segment was supposed to be at + public: + char *getStart() { + return _startAddress; + } + char *getEnd() { + return (_startAddress + _size); + } + Elf32_Addr getOffset() { + return (Elf32_Addr)(_startAddress - _origAddress); + } + bool inSegment(char *addr) { + return ((char *)addr >= _startAddress && (char *)addr <= _startAddress + _size); + } + }; + + Segment *newSegment(int size, char *origAddr); + void deleteSegment(Segment *); + +private: + ShortSegmentManager(); + friend class Common::Singleton<ShortSegmentManager>; + Common::List<Segment *> _list; + char *_highestAddress; +}; + +#endif /* SHORTS_SEGMENT_MANAGER_H */ + +#endif /* defined(DYNAMIC_MODULES) && defined(MIPS_TARGET) */ |