diff options
Diffstat (limited to 'backends/dc/dcloader.cpp')
-rw-r--r-- | backends/dc/dcloader.cpp | 441 |
1 files changed, 0 insertions, 441 deletions
diff --git a/backends/dc/dcloader.cpp b/backends/dc/dcloader.cpp deleted file mode 100644 index 2ce853c061..0000000000 --- a/backends/dc/dcloader.cpp +++ /dev/null @@ -1,441 +0,0 @@ -/* ScummVM - Scumm Interpreter - * Dreamcast port - * Copyright (C) 2002-2004 Marcus Comstedt - * - * 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$ - * - */ - -#include <common/stdafx.h> -#include <ronin/ronin.h> -#include <string.h> -#include <stdarg.h> - -#include "dcloader.h" - -#ifdef DL_DEBUG -#define DBG(...) reportf(__VA_ARGS__) -#else -#define DBG(...) 0 -#endif - - -/* ELF stuff */ - -typedef unsigned short Elf32_Half, Elf32_Section; -typedef unsigned long Elf32_Word, Elf32_Addr, Elf32_Off; -typedef signed long Elf32_Sword; -typedef Elf32_Half Elf32_Versym; - -#define EI_NIDENT (16) -#define ELFMAG "\177ELF\1\1" -#define SELFMAG 6 - -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; - -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; - -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; - -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; - -typedef struct -{ - Elf32_Addr r_offset; /* Address */ - Elf32_Word r_info; /* Relocation type and symbol index */ - Elf32_Sword r_addend; /* Addend */ -} Elf32_Rela; - - - -extern "C" void flush_instruction_cache(); - -static void purge_copyback() -{ - int i; - for(i=0; i!=(1<<14); i+=(1<<5)) - *(volatile unsigned int *)(0xf4000000+i) &= ~3; -} - - -void DLObject::seterror(const char *fmt, ...) -{ - if(errbuf) { - va_list va; - va_start(va, fmt); - vsnprintf(errbuf, MAXDLERRLEN, fmt, va); - va_end(va); - } -} - -void DLObject::discard_symtab() -{ - free(symtab); - free(strtab); - symtab = NULL; - strtab = NULL; - symbol_cnt = 0; -} - -void DLObject::unload() -{ - discard_symtab(); - free(segment); - segment = NULL; -} - -bool DLObject::relocate(int fd, unsigned long offset, unsigned long size) -{ - Elf32_Rela *rela; - - if(!(rela = (Elf32_Rela *)malloc(size))) { - seterror("Out of memory."); - return false; - } - - if(lseek(fd, offset, SEEK_SET)<0 || - read(fd, rela, size) != size) { - seterror("Relocation table load failed."); - free(rela); - return false; - } - - int cnt = size / sizeof(*rela); - for(int i=0; i<cnt; i++) { - - Elf32_Sym *sym = (Elf32_Sym *)(((char *)symtab)+(rela[i].r_info>>4)); - - void *target = ((char *)segment)+rela[i].r_offset; - - switch(rela[i].r_info & 0xf) { - case 1: /* DIR32 */ - if(sym->st_shndx < 0xff00) - *(unsigned long *)target += (unsigned long)segment; - break; - default: - seterror("Unknown relocation type %d.", rela[i].r_info & 0xf); - free(rela); - return false; - } - - } - - free(rela); - return true; -} - - -bool DLObject::load(int fd) -{ - Elf32_Ehdr ehdr; - Elf32_Phdr phdr; - Elf32_Shdr *shdr; - int symtab_sect = -1; - - if(read(fd, &ehdr, sizeof(ehdr)) != sizeof(ehdr) || - memcmp(ehdr.e_ident, ELFMAG, SELFMAG) || - ehdr.e_type != 2 || ehdr.e_machine != 42 || - ehdr.e_phentsize < sizeof(phdr) || ehdr.e_shentsize != sizeof(*shdr) || - ehdr.e_phnum != 1) { - seterror("Invalid file type."); - return false; - } - - DBG("phoff = %d, phentsz = %d, phnum = %d\n", - ehdr.e_phoff, ehdr.e_phentsize, ehdr.e_phnum); - - if(lseek(fd, ehdr.e_phoff, SEEK_SET)<0 || - read(fd, &phdr, sizeof(phdr)) != sizeof(phdr)) { - seterror("Program header load failed."); - return false; - } - - if(phdr.p_type != 1 || phdr.p_vaddr != 0 || phdr.p_paddr != 0 || - phdr.p_filesz > phdr.p_memsz) { - seterror("Invalid program header."); - return false; - } - - DBG("offs = %d, filesz = %d, memsz = %d, align = %d\n", - phdr.p_offset, phdr.p_filesz, phdr.p_memsz, phdr.p_align); - - if(!(segment = memalign(phdr.p_align, phdr.p_memsz))) { - seterror("Out of memory."); - return false; - } - - DBG("segment @ %p\n", segment); - - if(phdr.p_memsz > phdr.p_filesz) - memset(((char *)segment) + phdr.p_filesz, 0, phdr.p_memsz - phdr.p_filesz); - - if(lseek(fd, phdr.p_offset, SEEK_SET)<0 || - read(fd, segment, phdr.p_filesz) != phdr.p_filesz) { - seterror("Segment load failed."); - return false; - } - - DBG("shoff = %d, shentsz = %d, shnum = %d\n", - ehdr.e_shoff, ehdr.e_shentsize, ehdr.e_shnum); - - if(!(shdr = (Elf32_Shdr *)malloc(ehdr.e_shnum * sizeof(*shdr)))) { - seterror("Out of memory."); - return false; - } - - if(lseek(fd, ehdr.e_shoff, SEEK_SET)<0 || - read(fd, shdr, ehdr.e_shnum * sizeof(*shdr)) != - ehdr.e_shnum * sizeof(*shdr)) { - seterror("Section headers load failed."); - free(shdr); - return false; - } - - for(int i=0; i<ehdr.e_shnum; i++) { - DBG("Section %d: type = %d, size = %d, entsize = %d, link = %d\n", - i, shdr[i].sh_type, shdr[i].sh_size, shdr[i].sh_entsize, shdr[i].sh_link); - if(shdr[i].sh_type == 2 && shdr[i].sh_entsize == sizeof(Elf32_Sym) && - shdr[i].sh_link < ehdr.e_shnum && shdr[shdr[i].sh_link].sh_type == 3 && - symtab_sect < 0) - symtab_sect = i; - } - - if(symtab_sect < 0) { - seterror("No symbol table."); - free(shdr); - return false; - } - - if(!(symtab = malloc(shdr[symtab_sect].sh_size))) { - seterror("Out of memory."); - free(shdr); - return false; - } - - if(lseek(fd, shdr[symtab_sect].sh_offset, SEEK_SET)<0 || - read(fd, symtab, shdr[symtab_sect].sh_size) != shdr[symtab_sect].sh_size){ - seterror("Symbol table load failed."); - free(shdr); - return false; - } - - if(!(strtab = (char *)malloc(shdr[shdr[symtab_sect].sh_link].sh_size))) { - seterror("Out of memory."); - free(shdr); - return false; - } - - if(lseek(fd, shdr[shdr[symtab_sect].sh_link].sh_offset, SEEK_SET)<0 || - read(fd, strtab, shdr[shdr[symtab_sect].sh_link].sh_size) != - shdr[shdr[symtab_sect].sh_link].sh_size){ - seterror("Symbol table strings load failed."); - free(shdr); - return false; - } - - symbol_cnt = shdr[symtab_sect].sh_size / sizeof(Elf32_Sym); - DBG("Loaded %d symbols.\n", symbol_cnt); - - Elf32_Sym *s = (Elf32_Sym *)symtab; - for(int c = symbol_cnt; c--; s++) - if(s->st_shndx < 0xff00) - s->st_value += (Elf32_Addr)segment; - - for(int i=0; i<ehdr.e_shnum; i++) - if(shdr[i].sh_type == 4 && shdr[i].sh_entsize == sizeof(Elf32_Rela) && - shdr[i].sh_link == symtab_sect && shdr[i].sh_info < ehdr.e_shnum && - (shdr[shdr[i].sh_info].sh_flags & 2)) - if(!relocate(fd, shdr[i].sh_offset, shdr[i].sh_size)) { - free(shdr); - return false; - } - - free(shdr); - - return true; -} - -bool DLObject::open(const char *path) -{ - int fd; - void *ctors_start, *ctors_end; - - DBG("open(\"%s\")\n", path); - - if((fd = ::open(path, O_RDONLY))<0) { - seterror("%s not found.", path); - return false; - } - - if(!load(fd)) { - ::close(fd); - unload(); - return false; - } - - ::close(fd); - - int oldmask = getimask(); - setimask(15); - purge_copyback(); - flush_instruction_cache(); - setimask(oldmask); - - 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 == NULL || ctors_end == NULL || dtors_start == NULL || - dtors_end == NULL) { - seterror("Missing ctors/dtors."); - dtors_start = dtors_end = NULL; - unload(); - return false; - } - - DBG("Calling constructors.\n"); - for(void (**f)(void) = (void (**)(void))ctors_start; f != ctors_end; f++) - (**f)(); - - DBG("%s opened ok.\n", path); - return true; -} - -bool DLObject::close() -{ - if(dtors_start != NULL && dtors_end != NULL) - for(void (**f)(void) = (void (**)(void))dtors_start; f != dtors_end; f++) - (**f)(); - dtors_start = dtors_end = NULL; - unload(); - return true; -} - -void *DLObject::symbol(const char *name) -{ - DBG("symbol(\"%s\")\n", name); - - if(symtab == NULL || strtab == NULL || symbol_cnt < 1) { - seterror("No symbol table loaded."); - return NULL; - } - - Elf32_Sym *s = (Elf32_Sym *)symtab; - for(int c = symbol_cnt; c--; s++) - if((s->st_info>>4 == 1 || s->st_info>>4 == 2) && - strtab[s->st_name] == '_' && !strcmp(name, strtab+s->st_name+1)) { - DBG("=> %p\n", (void*)s->st_value); - return (void*)s->st_value; - } - - seterror("Symbol \"%s\" not found.", name); - return NULL; -} - - -static char dlerr[MAXDLERRLEN]; - -void *dlopen(const char *filename, int flags) -{ - DLObject *obj = new DLObject(dlerr); - if(obj->open(filename)) - return (void *)obj; - delete obj; - return NULL; -} - -int dlclose(void *handle) -{ - DLObject *obj = (DLObject *)handle; - if(obj == NULL) { - strcpy(dlerr, "Handle is NULL."); - return -1; - } - if(obj->close()) { - delete obj; - return 0; - } - return -1; -} - -void *dlsym(void *handle, const char *symbol) -{ - if(handle == NULL) { - strcpy(dlerr, "Handle is NULL."); - return NULL; - } - return ((DLObject *)handle)->symbol(symbol); -} - -const char *dlerror() -{ - return dlerr; -} - -void dlforgetsyms(void *handle) -{ - if(handle != NULL) - ((DLObject *)handle)->discard_symtab(); -} |