diff options
Diffstat (limited to 'backends')
-rw-r--r-- | backends/plugins/elf-loader.cpp | 73 | ||||
-rw-r--r-- | backends/plugins/elf-loader.h | 15 | ||||
-rw-r--r-- | backends/plugins/mips-loader.cpp | 89 |
3 files changed, 109 insertions, 68 deletions
diff --git a/backends/plugins/elf-loader.cpp b/backends/plugins/elf-loader.cpp index 3c66c765f6..9787c880ae 100644 --- a/backends/plugins/elf-loader.cpp +++ b/backends/plugins/elf-loader.cpp @@ -37,6 +37,11 @@ #include "common/fs.h" #include "elf-loader.h" +#ifdef __PSP__ +#include "backends/platform/psp/powerman.h" +#include "psputils.h" +#endif + #ifdef __DS__ #include <nds.h> #endif @@ -62,6 +67,9 @@ static void flushDataCache() { FlushCache(0); FlushCache(2); #endif +#ifdef __PSP__ + sceKernelDcacheWritebackAll(); +#endif } // Expel the symbol table from memory @@ -78,13 +86,6 @@ void DLObject::unload() { discard_symtab(); free(_segment); _segment = NULL; - -#ifdef MIPS_TARGET - if (_shortsSegment) { - ShortsMan.deleteSegment(_shortsSegment); - _shortsSegment = NULL; - } -#endif } bool DLObject::readElfHeader(Common::SeekableReadStream* DLFile, Elf32_Ehdr *ehdr) { @@ -97,7 +98,7 @@ bool DLObject::readElfHeader(Common::SeekableReadStream* DLFile, Elf32_Ehdr *ehd ehdr->e_machine != EM_ARM || // Check for ARM machine type #endif #ifdef MIPS_TARGET - ehdr->e_machine != EM_MIPS || + ehdr->e_machine != EM_MIPS || // Check for MIPS machine type #endif ehdr->e_phentsize < sizeof(Elf32_Phdr) || // Check for size of program header ehdr->e_shentsize != sizeof(Elf32_Shdr)) { // Check for size of section header @@ -137,33 +138,6 @@ bool DLObject::loadSegment(Common::SeekableReadStream* DLFile, Elf32_Phdr *phdr) char *baseAddress = 0; -#ifdef MIPS_TARGET - // We need to take account of non-allocated segment for shorts - if (phdr->p_flags & PF_X) { // This is a relocated segment - - // Attempt to allocate memory for segment - int extra = phdr->p_vaddr % phdr->p_align; // Get extra length TODO: check logic here - DBG("extra mem is %x\n", extra); - - if (phdr->p_align < 0x10000) phdr->p_align = 0x10000; // Fix for wrong alignment on e.g. AGI - - if (!(_segment = (char *)memalign(phdr->p_align, phdr->p_memsz + extra))) { - seterror("Out of memory.\n"); - return false; - } - DBG("allocated segment @ %p\n", _segment); - - // Get offset to load segment into - baseAddress = (char *)_segment + phdr->p_vaddr; - _segmentSize = phdr->p_memsz + extra; - } else { // This is a shorts section. - _shortsSegment = ShortsMan.newSegment(phdr->p_memsz, (char *)phdr->p_vaddr); - - baseAddress = _shortsSegment->getStart(); - DBG("shorts segment @ %p to %p. Segment wants to be at %x. Offset=%x\n", - _shortsSegment->getStart(), _shortsSegment->getEnd(), phdr->p_vaddr, _shortsSegment->getOffset()); - } -#else // Attempt to allocate memory for segment int extra = phdr->p_vaddr % phdr->p_align; // Get extra length TODO: check logic here DBG("extra mem is %x\n", extra); @@ -178,7 +152,6 @@ bool DLObject::loadSegment(Common::SeekableReadStream* DLFile, Elf32_Phdr *phdr) // Get offset to load segment into baseAddress = (char *)_segment + phdr->p_vaddr; _segmentSize = phdr->p_memsz + extra; -#endif // Set bss segment to 0 if necessary (assumes bss is at the end) if (phdr->p_memsz > phdr->p_filesz) { @@ -294,33 +267,13 @@ void DLObject::relocateSymbols(Elf32_Addr offset) { Elf32_Sym *s = (Elf32_Sym *)_symtab; for (int c = _symbol_cnt; c--; s++) { -#ifdef MIPS_TARGET - // Make sure we don't relocate special valued symbols - if (s->st_shndx < SHN_LOPROC) { - if (!ShortsMan.inGeneralSegment((char *)s->st_value)) { - mainCount++; - s->st_value += offset; - if (s->st_value < (Elf32_Addr)_segment || s->st_value > (Elf32_Addr)_segment + _segmentSize) - seterror("Symbol out of bounds! st_value = %x\n", s->st_value); - } else { // shorts section - shortsCount++; - s->st_value += _shortsSegment->getOffset(); - if (!_shortsSegment->inSegment((char *)s->st_value)) - seterror("Symbol out of bounds! st_value = %x\n", s->st_value); - } - - } -#else // Make sure we don't relocate special valued symbols if (s->st_shndx < SHN_LOPROC) { mainCount++; s->st_value += offset; if (s->st_value < (Elf32_Addr)_segment || s->st_value > (Elf32_Addr)_segment + _segmentSize) seterror("Symbol out of bounds! st_value = %x\n", s->st_value); - } -#endif - } } @@ -371,6 +324,10 @@ bool DLObject::open(const char *path) { Common::SeekableReadStream* DLFile; void *ctors_start, *ctors_end; +#ifdef __PSP__ + PowerMan.beginCriticalSection(); +#endif + DBG("open(\"%s\")\n", path); Common::FSNode file(path); @@ -390,6 +347,10 @@ bool DLObject::open(const char *path) { DBG("loaded!/n"); +#ifdef __PSP__ + PowerMan.endCriticalSection(); +#endif + flushDataCache(); ctors_start = symbol("___plugin_ctors"); diff --git a/backends/plugins/elf-loader.h b/backends/plugins/elf-loader.h index 7abe012003..56a9fa3767 100644 --- a/backends/plugins/elf-loader.h +++ b/backends/plugins/elf-loader.h @@ -30,10 +30,6 @@ #include "common/stream.h" #include "backends/plugins/dynamic-plugin.h" -#if defined(MIPS_TARGET) -#include "shorts-segment-manager.h" -#endif - class DLObject { protected: void *_segment, *_symtab; @@ -44,23 +40,18 @@ protected: int _segmentSize; -#ifdef MIPS_TARGET - ShortSegmentManager::Segment *_shortsSegment; // For assigning shorts ranges - unsigned int _gpVal; // Value of Global Pointer -#endif - //void seterror(const char *fmt, ...); - void unload(); + virtual void unload(); virtual bool relocate(Common::SeekableReadStream* DLFile, unsigned long offset, unsigned long size, void *relSegment) = 0; bool load(Common::SeekableReadStream* DLFile); bool readElfHeader(Common::SeekableReadStream* DLFile, Elf32_Ehdr *ehdr); bool readProgramHeaders(Common::SeekableReadStream* DLFile, Elf32_Ehdr *ehdr, Elf32_Phdr *phdr, int num); - bool loadSegment(Common::SeekableReadStream* DLFile, Elf32_Phdr *phdr); + 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); - void relocateSymbols(Elf32_Addr offset); + virtual void relocateSymbols(Elf32_Addr offset); virtual bool relocateRels(Common::SeekableReadStream* DLFile, Elf32_Ehdr *ehdr, Elf32_Shdr *shdr) = 0; public: diff --git a/backends/plugins/mips-loader.cpp b/backends/plugins/mips-loader.cpp index f537729197..7b59a2cffa 100644 --- a/backends/plugins/mips-loader.cpp +++ b/backends/plugins/mips-loader.cpp @@ -259,4 +259,93 @@ bool MIPSDLObject::relocateRels(Common::SeekableReadStream* DLFile, Elf32_Ehdr * return true; } +void MIPSDLObject::relocateSymbols(Elf32_Addr offset) { + + int mainCount = 0; + int shortsCount= 0; + + // Loop over symbols, add relocation offset + Elf32_Sym *s = (Elf32_Sym *)_symtab; + for (int c = _symbol_cnt; c--; s++) { + + // Make sure we don't relocate special valued symbols + if (s->st_shndx < SHN_LOPROC) { + if (!ShortsMan.inGeneralSegment((char *)s->st_value)) { + mainCount++; + s->st_value += offset; + if (s->st_value < (Elf32_Addr)_segment || s->st_value > (Elf32_Addr)_segment + _segmentSize) + seterror("Symbol out of bounds! st_value = %x\n", s->st_value); + } else { // shorts section + shortsCount++; + s->st_value += _shortsSegment->getOffset(); + if (!_shortsSegment->inSegment((char *)s->st_value)) + seterror("Symbol out of bounds! st_value = %x\n", s->st_value); + } + + } + } +} + +bool MIPSDLObject::loadSegment(Common::SeekableReadStream* DLFile, Elf32_Phdr *phdr) { + + char *baseAddress = 0; + + // We need to take account of non-allocated segment for shorts + if (phdr->p_flags & PF_X) { // This is a relocated segment + + // Attempt to allocate memory for segment + int extra = phdr->p_vaddr % phdr->p_align; // Get extra length TODO: check logic here + DBG("extra mem is %x\n", extra); + + if (phdr->p_align < 0x10000) phdr->p_align = 0x10000; // Fix for wrong alignment on e.g. AGI + + if (!(_segment = (char *)memalign(phdr->p_align, phdr->p_memsz + extra))) { + seterror("Out of memory.\n"); + return false; + } + DBG("allocated segment @ %p\n", _segment); + + // Get offset to load segment into + baseAddress = (char *)_segment + phdr->p_vaddr; + _segmentSize = phdr->p_memsz + extra; + } else { // This is a shorts section. + _shortsSegment = ShortsMan.newSegment(phdr->p_memsz, (char *)phdr->p_vaddr); + + baseAddress = _shortsSegment->getStart(); + DBG("shorts segment @ %p to %p. Segment wants to be at %x. Offset=%x\n", + _shortsSegment->getStart(), _shortsSegment->getEnd(), phdr->p_vaddr, _shortsSegment->getOffset()); + } + + // Set bss segment to 0 if necessary (assumes bss is at the end) + if (phdr->p_memsz > phdr->p_filesz) { + DBG("Setting %p to %p to 0 for bss\n", baseAddress + phdr->p_filesz, baseAddress + phdr->p_memsz); + memset(baseAddress + phdr->p_filesz, 0, phdr->p_memsz - phdr->p_filesz); + } + + DBG("Reading the segment into memory\n"); + + // Read the segment into memory + if (DLFile->seek(phdr->p_offset, SEEK_SET) < 0 || + DLFile->read(baseAddress, phdr->p_filesz) != (ssize_t)phdr->p_filesz) { + seterror("Segment load failed."); + return false; + } + + DBG("Segment has been read into memory\n"); + + return true; +} + +// Unload all objects from memory +void MIPSDLObject::unload() { + discard_symtab(); + free(_segment); + _segment = NULL; + + if (_shortsSegment) { + ShortsMan.deleteSegment(_shortsSegment); + _shortsSegment = NULL; + } +} + #endif /* defined(DYNAMIC_MODULES) && defined(MIPS_TARGET) */ |