From 58f3e81f0073f55a892802b562081300345ca23d Mon Sep 17 00:00:00 2001 From: Tony Puccinelli Date: Tue, 27 Jul 2010 06:27:45 +0000 Subject: Continued abstraction of generic ELF-loader, splitting off MIPS-processor specific things into their own files and testing on the PS2 svn-id: r51345 --- backends/platform/ds/arm9/makefile | 4 +- backends/platform/ds/arm9/source/plugin.ld | 218 -------- backends/platform/ds/arm9/source/plugin.syms | 8 - backends/platform/ps2/Makefile.ps2 | 8 +- backends/platform/ps2/plugin.ld | 94 ---- backends/platform/ps2/plugin.syms | 8 - backends/platform/ps2/ps2loader.cpp | 721 --------------------------- backends/platform/ps2/ps2loader.h | 137 ----- backends/platform/psp/Makefile | 4 +- backends/platform/psp/plugin.ld | 239 --------- backends/platform/psp/plugin.syms | 8 - backends/plugins/arm-relocs.cpp | 28 ++ backends/plugins/ds/plugin.ld | 218 ++++++++ backends/plugins/elf-loader.cpp | 110 ++-- backends/plugins/elf-loader.h | 28 +- backends/plugins/mips-loader.h | 43 -- backends/plugins/mips-relocs.cpp | 259 ++++++++++ backends/plugins/plugin.syms | 8 + backends/plugins/ps2/plugin.ld | 94 ++++ backends/plugins/psp/plugin.ld | 239 +++++++++ backends/plugins/shorts-segment-manager.cpp | 13 +- backends/plugins/shorts-segment-manager.h | 3 +- 22 files changed, 948 insertions(+), 1544 deletions(-) delete mode 100644 backends/platform/ds/arm9/source/plugin.ld delete mode 100644 backends/platform/ds/arm9/source/plugin.syms delete mode 100644 backends/platform/ps2/plugin.ld delete mode 100644 backends/platform/ps2/plugin.syms delete mode 100644 backends/platform/ps2/ps2loader.cpp delete mode 100644 backends/platform/ps2/ps2loader.h delete mode 100644 backends/platform/psp/plugin.ld delete mode 100644 backends/platform/psp/plugin.syms create mode 100644 backends/plugins/ds/plugin.ld delete mode 100644 backends/plugins/mips-loader.h create mode 100644 backends/plugins/mips-relocs.cpp create mode 100644 backends/plugins/plugin.syms create mode 100644 backends/plugins/ps2/plugin.ld create mode 100644 backends/plugins/psp/plugin.ld diff --git a/backends/platform/ds/arm9/makefile b/backends/platform/ds/arm9/makefile index 04f7ab9bf3..c5e4fe414c 100644 --- a/backends/platform/ds/arm9/makefile +++ b/backends/platform/ds/arm9/makefile @@ -278,8 +278,8 @@ endif EXECUTABLE = scummvm.elf PLUGIN_PREFIX = PLUGIN_SUFFIX = .plg -PLUGIN_EXTRA_DEPS = $(portdir)/source/plugin.ld $(portdir)/source/plugin.syms $(EXECUTABLE) -PLUGIN_LDFLAGS += -nostartfiles -Wl,-q,--target1-abs,--just-symbols,$(EXECUTABLE),-T$(portdir)/source/plugin.ld,--retain-symbols-file,$(portdir)/source/plugin.syms -lstdc++ -lc -mthumb-interwork -mno-fpu#-Wl,--gc-sections -mno-crt0 $(DEVKITPRO)/devkitARM/arm-eabi/lib/ds_arm9_crt0.o +PLUGIN_EXTRA_DEPS = $(srcdir)/backends/plugins/ds/plugin.ld $(srcdir)/backends/plugins/plugin.syms $(EXECUTABLE) +PLUGIN_LDFLAGS += -nostartfiles -Wl,-q,--target1-abs,--just-symbols,$(EXECUTABLE),-T$(srcdir)/backends/plugins/ds/plugin.ld,--retain-symbols-file,$(srcdir)/backends/plugins/plugin.syms -lstdc++ -lc -mthumb-interwork -mno-fpu#-Wl,--gc-sections -mno-crt0 $(DEVKITPRO)/devkitARM/arm-eabi/lib/ds_arm9_crt0.o MKDIR = mkdir -p RM = rm -f RM_REC = rm -rf diff --git a/backends/platform/ds/arm9/source/plugin.ld b/backends/platform/ds/arm9/source/plugin.ld deleted file mode 100644 index 2b2bca9745..0000000000 --- a/backends/platform/ds/arm9/source/plugin.ld +++ /dev/null @@ -1,218 +0,0 @@ -OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", - "elf32-littlearm") -OUTPUT_ARCH(arm) - -/* PHDRS specifies ELF Program Headers (or segments) to the plugin linker */ -PHDRS { - plugin PT_LOAD ; /* Specifies that the plugin segment should be loaded from file */ -} - -SECTIONS -{ - /* Read-only sections, merged into text segment: */ - . = 0; - .interp : { *(.interp) } : plugin - .note.gnu.build-id : { *(.note.gnu.build-id) } - .hash : { *(.hash) } - .gnu.hash : { *(.gnu.hash) } - .dynsym : { *(.dynsym) } - .dynstr : { *(.dynstr) } - .gnu.version : { *(.gnu.version) } - .gnu.version_d : { *(.gnu.version_d) } - .gnu.version_r : { *(.gnu.version_r) } - .rel.dyn : - { - *(.rel.init) - *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) - *(.rel.fini) - *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) - *(.rel.data.rel.ro* .rel.gnu.linkonce.d.rel.ro.*) - *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*) - *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*) - *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*) - *(.rel.ctors) - *(.rel.dtors) - *(.rel.got) - *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) - PROVIDE_HIDDEN (__rel_iplt_start = .); - *(.rel.iplt) - PROVIDE_HIDDEN (__rel_iplt_end = .); - PROVIDE_HIDDEN (__rela_iplt_start = .); - PROVIDE_HIDDEN (__rela_iplt_end = .); - } - .rela.dyn : - { - *(.rela.init) - *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) - *(.rela.fini) - *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) - *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) - *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) - *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) - *(.rela.ctors) - *(.rela.dtors) - *(.rela.got) - *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) - PROVIDE_HIDDEN (__rel_iplt_start = .); - PROVIDE_HIDDEN (__rel_iplt_end = .); - PROVIDE_HIDDEN (__rela_iplt_start = .); - *(.rela.iplt) - PROVIDE_HIDDEN (__rela_iplt_end = .); - } - .rel.plt : - { - *(.rel.plt) - } - .rela.plt : - { - *(.rela.plt) - } - .init : - { - KEEP (*(.init)) - } =0 - .plt : { *(.plt) } - .iplt : { *(.iplt) } - .text : - { - *(.text.unlikely .text.*_unlikely) - *(.text .stub .text.* .gnu.linkonce.t.*) - /* .gnu.warning sections are handled specially by elf32.em. */ - *(.gnu.warning) - *(.glue_7t) *(.glue_7) *(.vfp11_veneer) *(.v4_bx) - } =0 - .fini : - { - KEEP (*(.fini)) - } =0 - PROVIDE (__etext = .); - PROVIDE (_etext = .); - PROVIDE (etext = .); - .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } - .rodata1 : { *(.rodata1) } - .ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } - __exidx_start = .; - .ARM.exidx : { *(.ARM.exidx* .gnu.linkonce.armexidx.*) } - __exidx_end = .; - .eh_frame_hdr : { *(.eh_frame_hdr) } - .eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) } - .gcc_except_table : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) } - /* Adjust the address for the data segment. We want to adjust up to - the same address within the page on the next page up. */ - . = ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)); - /* Exception handling */ - .eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) } - .gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) } - /* Thread Local Storage sections */ - .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) } - .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } - .preinit_array : - { - PROVIDE_HIDDEN (__preinit_array_start = .); - KEEP (*(.preinit_array)) - PROVIDE_HIDDEN (__preinit_array_end = .); - } - .init_array : - { - PROVIDE_HIDDEN (__init_array_start = .); - KEEP (*(SORT(.init_array.*))) - KEEP (*(.init_array)) - PROVIDE_HIDDEN (__init_array_end = .); - } - .fini_array : - { - PROVIDE_HIDDEN (__fini_array_start = .); - KEEP (*(.fini_array)) - KEEP (*(SORT(.fini_array.*))) - PROVIDE_HIDDEN (__fini_array_end = .); - } - .ctors : - { - ___plugin_ctors = .; - KEEP (*(SORT(.ctors.*))) - KEEP (*(.ctors)) - ___plugin_ctors_end = .; - } - .dtors : - { - ___plugin_dtors = .; - KEEP (*(SORT(.dtors.*))) - KEEP (*(.dtors)) - ___plugin_dtors_end = .; - } - .jcr : { KEEP (*(.jcr)) } - .data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro* .gnu.linkonce.d.rel.ro.*) } - .dynamic : { *(.dynamic) } - .got : { *(.got.plt) *(.igot.plt) *(.got) *(.igot) } - .data : - { - __data_start = . ; - *(.data .data.* .gnu.linkonce.d.*) - SORT(CONSTRUCTORS) - } - .data1 : { *(.data1) } - _edata = .; PROVIDE (edata = .); - __bss_start = .; - __bss_start__ = .; - .bss : - { - *(.dynbss) - *(.bss .bss.* .gnu.linkonce.b.*) - *(COMMON) - /* Align here to ensure that the .bss section occupies space up to - _end. Align after .bss to ensure correct alignment even if the - .bss section disappears because there are no input sections. - FIXME: Why do we need it? When there is no .bss section, we don't - pad the .data section. */ - . = ALIGN(. != 0 ? 32 / 8 : 1); - } - _bss_end__ = . ; __bss_end__ = . ; - . = ALIGN(32 / 8); - . = ALIGN(32 / 8); - __end__ = . ; - _end = .; PROVIDE (end = .); - /* Stabs debugging sections. */ - .stab 0 : { *(.stab) } - .stabstr 0 : { *(.stabstr) } - .stab.excl 0 : { *(.stab.excl) } - .stab.exclstr 0 : { *(.stab.exclstr) } - .stab.index 0 : { *(.stab.index) } - .stab.indexstr 0 : { *(.stab.indexstr) } - .comment 0 : { *(.comment) } - /* DWARF debug sections. - Symbols in the DWARF debugging sections are relative to the beginning - of the section so we begin them at 0. */ - /* DWARF 1 */ - .debug 0 : { *(.debug) } - .line 0 : { *(.line) } - /* GNU DWARF 1 extensions */ - .debug_srcinfo 0 : { *(.debug_srcinfo) } - .debug_sfnames 0 : { *(.debug_sfnames) } - /* DWARF 1.1 and DWARF 2 */ - .debug_aranges 0 : { *(.debug_aranges) } - .debug_pubnames 0 : { *(.debug_pubnames) } - /* DWARF 2 */ - .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } - .debug_abbrev 0 : { *(.debug_abbrev) } - .debug_line 0 : { *(.debug_line) } - .debug_frame 0 : { *(.debug_frame) } - .debug_str 0 : { *(.debug_str) } - .debug_loc 0 : { *(.debug_loc) } - .debug_macinfo 0 : { *(.debug_macinfo) } - /* SGI/MIPS DWARF 2 extensions */ - .debug_weaknames 0 : { *(.debug_weaknames) } - .debug_funcnames 0 : { *(.debug_funcnames) } - .debug_typenames 0 : { *(.debug_typenames) } - .debug_varnames 0 : { *(.debug_varnames) } - /* DWARF 3 */ - .debug_pubtypes 0 : { *(.debug_pubtypes) } - .debug_ranges 0 : { *(.debug_ranges) } - .stack 0x80000 : - { - _stack = .; - *(.stack) - } - .ARM.attributes 0 : { KEEP (*(.ARM.attributes)) KEEP (*(.gnu.attributes)) } - .note.gnu.arm.ident 0 : { KEEP (*(.note.gnu.arm.ident)) } - /DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) } -} diff --git a/backends/platform/ds/arm9/source/plugin.syms b/backends/platform/ds/arm9/source/plugin.syms deleted file mode 100644 index 24ee1a19dc..0000000000 --- a/backends/platform/ds/arm9/source/plugin.syms +++ /dev/null @@ -1,8 +0,0 @@ -PLUGIN_getVersion -PLUGIN_getType -PLUGIN_getTypeVersion -PLUGIN_getObject -___plugin_ctors -___plugin_ctors_end -___plugin_dtors -___plugin_dtors_end diff --git a/backends/platform/ps2/Makefile.ps2 b/backends/platform/ps2/Makefile.ps2 index c2cf30ed23..5c60c4fca0 100644 --- a/backends/platform/ps2/Makefile.ps2 +++ b/backends/platform/ps2/Makefile.ps2 @@ -87,9 +87,9 @@ CXX_UPDATE_DEP_FLAG = -Wp,-MMD,"$(*D)/$(DEPDIR)/$(*F).d",-MQ,"$@",-MP # Variables for dynamic plugin building PLUGIN_PREFIX = PLUGIN_SUFFIX = .plg -PLUGIN_EXTRA_DEPS = plugin.ld plugin.syms elf/scummvm.elf +PLUGIN_EXTRA_DEPS = $(srcdir)/backends/plugins/plugin.syms elf/scummvm.elf PLUGIN_LDFLAGS += -mno-crt0 $(PS2SDK)/ee/startup/crt0.o -PLUGIN_LDFLAGS += -nostartfiles -Wl,-q,--just-symbols,elf/scummvm.elf,-Tplugin.ld,--retain-symbols-file,plugin.syms -lstdc++ -lc +PLUGIN_LDFLAGS += -nostartfiles -Wl,-q,--just-symbols,elf/scummvm.elf,-T$(srcdir)/backends/plugins/ps2/plugin.ld,--retain-symbols-file,$(srcdir)/backends/plugins/plugin.syms -lstdc++ -lc LDFLAGS = -mno-crt0 $(PS2SDK)/ee/startup/crt0.o -T main_prog.ld LDFLAGS += -L $(PS2SDK)/ee/lib -L . @@ -111,7 +111,9 @@ OBJS := $(srcdir)/backends/platform/ps2/DmaPipe.o \ $(srcdir)/backends/platform/ps2/systemps2.o \ $(srcdir)/backends/platform/ps2/ps2mutex.o \ $(srcdir)/backends/platform/ps2/ps2time.o \ - $(srcdir)/backends/platform/ps2/ps2loader.o \ + $(srcdir)/backends/plugins/elf-loader.o \ + $(srcdir)/backends/plugins/mips-relocs.o \ + $(srcdir)/backends/plugins/shorts-segment-manager.o \ $(srcdir)/backends/platform/ps2/ps2debug.o include $(srcdir)/Makefile.common diff --git a/backends/platform/ps2/plugin.ld b/backends/platform/ps2/plugin.ld deleted file mode 100644 index 9879413b98..0000000000 --- a/backends/platform/ps2/plugin.ld +++ /dev/null @@ -1,94 +0,0 @@ -/* PHDRS specifies ELF Program Headers (or segments) to the plugin linker */ -PHDRS { - plugin PT_LOAD ; /* Specifies that the plugin segment should be loaded from file */ - shorts PT_LOAD ; /* Specifies that the shorts segment should be loaded from file */ -} -SECTIONS { - .text 0: { - _ftext = . ; - *(.text) - *(.text.*) - *(.gnu.linkonce.t*) - KEEP(*(.init)) - KEEP(*(.fini)) - QUAD(0) - } : plugin /*The ": plugin" tells the linker to assign this and - the following sections to the "plugin" segment*/ - PROVIDE(_etext = .); - PROVIDE(etext = .); - - .reginfo : { *(.reginfo) } - - /* Global/static constructors and deconstructors. */ - .ctors ALIGN(16): { - ___plugin_ctors = .; - KEEP(*(SORT(.ctors.*))) - KEEP(*(.ctors)) - ___plugin_ctors_end = .; - } - .dtors ALIGN(16): { - ___plugin_dtors = .; - KEEP(*(SORT(.dtors.*))) - KEEP(*(.dtors)) - ___plugin_dtors_end = .; - } - - /* Static data. */ - .rodata ALIGN(128): { - *(.rodata) - *(.rodata.*) - *(.gnu.linkonce.r*) - } - - .data ALIGN(128): { - _fdata = . ; - *(.data) - *(.data.*) - *(.gnu.linkonce.d*) - SORT(CONSTRUCTORS) - } - - .rdata ALIGN(128): { *(.rdata) } - .gcc_except_table ALIGN(128): { *(.gcc_except_table) } - - .bss ALIGN(128) : { - *(.bss) - *(.bss.*) - *(.gnu.linkonce.b*) - *(COMMON) - } - _end_bss = .; - - _end = . ; - PROVIDE(end = .); - - /* Symbols needed by crt0.s. */ - PROVIDE(_heap_size = -1); - PROVIDE(_stack = -1); - PROVIDE(_stack_size = 128 * 1024); - - /*We assign the output location counter to the plugin hole made - in main_prog.ld, then assign the small data sections to the shorts segment*/ - . = __plugin_hole_start; - .lit4 ALIGN(128): { *(.lit4) } : shorts - .lit8 ALIGN(128): { *(.lit8) } - - .sdata ALIGN(128): { - *(.sdata) - *(.sdata.*) - *(.gnu.linkonce.s*) - } - - _edata = .; - PROVIDE(edata = .); - - /* Uninitialized data. */ - .sbss ALIGN(128) : { - _fbss = . ; - *(.sbss) - *(.sbss.*) - *(.gnu.linkonce.sb*) - *(.scommon) - } - -} diff --git a/backends/platform/ps2/plugin.syms b/backends/platform/ps2/plugin.syms deleted file mode 100644 index 24ee1a19dc..0000000000 --- a/backends/platform/ps2/plugin.syms +++ /dev/null @@ -1,8 +0,0 @@ -PLUGIN_getVersion -PLUGIN_getType -PLUGIN_getTypeVersion -PLUGIN_getObject -___plugin_ctors -___plugin_ctors_end -___plugin_dtors -___plugin_dtors_end diff --git a/backends/platform/ps2/ps2loader.cpp b/backends/platform/ps2/ps2loader.cpp deleted file mode 100644 index 0f46b2ad45..0000000000 --- a/backends/platform/ps2/ps2loader.cpp +++ /dev/null @@ -1,721 +0,0 @@ -/* 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(__PLAYSTATION2__) - -#include -#include -#include -#include -#include -#include - -#include "savefilemgr.h" -#include "backends/fs/ps2/ps2-fs-factory.h" - -#include "backends/platform/ps2/ps2loader.h" - -//#define __PS2_DEBUG_PLUGINS__ - -#ifdef __PS2_DEBUG_PLUGINS__ -#define DBG(x,...) printf(x, ## __VA_ARGS__) -#else -#define DBG(x,...) -#endif - -#define seterror(x,...) printf(x, ## __VA_ARGS__) - -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 - -// Get rid of symbol table in memory -void DLObject::discard_symtab() { - free(_symtab); - free(_strtab); - _symtab = NULL; - _strtab = NULL; - _symbol_cnt = 0; -} - -// Unload all objects from memory -void DLObject::unload() { - discard_symtab(); - free(_segment); - _segment = NULL; - - if (_shortsSegment) { - ShortsMan.deleteSegment(_shortsSegment); - _shortsSegment = 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 - * @param relSegment Base address of relocated segment in memory (memory offset) - * - */ -bool DLObject::relocate(Common::SeekableReadStream* DLFile, unsigned long offset, unsigned long size, void *relSegment) { - Elf32_Rel *rel = NULL; // relocation entry - - // Allocate memory for relocation table - if (!(rel = (Elf32_Rel *)malloc(size))) { - seterror("Out of memory."); - return false; - } - - // Read in our relocation table - if (DLFile->seek(offset, SEEK_SET) < 0 || - DLFile->read(rel, size) != (ssize_t)size) { - seterror("Relocation table load failed."); - free(rel); - return false; - } - - // Treat each relocation entry. Loop over all of them - int cnt = size / sizeof(*rel); - - DBG("Loaded relocation table. %d entries. base address=%p\n", 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 - DBG("R_MIPS_HI16: i=%d, offset=%x, ahl = %x, target = %x\n", - 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 - seterror("R_MIPS_LO16 w/o preceding R_MIPS_HI16 at relocation %d!\n", 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) - DBG("R_MIPS_LO16: i=%d, offset=%x, a=%x, ahl = %x, lastTarget = %x, origt = %x, target = %x\n", - i, rel[i].r_offset, a, ahl, *lastTarget, origTarget, *target); - if (lo16InShorts && debugRelocs[2]++ < DEBUG_NUM) - DBG("R_MIPS_LO16s: i=%d, offset=%x, a=%x, ahl = %x, lastTarget = %x, origt = %x, target = %x\n", - 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) - DBG("R_MIPS_26: i=%d, offset=%x, symbol=%d, stinfo=%x, a=%x, origTarget=%x, target=%x\n", - i, rel[i].r_offset, REL_INDEX(rel[i].r_info), sym->st_info, a, origTarget, *target); - } else { - if (debugRelocs[4]++ < DEBUG_NUM) - DBG("R_MIPS_26: i=%d, offset=%x, symbol=%d, stinfo=%x, a=%x, origTarget=%x, target=%x\n", - 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) - DBG("R_MIPS_GPREL16: i=%d, a=%x, gpVal=%x, origTarget=%x, target=%x, offset=%x\n", - 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) - DBG("R_MIPS_32: i=%d, a=%x, origTarget=%x, target=%x\n", i, a, origTarget, *target); - } - break; - - default: - seterror("Unknown relocation type %x at relocation %d.\n", REL_TYPE(rel[i].r_info), i); - free(rel); - return false; - } - } - - DBG("Done with relocation. extendedHi16=%d\n\n", extendedHi16); - - free(rel); - return true; -} - -bool DLObject::readElfHeader(Common::SeekableReadStream* DLFile, Elf32_Ehdr *ehdr) { - // Start reading the elf header. Check for errors - if (DLFile->read(ehdr, sizeof(*ehdr)) != sizeof(*ehdr) || - memcmp(ehdr->e_ident, ELFMAG, SELFMAG) || // Check MAGIC - ehdr->e_type != ET_EXEC || // Check for executable - ehdr->e_machine != EM_MIPS || // Check for MIPS machine type - ehdr->e_phentsize < sizeof(Elf32_Phdr) || // Check for size of program header - ehdr->e_shentsize != sizeof(Elf32_Shdr)) { // Check for size of section header - seterror("Invalid file type."); - return false; - } - - DBG("phoff = %d, phentsz = %d, phnum = %d\n", - 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) < 0 || - DLFile->read(phdr, sizeof(*phdr)) != sizeof(*phdr)) { - seterror("Program header load failed."); - return false; - } - - // Check program header values - if (phdr->p_type != PT_LOAD || phdr->p_filesz > phdr->p_memsz) { - seterror("Invalid program header."); - return false; - } - - DBG("offs = %x, filesz = %x, memsz = %x, align = %x\n", - 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; - - // 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); - } - // 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; - } - - return true; -} - - -Elf32_Shdr * DLObject::loadSectionHeaders(Common::SeekableReadStream* DLFile, Elf32_Ehdr *ehdr) { - - Elf32_Shdr *shdr = NULL; - - // Allocate memory for section headers - if (!(shdr = (Elf32_Shdr *)malloc(ehdr->e_shnum * sizeof(*shdr)))) { - seterror("Out of memory."); - return NULL; - } - - // Read from file into section headers - if (DLFile->seek(ehdr->e_shoff, SEEK_SET) < 0 || - DLFile->read(shdr, ehdr->e_shnum * sizeof(*shdr)) != - (ssize_t)(ehdr->e_shnum * sizeof(*shdr))) { - seterror("Section headers load failed."); - return NULL; - } - - 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++) { - DBG("Section %d: type = %x, size = %x, entsize = %x, link = %x\n", - i, shdr[i].sh_type, shdr[i].sh_size, shdr[i].sh_entsize, shdr[i].sh_link); - - 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) { - seterror("No symbol table."); - return -1; - } - - DBG("Symbol section at section %d, size %x\n", _symtab_sect, shdr[_symtab_sect].sh_size); - - // Allocate memory for symbol table - if (!(_symtab = malloc(shdr[_symtab_sect].sh_size))) { - seterror("Out of memory."); - return -1; - } - - // Read symbol table into memory - if (DLFile->seek(shdr[_symtab_sect].sh_offset, SEEK_SET) < 0 || - DLFile->read(_symtab, shdr[_symtab_sect].sh_size) != - (ssize_t)shdr[_symtab_sect].sh_size) { - seterror("Symbol table load failed."); - return -1; - } - - // Set number of symbols - _symbol_cnt = shdr[_symtab_sect].sh_size / sizeof(Elf32_Sym); - DBG("Loaded %d symbols.\n", _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))) { - seterror("Out of memory."); - return false; - } - - // Read string table into memory - if (DLFile->seek(shdr[string_sect].sh_offset, SEEK_SET) < 0 || - DLFile->read(_strtab, shdr[string_sect].sh_size) != - (ssize_t)shdr[string_sect].sh_size) { - seterror("Symbol table strings load failed."); - return false; - } - return true; -} - -void DLObject::relocateSymbols(Elf32_Addr offset, Elf32_Addr shortsOffset) { - - int shortsCount = 0, othersCount = 0; - DBG("Relocating symbols by %x. Shorts offset=%x\n", offset, shortsOffset); - - // 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)) { - othersCount++; - 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 += shortsOffset; - if (!_shortsSegment->inSegment((char *)s->st_value)) - seterror("Symbol out of bounds! st_value = %x\n", s->st_value); - } - - } - - } - - DBG("Relocated %d short symbols, %d others.\n", shortsCount, othersCount); -} - -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 && // 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; -} - - -bool DLObject::load(Common::SeekableReadStream* DLFile) { - fprintf(stderr, "In DLObject::load\n"); - - Elf32_Ehdr ehdr; // ELF header - Elf32_Phdr phdr; // Program header - Elf32_Shdr *shdr; // Section header - bool ret = true; - - if (readElfHeader(DLFile, &ehdr) == false) { - return false; - } - - for (int i = 0; i < ehdr.e_phnum; i++) { // Load our 2 segments - - fprintf(stderr, "Loading segment %d\n", i); - - if (readProgramHeaders(DLFile, &ehdr, &phdr, i) == false) - return false; - - if (!loadSegment(DLFile, &phdr)) - return false; - } - - if ((shdr = loadSectionHeaders(DLFile, &ehdr)) == NULL) - ret = false; - - if (ret && ((_symtab_sect = loadSymbolTable(DLFile, &ehdr, shdr)) < 0)) - ret = false; - - if (ret && (loadStringTable(DLFile, shdr) == false)) - ret = false; - - if (ret) - relocateSymbols((Elf32_Addr)_segment, _shortsSegment->getOffset()); // Offset by our segment allocated address - - 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; - - DBG("open(\"%s\")\n", path); - - // Get the address of the global pointer - _gpVal = (unsigned int) & _gp; - DBG("_gpVal is %x\n", _gpVal); - - Common::FSNode file(path); - - if (!(DLFile = file.createReadStream())) { - seterror("%s not found.", path); - return false; - } - - // Try to load and relocate - if (!load(DLFile)) { - //::close(fd); - unload(); - return false; - } - - //::close(fd); - - // flush data cache - DBG("Flushing data cache"); - FlushCache(0); - FlushCache(2); - - // Get the symbols for the global constructors and destructors - 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++) { - - // 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) && - /*_strtab[s->st_name] == '_' && */ // Try to make this more efficient - !strcmp(name, _strtab + s->st_name)) { - - // We found the symbol - DBG("=> %p\n", (void*)s->st_value); - return (void*)s->st_value; - } - } - - seterror("Symbol \"%s\" not found.", name); - return NULL; -} - - - -ShortSegmentManager::ShortSegmentManager() { - _shortsStart = &__plugin_hole_start ; - _shortsEnd = &__plugin_hole_end; -} - -ShortSegmentManager::Segment *ShortSegmentManager::newSegment(int size, char *origAddr) { - char *lastAddress = origAddr; - Common::List::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) { - seterror("Error. No space in shorts segment for %x bytes. Last address is %p, max address is %p.\n", - size, lastAddress, _shortsEnd); - return NULL; - } - - 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); - - DBG("Shorts segment size %x allocated. End = %p. Remaining space = %x. Highest so far is %p.\n", - size, lastAddress + size, _shortsEnd - _list.back()->getEnd(), _highestAddress); - - return seg; -} - -void ShortSegmentManager::deleteSegment(ShortSegmentManager::Segment *seg) { - DBG("Deleting shorts segment from %p to %p.\n\n", seg->getStart(), seg->getEnd()); - _list.remove(seg); - delete seg; -} - -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(); -} - - -#endif /* DYNAMIC_MODULES && __PLAYSTATION2__ */ diff --git a/backends/platform/ps2/ps2loader.h b/backends/platform/ps2/ps2loader.h deleted file mode 100644 index cfaf4e4f55..0000000000 --- a/backends/platform/ps2/ps2loader.h +++ /dev/null @@ -1,137 +0,0 @@ -/* 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 PS2LOADER_H -#define PS2LOADER_H - -#include "elf32.h" -#include "common/list.h" -#include "common/singleton.h" - -#define MAXDLERRLEN 80 - -#define ShortsMan ShortSegmentManager::instance() - -class ShortSegmentManager : public Common::Singleton { -private: - char *_shortsStart; - char *_shortsEnd; - -public: - char *getShortsStart() { - return _shortsStart; - } - 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; - Common::List _list; - char *_highestAddress; -}; - - - - -class DLObject { -protected: - char *_errbuf; /* For error messages, at least MAXDLERRLEN in size */ - - ShortSegmentManager::Segment *_shortsSegment; // For assigning shorts ranges - void *_segment, *_symtab; - char *_strtab; - int _symbol_cnt; - int _symtab_sect; - void *_dtors_start, *_dtors_end; - - unsigned int _gpVal; // Value of Global Pointer - int _segmentSize; - - void seterror(const char *fmt, ...); - void unload(); - bool relocate(Common::SeekableReadStream*, unsigned long offset, unsigned long size, void *); - bool load(Common::SeekableReadStream*); - - bool readElfHeader(Common::SeekableReadStream*, Elf32_Ehdr *ehdr); - bool readProgramHeaders(Common::SeekableReadStream*, Elf32_Ehdr *ehdr, Elf32_Phdr *phdr, int num); - bool loadSegment(Common::SeekableReadStream*, Elf32_Phdr *phdr); - Elf32_Shdr *loadSectionHeaders(Common::SeekableReadStream*, Elf32_Ehdr *ehdr); - int loadSymbolTable(Common::SeekableReadStream*, Elf32_Ehdr *ehdr, Elf32_Shdr *shdr); - bool loadStringTable(Common::SeekableReadStream*, Elf32_Shdr *shdr); - void relocateSymbols(Elf32_Addr offset, Elf32_Addr shortsOffset); - bool relocateRels(Common::SeekableReadStream*, Elf32_Ehdr *ehdr, Elf32_Shdr *shdr); - -public: - bool open(const char *path); - bool close(); - void *symbol(const char *name); - void discard_symtab(); - - DLObject(char *errbuf = NULL) : _errbuf(_errbuf), _shortsSegment(NULL), _segment(NULL), _symtab(NULL), - _strtab(NULL), _symbol_cnt(0), _symtab_sect(-1), _dtors_start(NULL), _dtors_end(NULL), _gpVal(0) , - _segmentSize(0) {} -}; - - - -#define RTLD_LAZY 0 - -extern "C" { - void *dlopen(const char *filename, int flags); - int dlclose(void *handle); - void *dlsym(void *handle, const char *symbol); - const char *dlerror(); - void dlforgetsyms(void *handle); -} - -#endif /* PS2LOADER_H */ diff --git a/backends/platform/psp/Makefile b/backends/platform/psp/Makefile index 8e83563d10..c479244551 100644 --- a/backends/platform/psp/Makefile +++ b/backends/platform/psp/Makefile @@ -88,8 +88,8 @@ CXX_UPDATE_DEP_FLAG = -Wp,-MMD,"$(*D)/$(DEPDIR)/$(*F).d",-MQ,"$@",-MP # Variables for dynamic plugin building PLUGIN_PREFIX = PLUGIN_SUFFIX = .plg -PLUGIN_EXTRA_DEPS = plugin.syms scummvm-psp.elf -PLUGIN_LDFLAGS = -nostartfiles -Wl,-q,--just-symbols=scummvm-psp.org.elf,-Tplugin.ld,--retain-symbols-file,plugin.syms -lstdc++ -lc +PLUGIN_EXTRA_DEPS = $(srcdir)/backends/plugins/plugin.syms scummvm-psp.elf +PLUGIN_LDFLAGS = -nostartfiles -Wl,-q,--just-symbols=scummvm-psp.org.elf,-T$(srcdir)/backends/plugins/psp/plugin.ld,--retain-symbols-file,$(srcdir)/backends/plugins/plugin.syms -lstdc++ -lc # PSP-specific variables STRIP = psp-strip diff --git a/backends/platform/psp/plugin.ld b/backends/platform/psp/plugin.ld deleted file mode 100644 index db4df45264..0000000000 --- a/backends/platform/psp/plugin.ld +++ /dev/null @@ -1,239 +0,0 @@ -OUTPUT_FORMAT("elf32-littlemips", "elf32-bigmips", - "elf32-littlemips") -OUTPUT_ARCH(mips:allegrex) -PHDRS -{ - plugin PT_LOAD ; - shorts PT_LOAD ; -} -/* Do we need any of these for elf? - __DYNAMIC = 0; */ -SECTIONS -{ - /* Read-only sections, merged into text segment: */ - . = 0; - .interp : { *(.interp) } : plugin - .reginfo : { *(.reginfo) } : plugin - .dynamic : { *(.dynamic) } - .hash : { *(.hash) } - .dynsym : { *(.dynsym) } - .dynstr : { *(.dynstr) } - .gnu.version : { *(.gnu.version) } - .gnu.version_d : { *(.gnu.version_d) } - .gnu.version_r : { *(.gnu.version_r) } - .rel.init : { *(.rel.init) } - .rela.init : { *(.rela.init) } - .rel.text : { *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) } - .rela.text : { *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) } - .rel.fini : { *(.rel.fini) } - .rela.fini : { *(.rela.fini) } - /* PSP-specific relocations. */ - .rel.sceStub.text : { *(.rel.sceStub.text) *(SORT(.rel.sceStub.text.*)) } - .rel.lib.ent.top : { *(.rel.lib.ent.top) } - .rel.lib.ent : { *(.rel.lib.ent) } - .rel.lib.ent.btm : { *(.rel.lib.ent.btm) } - .rel.lib.stub.top : { *(.rel.lib.stub.top) } - .rel.lib.stub : { *(.rel.lib.stub) } - .rel.lib.stub.btm : { *(.rel.lib.stub.btm) } - .rel.rodata.sceModuleInfo : { *(.rel.rodata.sceModuleInfo) } - .rel.rodata.sceResident : { *(.rel.rodata.sceResident) } - .rel.rodata.sceNid : { *(.rel.rodata.sceNid) } - .rel.rodata.sceVstub : { *(.rel.rodata.sceVstub) *(SORT(.rel.rodata.sceVstub.*)) } - .rel.rodata : { *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) } - .rela.rodata : { *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) } - .rel.data.rel.ro : { *(.rel.data.rel.ro*) } - .rela.data.rel.ro : { *(.rel.data.rel.ro*) } - .rel.data : { *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*) } - .rela.data : { *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) } - .rel.tdata : { *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*) } - .rela.tdata : { *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) } - .rel.tbss : { *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*) } - .rela.tbss : { *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) } - .rel.ctors : { *(.rel.ctors) } - .rela.ctors : { *(.rela.ctors) } - .rel.dtors : { *(.rel.dtors) } - .rela.dtors : { *(.rela.dtors) } - .rel.got : { *(.rel.got) } - .rela.got : { *(.rela.got) } - .rel.sdata : { *(.rel.sdata .rel.sdata.* .rel.gnu.linkonce.s.*) } - .rela.sdata : { *(.rela.sdata .rela.sdata.* .rela.gnu.linkonce.s.*) } - .rel.sbss : { *(.rel.sbss .rel.sbss.* .rel.gnu.linkonce.sb.*) } - .rela.sbss : { *(.rela.sbss .rela.sbss.* .rela.gnu.linkonce.sb.*) } - .rel.sdata2 : { *(.rel.sdata2 .rel.sdata2.* .rel.gnu.linkonce.s2.*) } - .rela.sdata2 : { *(.rela.sdata2 .rela.sdata2.* .rela.gnu.linkonce.s2.*) } - .rel.sbss2 : { *(.rel.sbss2 .rel.sbss2.* .rel.gnu.linkonce.sb2.*) } - .rela.sbss2 : { *(.rela.sbss2 .rela.sbss2.* .rela.gnu.linkonce.sb2.*) } - .rel.bss : { *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) } - .rela.bss : { *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) } - .rel.plt : { *(.rel.plt) } - .rela.plt : { *(.rela.plt) } - .init : - { - KEEP (*(.init)) - } =0 - .plt : { *(.plt) } - .text : - { - _ftext = . ; - *(.text .stub .text.* .gnu.linkonce.t.*) - KEEP (*(.text.*personality*)) - /* .gnu.warning sections are handled specially by elf32.em. */ - *(.gnu.warning) - *(.mips16.fn.*) *(.mips16.call.*) - } =0 - .fini : - { - KEEP (*(.fini)) - } =0 - /* PSP library stub functions. */ - .sceStub.text : { *(.sceStub.text) *(SORT(.sceStub.text.*)) } - PROVIDE (__etext = .); - PROVIDE (_etext = .); - PROVIDE (etext = .); - /* PSP library entry table and library stub table. */ - .lib.ent.top : { *(.lib.ent.top) } - .lib.ent : { *(.lib.ent) } - .lib.ent.btm : { *(.lib.ent.btm) } - .lib.stub.top : { *(.lib.stub.top) } - .lib.stub : { *(.lib.stub) } - .lib.stub.btm : { *(.lib.stub.btm) } - /* PSP read-only data for module info, NIDs, and Vstubs. The - .rodata.sceModuleInfo section must appear before the .rodata section - otherwise it would get absorbed into .rodata and the PSP bootloader - would be unable to locate the module info structure. */ - .rodata.sceModuleInfo : { *(.rodata.sceModuleInfo) } - .rodata.sceResident : { *(.rodata.sceResident) } - .rodata.sceNid : { *(.rodata.sceNid) } - .rodata.sceVstub : { *(.rodata.sceVstub) *(SORT(.rodata.sceVstub.*)) } - .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } - .rodata1 : { *(.rodata1) } - .sdata2 : { *(.sdata2 .sdata2.* .gnu.linkonce.s2.*) } - .sbss2 : { *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) } - .eh_frame_hdr : { *(.eh_frame_hdr) } - .eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) } - .gcc_except_table : ONLY_IF_RO { KEEP (*(.gcc_except_table)) *(.gcc_except_table.*) } - /* Adjust the address for the data segment. We want to adjust up to - the same address within the page on the next page up. */ - . = ALIGN(256) + (. & (256 - 1)); - /* Exception handling */ - .eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) } - .gcc_except_table : ONLY_IF_RW { KEEP (*(.gcc_except_table)) *(.gcc_except_table.*) } - /* Thread Local Storage sections */ - .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) } - .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } - /* Ensure the __preinit_array_start label is properly aligned. We - could instead move the label definition inside the section, but - the linker would then create the section even if it turns out to - be empty, which isn't pretty. */ - . = ALIGN(32 / 8); - PROVIDE (__preinit_array_start = .); - .preinit_array : { KEEP (*(.preinit_array)) } - PROVIDE (__preinit_array_end = .); - PROVIDE (__init_array_start = .); - .init_array : { KEEP (*(.init_array)) } - PROVIDE (__init_array_end = .); - PROVIDE (__fini_array_start = .); - .fini_array : { KEEP (*(.fini_array)) } - PROVIDE (__fini_array_end = .); - .ctors : - { - ___plugin_ctors = .; - KEEP (*(SORT(.ctors.*))) - KEEP (*(.ctors)) - ___plugin_ctors_end = .; - } - .dtors : - { - ___plugin_dtors = .; - KEEP (*(SORT(.dtors.*))) - KEEP (*(.dtors)) - ___plugin_dtors_end = .; - } - .jcr : { KEEP (*(.jcr)) } - .data.rel.ro : { *(.data.rel.ro.local) *(.data.rel.ro*) } - .data : - { - _fdata = . ; - *(.data .data.* .gnu.linkonce.d.*) - KEEP (*(.gnu.linkonce.d.*personality*)) - SORT(CONSTRUCTORS) - } - .data1 : { *(.data1) } - . = .; - .bss : - { - *(.dynbss) - *(.bss .bss.* .gnu.linkonce.b.*) - *(COMMON) - /* Align here to ensure that the .bss section occupies space up to - _end. Align after .bss to ensure correct alignment even if the - .bss section disappears because there are no input sections. */ - . = ALIGN(32 / 8); - } - . = ALIGN(32 / 8); - _end = .; - PROVIDE (end = .); - /* Stabs debugging sections. */ - .stab 0 : { *(.stab) } - .stabstr 0 : { *(.stabstr) } - .stab.excl 0 : { *(.stab.excl) } - .stab.exclstr 0 : { *(.stab.exclstr) } - .stab.index 0 : { *(.stab.index) } - .stab.indexstr 0 : { *(.stab.indexstr) } - .comment 0 : { *(.comment) } - /* DWARF debug sections. - Symbols in the DWARF debugging sections are relative to the beginning - of the section so we begin them at 0. */ - /* DWARF 1 */ - .debug 0 : { *(.debug) } - .line 0 : { *(.line) } - /* GNU DWARF 1 extensions */ - .debug_srcinfo 0 : { *(.debug_srcinfo) } - .debug_sfnames 0 : { *(.debug_sfnames) } - /* DWARF 1.1 and DWARF 2 */ - .debug_aranges 0 : { *(.debug_aranges) } - .debug_pubnames 0 : { *(.debug_pubnames) } - /* DWARF 2 */ - .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } - .debug_abbrev 0 : { *(.debug_abbrev) } - .debug_line 0 : { *(.debug_line) } - .debug_frame 0 : { *(.debug_frame) } - .debug_str 0 : { *(.debug_str) } - .debug_loc 0 : { *(.debug_loc) } - .debug_macinfo 0 : { *(.debug_macinfo) } - /* SGI/MIPS DWARF 2 extensions */ - .debug_weaknames 0 : { *(.debug_weaknames) } - .debug_funcnames 0 : { *(.debug_funcnames) } - .debug_typenames 0 : { *(.debug_typenames) } - .debug_varnames 0 : { *(.debug_varnames) } - /DISCARD/ : { *(.comment) *(.pdr) } - /DISCARD/ : { *(.note.GNU-stack) } - - . = __plugin_hole_start; - .got : { *(.got.plt) *(.got) } : shorts - /* We want the small data sections together, so single-instruction offsets - can access them all, and initialized data all before uninitialized, so - we can shorten the on-disk segment size. */ - .sdata : - { - *(.sdata .sdata.* .gnu.linkonce.s.*) - } - .lit8 : { *(.lit8) } - .lit4 : { *(.lit4) } - _edata = .; - PROVIDE (edata = .); - __bss_start = .; - _fbss = .; - .sbss : - { - PROVIDE (__sbss_start = .); - PROVIDE (___sbss_start = .); - *(.dynsbss) - *(.sbss .sbss.* .gnu.linkonce.sb.*) - *(.scommon) - PROVIDE (__sbss_end = .); - PROVIDE (___sbss_end = .); - } - - -} diff --git a/backends/platform/psp/plugin.syms b/backends/platform/psp/plugin.syms deleted file mode 100644 index 24ee1a19dc..0000000000 --- a/backends/platform/psp/plugin.syms +++ /dev/null @@ -1,8 +0,0 @@ -PLUGIN_getVersion -PLUGIN_getType -PLUGIN_getTypeVersion -PLUGIN_getObject -___plugin_ctors -___plugin_ctors_end -___plugin_dtors -___plugin_dtors_end diff --git a/backends/plugins/arm-relocs.cpp b/backends/plugins/arm-relocs.cpp index 66e466a58a..b00fb42f4a 100644 --- a/backends/plugins/arm-relocs.cpp +++ b/backends/plugins/arm-relocs.cpp @@ -134,3 +134,31 @@ bool DLObject::relocate(Common::SeekableReadStream* DLFile, unsigned long offset free(rel); return true; } + +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]); + + 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; + } + + if (!relocate(DLFile, curShdr->sh_offset, curShdr->sh_size, _segment)) { + return false; + } + + } + } + + return true; +} diff --git a/backends/plugins/ds/plugin.ld b/backends/plugins/ds/plugin.ld new file mode 100644 index 0000000000..2b2bca9745 --- /dev/null +++ b/backends/plugins/ds/plugin.ld @@ -0,0 +1,218 @@ +OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", + "elf32-littlearm") +OUTPUT_ARCH(arm) + +/* PHDRS specifies ELF Program Headers (or segments) to the plugin linker */ +PHDRS { + plugin PT_LOAD ; /* Specifies that the plugin segment should be loaded from file */ +} + +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + . = 0; + .interp : { *(.interp) } : plugin + .note.gnu.build-id : { *(.note.gnu.build-id) } + .hash : { *(.hash) } + .gnu.hash : { *(.gnu.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .gnu.version : { *(.gnu.version) } + .gnu.version_d : { *(.gnu.version_d) } + .gnu.version_r : { *(.gnu.version_r) } + .rel.dyn : + { + *(.rel.init) + *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) + *(.rel.fini) + *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) + *(.rel.data.rel.ro* .rel.gnu.linkonce.d.rel.ro.*) + *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*) + *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*) + *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*) + *(.rel.ctors) + *(.rel.dtors) + *(.rel.got) + *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) + PROVIDE_HIDDEN (__rel_iplt_start = .); + *(.rel.iplt) + PROVIDE_HIDDEN (__rel_iplt_end = .); + PROVIDE_HIDDEN (__rela_iplt_start = .); + PROVIDE_HIDDEN (__rela_iplt_end = .); + } + .rela.dyn : + { + *(.rela.init) + *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) + *(.rela.fini) + *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) + *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) + *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) + *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) + *(.rela.ctors) + *(.rela.dtors) + *(.rela.got) + *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) + PROVIDE_HIDDEN (__rel_iplt_start = .); + PROVIDE_HIDDEN (__rel_iplt_end = .); + PROVIDE_HIDDEN (__rela_iplt_start = .); + *(.rela.iplt) + PROVIDE_HIDDEN (__rela_iplt_end = .); + } + .rel.plt : + { + *(.rel.plt) + } + .rela.plt : + { + *(.rela.plt) + } + .init : + { + KEEP (*(.init)) + } =0 + .plt : { *(.plt) } + .iplt : { *(.iplt) } + .text : + { + *(.text.unlikely .text.*_unlikely) + *(.text .stub .text.* .gnu.linkonce.t.*) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + *(.glue_7t) *(.glue_7) *(.vfp11_veneer) *(.v4_bx) + } =0 + .fini : + { + KEEP (*(.fini)) + } =0 + PROVIDE (__etext = .); + PROVIDE (_etext = .); + PROVIDE (etext = .); + .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } + .rodata1 : { *(.rodata1) } + .ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } + __exidx_start = .; + .ARM.exidx : { *(.ARM.exidx* .gnu.linkonce.armexidx.*) } + __exidx_end = .; + .eh_frame_hdr : { *(.eh_frame_hdr) } + .eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) } + .gcc_except_table : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) } + /* Adjust the address for the data segment. We want to adjust up to + the same address within the page on the next page up. */ + . = ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)); + /* Exception handling */ + .eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) } + .gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) } + /* Thread Local Storage sections */ + .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) } + .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } + .preinit_array : + { + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + } + .init_array : + { + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + PROVIDE_HIDDEN (__init_array_end = .); + } + .fini_array : + { + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(.fini_array)) + KEEP (*(SORT(.fini_array.*))) + PROVIDE_HIDDEN (__fini_array_end = .); + } + .ctors : + { + ___plugin_ctors = .; + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + ___plugin_ctors_end = .; + } + .dtors : + { + ___plugin_dtors = .; + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + ___plugin_dtors_end = .; + } + .jcr : { KEEP (*(.jcr)) } + .data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro* .gnu.linkonce.d.rel.ro.*) } + .dynamic : { *(.dynamic) } + .got : { *(.got.plt) *(.igot.plt) *(.got) *(.igot) } + .data : + { + __data_start = . ; + *(.data .data.* .gnu.linkonce.d.*) + SORT(CONSTRUCTORS) + } + .data1 : { *(.data1) } + _edata = .; PROVIDE (edata = .); + __bss_start = .; + __bss_start__ = .; + .bss : + { + *(.dynbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + /* Align here to ensure that the .bss section occupies space up to + _end. Align after .bss to ensure correct alignment even if the + .bss section disappears because there are no input sections. + FIXME: Why do we need it? When there is no .bss section, we don't + pad the .data section. */ + . = ALIGN(. != 0 ? 32 / 8 : 1); + } + _bss_end__ = . ; __bss_end__ = . ; + . = ALIGN(32 / 8); + . = ALIGN(32 / 8); + __end__ = . ; + _end = .; PROVIDE (end = .); + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + /* DWARF 3 */ + .debug_pubtypes 0 : { *(.debug_pubtypes) } + .debug_ranges 0 : { *(.debug_ranges) } + .stack 0x80000 : + { + _stack = .; + *(.stack) + } + .ARM.attributes 0 : { KEEP (*(.ARM.attributes)) KEEP (*(.gnu.attributes)) } + .note.gnu.arm.ident 0 : { KEEP (*(.note.gnu.arm.ident)) } + /DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) } +} 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 #include #include +#include #include -//#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) { diff --git a/backends/plugins/elf-loader.h b/backends/plugins/elf-loader.h index e8c5701f6e..1bbcbc4b78 100644 --- a/backends/plugins/elf-loader.h +++ b/backends/plugins/elf-loader.h @@ -23,11 +23,16 @@ * */ -#ifndef LOADER_H -#define LOADER_H +#ifndef ELF_LOADER_H +#define ELF_LOADER_H -#include "backends/plugins/elf32.h" -#include "common/list.h" +#include "elf32.h" +#include "common/stream.h" + +#if defined(__PLAYSTATION2__) || defined(__PSP__) +#define MIPS_TARGET +#include "shorts-segment-manager.h" +#endif #define MAXDLERRLEN 80 @@ -43,6 +48,11 @@ 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(); bool relocate(Common::SeekableReadStream* DLFile, unsigned long offset, unsigned long size, void *relSegment); @@ -65,7 +75,13 @@ public: DLObject(char *errbuf = NULL) : _errbuf(_errbuf), _segment(NULL), _symtab(NULL), _strtab(NULL), _symbol_cnt(0), _symtab_sect(-1), _dtors_start(NULL), _dtors_end(NULL), - _segmentSize(0) {} + _segmentSize(0) { +#ifdef MIPS_TARGET + _shortsSegment = NULL; + _gpVal = 0; +#endif + } + }; #define RTLD_LAZY 0 @@ -78,8 +94,6 @@ extern "C" { void dlforgetsyms(void *handle); } -//The following need to be defined by specific ports. extern void flushDataCache(); -extern bool dlRelocate(Common::SeekableReadStream* DLFile, unsigned long offset, unsigned long size, void *relSegment); #endif /* LOADER_H */ diff --git a/backends/plugins/mips-loader.h b/backends/plugins/mips-loader.h deleted file mode 100644 index fc8334ad17..0000000000 --- a/backends/plugins/mips-loader.h +++ /dev/null @@ -1,43 +0,0 @@ -/* 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 MIPS_LOADER_H -#define MIPS_LOADER_H - -#include "loader.h" -#include "shorts-segment-manager.h" - -class MipsDLObject : public DLObject { -protected: - ShortSegmentManager::Segment *_shortsSegment; // For assigning shorts ranges - unsigned int _gpVal; // Value of Global Pointer - -public: - MipsDLObject(char *errbuf = NULL) : _errbuf(_errbuf), _shortsSegment(NULL), _segment(NULL), _symtab(NULL), - _strtab(NULL), _symbol_cnt(0), _symtab_sect(-1), _dtors_start(NULL), _dtors_end(NULL), _gpVal(0) , - _segmentSize(0) {} -}; - -#endif /* MIPS_LOADER_H */ diff --git a/backends/plugins/mips-relocs.cpp b/backends/plugins/mips-relocs.cpp new file mode 100644 index 0000000000..fe8fa7c1a0 --- /dev/null +++ b/backends/plugins/mips-relocs.cpp @@ -0,0 +1,259 @@ +/* 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$ + * + */ + +#include "elf-loader.h" + +#define __DEBUG_PLUGINS__ + +#ifdef __DEBUG_PLUGINS__ +#define DBG(x,...) printf(x, ## __VA_ARGS__) +#else +#define DBG(x,...) +#endif + +#define seterror(x,...) printf(x, ## __VA_ARGS__) + +/** + * Follow the instruction of a relocation section. + * + * @param DLFile SeekableReadStream of File + * @param offset Offset into the File + * @param size Size of relocation section + * @param relSegment Base address of relocated segment in memory (memory offset) + * + */ +bool DLObject::relocate(Common::SeekableReadStream* DLFile, unsigned long offset, unsigned long size, void *relSegment) { + Elf32_Rel *rel = NULL; // relocation entry + + // Allocate memory for relocation table + if (!(rel = (Elf32_Rel *)malloc(size))) { + seterror("Out of memory."); + return false; + } + + // Read in our relocation table + if (DLFile->seek(offset, SEEK_SET) < 0 || + DLFile->read(rel, size) != (ssize_t)size) { + seterror("Relocation table load failed."); + free(rel); + return false; + } + + // Treat each relocation entry. Loop over all of them + int cnt = size / sizeof(*rel); + + DBG("Loaded relocation table. %d entries. base address=%p\n", 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 + DBG("R_MIPS_HI16: i=%d, offset=%x, ahl = %x, target = %x\n", + 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 + seterror("R_MIPS_LO16 w/o preceding R_MIPS_HI16 at relocation %d!\n", 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) + DBG("R_MIPS_LO16: i=%d, offset=%x, a=%x, ahl = %x, lastTarget = %x, origt = %x, target = %x\n", + i, rel[i].r_offset, a, ahl, *lastTarget, origTarget, *target); + if (lo16InShorts && debugRelocs[2]++ < DEBUG_NUM) + DBG("R_MIPS_LO16s: i=%d, offset=%x, a=%x, ahl = %x, lastTarget = %x, origt = %x, target = %x\n", + 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) + DBG("R_MIPS_26: i=%d, offset=%x, symbol=%d, stinfo=%x, a=%x, origTarget=%x, target=%x\n", + i, rel[i].r_offset, REL_INDEX(rel[i].r_info), sym->st_info, a, origTarget, *target); + } else { + if (debugRelocs[4]++ < DEBUG_NUM) + DBG("R_MIPS_26: i=%d, offset=%x, symbol=%d, stinfo=%x, a=%x, origTarget=%x, target=%x\n", + 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) + DBG("R_MIPS_GPREL16: i=%d, a=%x, gpVal=%x, origTarget=%x, target=%x, offset=%x\n", + 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) + DBG("R_MIPS_32: i=%d, a=%x, origTarget=%x, target=%x\n", i, a, origTarget, *target); + } + break; + + default: + seterror("Unknown relocation type %x at relocation %d.\n", REL_TYPE(rel[i].r_info), i); + free(rel); + return false; + } + } + + DBG("Done with relocation. extendedHi16=%d\n\n", extendedHi16); + + free(rel); + return true; +} + +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 && // 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; +} + diff --git a/backends/plugins/plugin.syms b/backends/plugins/plugin.syms new file mode 100644 index 0000000000..24ee1a19dc --- /dev/null +++ b/backends/plugins/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/ps2/plugin.ld b/backends/plugins/ps2/plugin.ld new file mode 100644 index 0000000000..9879413b98 --- /dev/null +++ b/backends/plugins/ps2/plugin.ld @@ -0,0 +1,94 @@ +/* PHDRS specifies ELF Program Headers (or segments) to the plugin linker */ +PHDRS { + plugin PT_LOAD ; /* Specifies that the plugin segment should be loaded from file */ + shorts PT_LOAD ; /* Specifies that the shorts segment should be loaded from file */ +} +SECTIONS { + .text 0: { + _ftext = . ; + *(.text) + *(.text.*) + *(.gnu.linkonce.t*) + KEEP(*(.init)) + KEEP(*(.fini)) + QUAD(0) + } : plugin /*The ": plugin" tells the linker to assign this and + the following sections to the "plugin" segment*/ + PROVIDE(_etext = .); + PROVIDE(etext = .); + + .reginfo : { *(.reginfo) } + + /* Global/static constructors and deconstructors. */ + .ctors ALIGN(16): { + ___plugin_ctors = .; + KEEP(*(SORT(.ctors.*))) + KEEP(*(.ctors)) + ___plugin_ctors_end = .; + } + .dtors ALIGN(16): { + ___plugin_dtors = .; + KEEP(*(SORT(.dtors.*))) + KEEP(*(.dtors)) + ___plugin_dtors_end = .; + } + + /* Static data. */ + .rodata ALIGN(128): { + *(.rodata) + *(.rodata.*) + *(.gnu.linkonce.r*) + } + + .data ALIGN(128): { + _fdata = . ; + *(.data) + *(.data.*) + *(.gnu.linkonce.d*) + SORT(CONSTRUCTORS) + } + + .rdata ALIGN(128): { *(.rdata) } + .gcc_except_table ALIGN(128): { *(.gcc_except_table) } + + .bss ALIGN(128) : { + *(.bss) + *(.bss.*) + *(.gnu.linkonce.b*) + *(COMMON) + } + _end_bss = .; + + _end = . ; + PROVIDE(end = .); + + /* Symbols needed by crt0.s. */ + PROVIDE(_heap_size = -1); + PROVIDE(_stack = -1); + PROVIDE(_stack_size = 128 * 1024); + + /*We assign the output location counter to the plugin hole made + in main_prog.ld, then assign the small data sections to the shorts segment*/ + . = __plugin_hole_start; + .lit4 ALIGN(128): { *(.lit4) } : shorts + .lit8 ALIGN(128): { *(.lit8) } + + .sdata ALIGN(128): { + *(.sdata) + *(.sdata.*) + *(.gnu.linkonce.s*) + } + + _edata = .; + PROVIDE(edata = .); + + /* Uninitialized data. */ + .sbss ALIGN(128) : { + _fbss = . ; + *(.sbss) + *(.sbss.*) + *(.gnu.linkonce.sb*) + *(.scommon) + } + +} diff --git a/backends/plugins/psp/plugin.ld b/backends/plugins/psp/plugin.ld new file mode 100644 index 0000000000..db4df45264 --- /dev/null +++ b/backends/plugins/psp/plugin.ld @@ -0,0 +1,239 @@ +OUTPUT_FORMAT("elf32-littlemips", "elf32-bigmips", + "elf32-littlemips") +OUTPUT_ARCH(mips:allegrex) +PHDRS +{ + plugin PT_LOAD ; + shorts PT_LOAD ; +} +/* Do we need any of these for elf? + __DYNAMIC = 0; */ +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + . = 0; + .interp : { *(.interp) } : plugin + .reginfo : { *(.reginfo) } : plugin + .dynamic : { *(.dynamic) } + .hash : { *(.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .gnu.version : { *(.gnu.version) } + .gnu.version_d : { *(.gnu.version_d) } + .gnu.version_r : { *(.gnu.version_r) } + .rel.init : { *(.rel.init) } + .rela.init : { *(.rela.init) } + .rel.text : { *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) } + .rela.text : { *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) } + .rel.fini : { *(.rel.fini) } + .rela.fini : { *(.rela.fini) } + /* PSP-specific relocations. */ + .rel.sceStub.text : { *(.rel.sceStub.text) *(SORT(.rel.sceStub.text.*)) } + .rel.lib.ent.top : { *(.rel.lib.ent.top) } + .rel.lib.ent : { *(.rel.lib.ent) } + .rel.lib.ent.btm : { *(.rel.lib.ent.btm) } + .rel.lib.stub.top : { *(.rel.lib.stub.top) } + .rel.lib.stub : { *(.rel.lib.stub) } + .rel.lib.stub.btm : { *(.rel.lib.stub.btm) } + .rel.rodata.sceModuleInfo : { *(.rel.rodata.sceModuleInfo) } + .rel.rodata.sceResident : { *(.rel.rodata.sceResident) } + .rel.rodata.sceNid : { *(.rel.rodata.sceNid) } + .rel.rodata.sceVstub : { *(.rel.rodata.sceVstub) *(SORT(.rel.rodata.sceVstub.*)) } + .rel.rodata : { *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) } + .rela.rodata : { *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) } + .rel.data.rel.ro : { *(.rel.data.rel.ro*) } + .rela.data.rel.ro : { *(.rel.data.rel.ro*) } + .rel.data : { *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*) } + .rela.data : { *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) } + .rel.tdata : { *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*) } + .rela.tdata : { *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) } + .rel.tbss : { *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*) } + .rela.tbss : { *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) } + .rel.ctors : { *(.rel.ctors) } + .rela.ctors : { *(.rela.ctors) } + .rel.dtors : { *(.rel.dtors) } + .rela.dtors : { *(.rela.dtors) } + .rel.got : { *(.rel.got) } + .rela.got : { *(.rela.got) } + .rel.sdata : { *(.rel.sdata .rel.sdata.* .rel.gnu.linkonce.s.*) } + .rela.sdata : { *(.rela.sdata .rela.sdata.* .rela.gnu.linkonce.s.*) } + .rel.sbss : { *(.rel.sbss .rel.sbss.* .rel.gnu.linkonce.sb.*) } + .rela.sbss : { *(.rela.sbss .rela.sbss.* .rela.gnu.linkonce.sb.*) } + .rel.sdata2 : { *(.rel.sdata2 .rel.sdata2.* .rel.gnu.linkonce.s2.*) } + .rela.sdata2 : { *(.rela.sdata2 .rela.sdata2.* .rela.gnu.linkonce.s2.*) } + .rel.sbss2 : { *(.rel.sbss2 .rel.sbss2.* .rel.gnu.linkonce.sb2.*) } + .rela.sbss2 : { *(.rela.sbss2 .rela.sbss2.* .rela.gnu.linkonce.sb2.*) } + .rel.bss : { *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) } + .rela.bss : { *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) } + .rel.plt : { *(.rel.plt) } + .rela.plt : { *(.rela.plt) } + .init : + { + KEEP (*(.init)) + } =0 + .plt : { *(.plt) } + .text : + { + _ftext = . ; + *(.text .stub .text.* .gnu.linkonce.t.*) + KEEP (*(.text.*personality*)) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + *(.mips16.fn.*) *(.mips16.call.*) + } =0 + .fini : + { + KEEP (*(.fini)) + } =0 + /* PSP library stub functions. */ + .sceStub.text : { *(.sceStub.text) *(SORT(.sceStub.text.*)) } + PROVIDE (__etext = .); + PROVIDE (_etext = .); + PROVIDE (etext = .); + /* PSP library entry table and library stub table. */ + .lib.ent.top : { *(.lib.ent.top) } + .lib.ent : { *(.lib.ent) } + .lib.ent.btm : { *(.lib.ent.btm) } + .lib.stub.top : { *(.lib.stub.top) } + .lib.stub : { *(.lib.stub) } + .lib.stub.btm : { *(.lib.stub.btm) } + /* PSP read-only data for module info, NIDs, and Vstubs. The + .rodata.sceModuleInfo section must appear before the .rodata section + otherwise it would get absorbed into .rodata and the PSP bootloader + would be unable to locate the module info structure. */ + .rodata.sceModuleInfo : { *(.rodata.sceModuleInfo) } + .rodata.sceResident : { *(.rodata.sceResident) } + .rodata.sceNid : { *(.rodata.sceNid) } + .rodata.sceVstub : { *(.rodata.sceVstub) *(SORT(.rodata.sceVstub.*)) } + .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } + .rodata1 : { *(.rodata1) } + .sdata2 : { *(.sdata2 .sdata2.* .gnu.linkonce.s2.*) } + .sbss2 : { *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) } + .eh_frame_hdr : { *(.eh_frame_hdr) } + .eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) } + .gcc_except_table : ONLY_IF_RO { KEEP (*(.gcc_except_table)) *(.gcc_except_table.*) } + /* Adjust the address for the data segment. We want to adjust up to + the same address within the page on the next page up. */ + . = ALIGN(256) + (. & (256 - 1)); + /* Exception handling */ + .eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) } + .gcc_except_table : ONLY_IF_RW { KEEP (*(.gcc_except_table)) *(.gcc_except_table.*) } + /* Thread Local Storage sections */ + .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) } + .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } + /* Ensure the __preinit_array_start label is properly aligned. We + could instead move the label definition inside the section, but + the linker would then create the section even if it turns out to + be empty, which isn't pretty. */ + . = ALIGN(32 / 8); + PROVIDE (__preinit_array_start = .); + .preinit_array : { KEEP (*(.preinit_array)) } + PROVIDE (__preinit_array_end = .); + PROVIDE (__init_array_start = .); + .init_array : { KEEP (*(.init_array)) } + PROVIDE (__init_array_end = .); + PROVIDE (__fini_array_start = .); + .fini_array : { KEEP (*(.fini_array)) } + PROVIDE (__fini_array_end = .); + .ctors : + { + ___plugin_ctors = .; + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + ___plugin_ctors_end = .; + } + .dtors : + { + ___plugin_dtors = .; + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + ___plugin_dtors_end = .; + } + .jcr : { KEEP (*(.jcr)) } + .data.rel.ro : { *(.data.rel.ro.local) *(.data.rel.ro*) } + .data : + { + _fdata = . ; + *(.data .data.* .gnu.linkonce.d.*) + KEEP (*(.gnu.linkonce.d.*personality*)) + SORT(CONSTRUCTORS) + } + .data1 : { *(.data1) } + . = .; + .bss : + { + *(.dynbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + /* Align here to ensure that the .bss section occupies space up to + _end. Align after .bss to ensure correct alignment even if the + .bss section disappears because there are no input sections. */ + . = ALIGN(32 / 8); + } + . = ALIGN(32 / 8); + _end = .; + PROVIDE (end = .); + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + /DISCARD/ : { *(.comment) *(.pdr) } + /DISCARD/ : { *(.note.GNU-stack) } + + . = __plugin_hole_start; + .got : { *(.got.plt) *(.got) } : shorts + /* We want the small data sections together, so single-instruction offsets + can access them all, and initialized data all before uninitialized, so + we can shorten the on-disk segment size. */ + .sdata : + { + *(.sdata .sdata.* .gnu.linkonce.s.*) + } + .lit8 : { *(.lit8) } + .lit4 : { *(.lit4) } + _edata = .; + PROVIDE (edata = .); + __bss_start = .; + _fbss = .; + .sbss : + { + PROVIDE (__sbss_start = .); + PROVIDE (___sbss_start = .); + *(.dynsbss) + *(.sbss .sbss.* .gnu.linkonce.sb.*) + *(.scommon) + PROVIDE (__sbss_end = .); + PROVIDE (___sbss_end = .); + } + + +} diff --git a/backends/plugins/shorts-segment-manager.cpp b/backends/plugins/shorts-segment-manager.cpp index cce93e7f86..eb2ab2d953 100644 --- a/backends/plugins/shorts-segment-manager.cpp +++ b/backends/plugins/shorts-segment-manager.cpp @@ -25,9 +25,20 @@ #if defined(DYNAMIC_MODULES) //TODO: && defined (MIPS target) -//#include "MIPS-loader.h" #include "shorts-segment-manager.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 + +#ifdef DEBUG_PLUGINS +#define DBG(x,...) printf(x, ## __VA_ARGS__) +#else +#define DBG(x,...) +#endif + +#define seterror(x,...) printf(x, ## __VA_ARGS__) + DECLARE_SINGLETON(ShortSegmentManager); // For singleton ShortSegmentManager::ShortSegmentManager() { diff --git a/backends/plugins/shorts-segment-manager.h b/backends/plugins/shorts-segment-manager.h index 40ceef60f0..02f5221e8d 100644 --- a/backends/plugins/shorts-segment-manager.h +++ b/backends/plugins/shorts-segment-manager.h @@ -26,8 +26,9 @@ #ifndef SHORTS_SEGMENT_MANAGER_H #define SHORTS_SEGMENT_MANAGER_H -#include "loader.h" #include "common/singleton.h" +#include "common/list.h" +#include "elf32.h" #define ShortsMan ShortSegmentManager::instance() -- cgit v1.2.3