aboutsummaryrefslogtreecommitdiff
path: root/backends/plugins/elf-loader.cpp
diff options
context:
space:
mode:
authorTony Puccinelli2010-07-27 06:27:45 +0000
committerTony Puccinelli2010-07-27 06:27:45 +0000
commit58f3e81f0073f55a892802b562081300345ca23d (patch)
tree0e2bb58497a4bdf74100aeba0ca690b8f0b1d204 /backends/plugins/elf-loader.cpp
parent4e530debd2b2cb79078b705792fc599d328d6c7c (diff)
downloadscummvm-rg350-58f3e81f0073f55a892802b562081300345ca23d.tar.gz
scummvm-rg350-58f3e81f0073f55a892802b562081300345ca23d.tar.bz2
scummvm-rg350-58f3e81f0073f55a892802b562081300345ca23d.zip
Continued abstraction of generic ELF-loader, splitting off MIPS-processor specific things into their own files and testing on the PS2
svn-id: r51345
Diffstat (limited to 'backends/plugins/elf-loader.cpp')
-rw-r--r--backends/plugins/elf-loader.cpp110
1 files changed, 58 insertions, 52 deletions
diff --git a/backends/plugins/elf-loader.cpp b/backends/plugins/elf-loader.cpp
index 685d22e28a..eae8bebcc7 100644
--- a/backends/plugins/elf-loader.cpp
+++ b/backends/plugins/elf-loader.cpp
@@ -30,12 +30,11 @@
#include <stdio.h>
#include <malloc.h>
#include <unistd.h>
+#include <sys/fcntl.h>
#include <sys/_default_fcntl.h>
-//#include "backends/fs/stdiostream.h"
-//#include "backends/fs/ds/ds-fs.h"
-#include "dsmain.h"
-
+#include "common/file.h"
+#include "common/fs.h"
#include "elf-loader.h"
#define __DEBUG_PLUGINS__
@@ -61,7 +60,6 @@ void flushDataCache() {
#endif
}
-
// Expel the symbol table from memory
void DLObject::discard_symtab() {
free(_symtab);
@@ -76,18 +74,13 @@ void DLObject::unload() {
discard_symtab();
free(_segment);
_segment = NULL;
-}
-/**
- * Follow the instruction of a relocation section.
- *
- * @param DLFile SeekableReadStream of File
- * @param offset Offset into the File
- * @param size Size of relocation section
- *
- */
-bool DLObject::relocate(Common::SeekableReadStream* DLFile, unsigned long offset, unsigned long size, void *relSegment) {
- dlRelocate(DLFile, offset, size, relSegment);
+#ifdef MIPS_TARGET
+ if (_shortsSegment) {
+ ShortsMan.deleteSegment(_shortsSegment);
+ _shortsSegment = NULL;
+ }
+#endif
}
bool DLObject::readElfHeader(Common::SeekableReadStream* DLFile, Elf32_Ehdr *ehdr) {
@@ -135,6 +128,33 @@ 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);
@@ -149,9 +169,7 @@ 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;
-
- DBG("base address is %p\n", baseAddress);
- DBG("_segmentSize is %p\n", _segmentSize);
+#endif
// Set bss segment to 0 if necessary (assumes bss is at the end)
if (phdr->p_memsz > phdr->p_filesz) {
@@ -260,53 +278,41 @@ bool DLObject::loadStringTable(Common::SeekableReadStream* DLFile, Elf32_Shdr *s
void DLObject::relocateSymbols(Elf32_Addr offset) {
- int relocCount = 0;
- DBG("Relocating symbols by %x\n", 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++) {
+
+#ifdef MIPS_TARGET
// Make sure we don't relocate special valued symbols
if (s->st_shndx < SHN_LOPROC) {
- relocCount++;
+ 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);
-
- }
-
- }
-
- DBG("Relocated %d symbols.\n",relocCount);
-}
-
-bool DLObject::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 || curShdr->sh_type == SHT_RELA) && // Check for a relocation section
- curShdr->sh_entsize == sizeof(Elf32_Rel) && // Check for proper relocation size
- (int)curShdr->sh_link == _symtab_sect && // Check that the sh_link connects to our symbol table
- curShdr->sh_info < ehdr->e_shnum && // Check that the relocated section exists
- (shdr[curShdr->sh_info].sh_flags & SHF_ALLOC)) { // Check if relocated section resides in memory
-
- if (curShdr->sh_type == SHT_RELA) {
- seterror("RELA entries not supported yet!\n");
- return false;
+ } 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);
}
- if (!relocate(DLFile, curShdr->sh_offset, curShdr->sh_size, _segment)) {
- return false;
- }
+ }
+#else
+ // Make sure we don't relocate special valued symbols
+ if (s->st_shndx < SHN_LOPROC) {
+ relocCount++;
+ 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
- return true;
+ }
}
bool DLObject::load(Common::SeekableReadStream* DLFile) {