diff options
author | Bastien Bouclet | 2019-12-01 17:19:50 +0100 |
---|---|---|
committer | Bastien Bouclet | 2019-12-01 17:19:50 +0100 |
commit | 34e835a20ca648b0fd2e67cefc84511c1dab6217 (patch) | |
tree | 97ba9b239a8fd9c9d8bba925b21262314de2f2c2 /backends/plugins/elf | |
parent | a51c23abd3a667811b01e90b0c8c53505021950a (diff) | |
download | scummvm-rg350-34e835a20ca648b0fd2e67cefc84511c1dab6217.tar.gz scummvm-rg350-34e835a20ca648b0fd2e67cefc84511c1dab6217.tar.bz2 scummvm-rg350-34e835a20ca648b0fd2e67cefc84511c1dab6217.zip |
3DS: Implement dynamic plugins
Allows a full build to run on old generation devices
Diffstat (limited to 'backends/plugins/elf')
-rw-r--r-- | backends/plugins/elf/arm-loader.cpp | 34 | ||||
-rw-r--r-- | backends/plugins/elf/elf-loader.cpp | 32 | ||||
-rw-r--r-- | backends/plugins/elf/elf-loader.h | 4 | ||||
-rw-r--r-- | backends/plugins/elf/mips-loader.cpp | 2 |
4 files changed, 58 insertions, 14 deletions
diff --git a/backends/plugins/elf/arm-loader.cpp b/backends/plugins/elf/arm-loader.cpp index 3aabf44452..3bbb5b2ee5 100644 --- a/backends/plugins/elf/arm-loader.cpp +++ b/backends/plugins/elf/arm-loader.cpp @@ -65,6 +65,7 @@ bool ARMDLObject::relocate(Elf32_Off offset, Elf32_Word size, byte *relSegment) // Act differently based on the type of relocation switch (REL_TYPE(rel[i].r_info)) { case R_ARM_ABS32: + case R_ARM_TARGET1: if (sym->st_shndx < SHN_LOPROC) { // Only shift for plugin section. a = *target; // Get full 32 bits of addend relocation = a + Elf32_Addr(_segment); // Shift by main offset @@ -80,13 +81,36 @@ bool ARMDLObject::relocate(Elf32_Off offset, Elf32_Word size, byte *relSegment) 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; + if (sym->st_shndx == SHN_ABS) { // Absolute symbols used in PC-relative instructions need to be relocated + // Extract the PC offset from the instruction + int32 pcOffset = *target; + pcOffset = (pcOffset & 0x00ffffff) << 2; + + if (pcOffset & 0x02000000) + pcOffset -= 0x04000000; + + // Shift by the segment offset + pcOffset -= Elf32_Addr(_segment); + // Check the relocated offset is valid for the instruction + if (pcOffset <= (int32)0xfe000000 || + pcOffset >= (int32)0x02000000) { + warning("elfloader: R_ARM_CALL/R_ARM_JUMP24: Out of range relocation i=%d, target=%p, pcOffset=%d", i, target, pcOffset); + free(rel); + return false; + } + + // Put the relocated offset back in the instruction + pcOffset >>= 2; + pcOffset &= 0x00ffffff; + + *target &= (uint32)0xff000000; + *target |= (uint32)pcOffset; + + debug(8, "elfloader: R_ARM_CALL/R_ARM_JUMP24: i=%d, origTarget=%x, target=%x", i, origTarget, *target); + } + break; case R_ARM_V4BX: debug(8, "elfloader: R_ARM_V4BX: No relocation calculation necessary."); break; diff --git a/backends/plugins/elf/elf-loader.cpp b/backends/plugins/elf/elf-loader.cpp index 5198fa8088..39f1f7dfa5 100644 --- a/backends/plugins/elf/elf-loader.cpp +++ b/backends/plugins/elf/elf-loader.cpp @@ -50,8 +50,7 @@ DLObject::DLObject() : DLObject::~DLObject() { discardSymtab(); - ELFMemMan.pluginDeallocate(_segment); - _segment = 0; + discardSegment(); } // Expel the symbol table from memory @@ -65,11 +64,12 @@ void DLObject::discardSymtab() { _symbol_cnt = 0; } -// Unload all objects from memory -void DLObject::unload() { - discardSymtab(); - - ELFMemMan.pluginDeallocate(_segment); +void DLObject::discardSegment() { + if (_segment) { + // Restore default protection before returning memory + protectMemory(_segment, _segmentSize, PF_R | PF_W); + deallocateMemory(_segment, _segmentSize); + } _segment = 0; _segmentSize = 0; @@ -77,6 +77,12 @@ void DLObject::unload() { _segmentVMA = 0; } +// Unload all objects from memory +void DLObject::unload() { + discardSymtab(); + discardSegment(); +} + bool DLObject::readElfHeader(Elf32_Ehdr *ehdr) { assert(_file); @@ -163,7 +169,7 @@ bool DLObject::readProgramHeaders(Elf32_Ehdr *ehdr, Elf32_Phdr *phdr, Elf32_Half } bool DLObject::loadSegment(Elf32_Phdr *phdr) { - _segment = (byte *)ELFMemMan.pluginAllocate(phdr->p_align, phdr->p_memsz); + _segment = (byte *)allocateMemory(phdr->p_align, phdr->p_memsz); if (!_segment) { warning("elfloader: Out of memory."); @@ -402,6 +408,8 @@ bool DLObject::load() { return false; } + protectMemory(_segment, _segmentSize, phdr.p_flags); + return true; } @@ -488,4 +496,12 @@ void *DLObject::symbol(const char *name) { return 0; } +void *DLObject::allocateMemory(uint32 align, uint32 size) { + return ELFMemMan.pluginAllocate(align, size); +} + +void DLObject::deallocateMemory(void *ptr, uint32 size) { + ELFMemMan.pluginDeallocate(ptr); +} + #endif /* defined(DYNAMIC_MODULES) && defined(USE_ELF_LOADER) */ diff --git a/backends/plugins/elf/elf-loader.h b/backends/plugins/elf/elf-loader.h index 17ca35482a..1730338807 100644 --- a/backends/plugins/elf/elf-loader.h +++ b/backends/plugins/elf/elf-loader.h @@ -68,6 +68,7 @@ protected: int loadSymbolTable(Elf32_Ehdr *ehdr, Elf32_Shdr *shdr); bool loadStringTable(Elf32_Shdr *shdr); virtual void relocateSymbols(ptrdiff_t offset); + void discardSegment(); // architecture specific @@ -83,6 +84,9 @@ protected: // platform specific virtual void flushDataCache(void *ptr, uint32 len) const = 0; + virtual void *allocateMemory(uint32 align, uint32 size); + virtual void deallocateMemory(void *ptr, uint32 size); + virtual void protectMemory(void *ptr, uint32 len, int prot) const {}; public: DLObject(); diff --git a/backends/plugins/elf/mips-loader.cpp b/backends/plugins/elf/mips-loader.cpp index 47ae00a8ea..e1e62234d5 100644 --- a/backends/plugins/elf/mips-loader.cpp +++ b/backends/plugins/elf/mips-loader.cpp @@ -279,7 +279,7 @@ bool MIPSDLObject::loadSegment(Elf32_Phdr *phdr) { // We need to take account of non-allocated segment for shorts if (phdr->p_flags & PF_X) { // This is a relocated segment // Attempt to allocate memory for segment - _segment = (byte *)ELFMemMan.pluginAllocate(phdr->p_align, phdr->p_memsz); + _segment = (byte *)allocateMemory(phdr->p_align, phdr->p_memsz); if (!_segment) { warning("elfloader: Out of memory."); |