added files for ps2 loadable modules (mainly transplanted from psp code with VERY minor tweaks)
svn-id: r49256
This commit is contained in:
parent
fab28cb74b
commit
0fdfd5d47b
8 changed files with 1617 additions and 0 deletions
209
backends/platform/ps2/elf32.h
Normal file
209
backends/platform/ps2/elf32.h
Normal file
|
@ -0,0 +1,209 @@
|
|||
/* 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: https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/branches/gsoc2010-plugins/backends/platform/ps2/elf32.h $
|
||||
* $Id: elf32.h 49253 2010-05-12 05:26:54Z Toneman $
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef BACKENDS_ELF_H
|
||||
#define BACKENDS_ELF_H
|
||||
|
||||
/* ELF stuff */
|
||||
|
||||
typedef unsigned short Elf32_Half, Elf32_Section;
|
||||
typedef unsigned int Elf32_Word, Elf32_Addr, Elf32_Off;
|
||||
typedef signed int Elf32_Sword;
|
||||
typedef Elf32_Half Elf32_Versym;
|
||||
|
||||
#define EI_NIDENT (16)
|
||||
#define SELFMAG 6
|
||||
|
||||
/* ELF File format structures. Look up ELF structure for more details */
|
||||
|
||||
// ELF header (contains info about the file)
|
||||
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;
|
||||
|
||||
// Should be in e_ident
|
||||
#define ELFMAG "\177ELF\1\1" /* ELF Magic number */
|
||||
|
||||
// e_type values
|
||||
#define ET_NONE 0 /* no file type */
|
||||
#define ET_REL 1 /* relocatable */
|
||||
#define ET_EXEC 2 /* executable */
|
||||
#define ET_DYN 3 /* shared object */
|
||||
#define ET_CORE 4 /* core file */
|
||||
|
||||
// e_machine values
|
||||
#define EM_MIPS 8
|
||||
|
||||
|
||||
// Program header (contains info about segment)
|
||||
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;
|
||||
|
||||
// p_type values
|
||||
#define PT_NULL 0 /* ignored */
|
||||
#define PT_LOAD 1 /* loadable segment */
|
||||
#define PT_DYNAMIC 2 /* dynamic linking info */
|
||||
#define PT_INTERP 3 /* info about interpreter */
|
||||
#define PT_NOTE 4 /* note segment */
|
||||
#define PT_SHLIB 5 /* reserved */
|
||||
#define PT_PHDR 6 /* Program header table */
|
||||
#define PT_MIPS_REGINFO 0x70000000 /* register usage info */
|
||||
|
||||
// p_flags value
|
||||
#define PF_X 1 /* execute */
|
||||
#define PF_W 2 /* write */
|
||||
#define PF_R 4 /* read */
|
||||
|
||||
// Section header (contains info about section)
|
||||
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;
|
||||
|
||||
// sh_type values
|
||||
#define SHT_NULL 0 /* Inactive section */
|
||||
#define SHT_PROGBITS 1 /* Proprietary */
|
||||
#define SHT_SYMTAB 2 /* Symbol table */
|
||||
#define SHT_STRTAB 3 /* String table */
|
||||
#define SHT_RELA 4 /* Relocation entries with addend */
|
||||
#define SHT_HASH 5 /* Symbol hash table */
|
||||
#define SHT_DYNAMIC 6 /* Info for dynamic linking */
|
||||
#define SHT_NOTE 7 /* Note section */
|
||||
#define SHT_NOBITS 8 /* Occupies no space */
|
||||
#define SHT_REL 9 /* Relocation entries without addend */
|
||||
#define SHT_SHLIB 10 /* Reserved */
|
||||
#define SHT_DYNSYM 11 /* Minimal set of dynamic linking symbols */
|
||||
#define SHT_MIPS_LIBLSIT 0x70000000 /* Info about dynamic shared object libs */
|
||||
#define SHT_MIPS_CONFLICT 0x70000002 /* Conflicts btw executables and shared objects */
|
||||
#define SHT_MIPS_GPTAB 0x70000003 /* Global pointer table */
|
||||
|
||||
// sh_flags values
|
||||
#define SHF_WRITE 0 /* writable section */
|
||||
#define SHF_ALLOC 2 /* section occupies memory */
|
||||
#define SHF_EXECINSTR 4 /* machine instructions */
|
||||
#define SHF_MIPS_GPREL 0x10000000 /* Must be made part of global data area */
|
||||
|
||||
|
||||
// Symbol entry (contain info about a symbol)
|
||||
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;
|
||||
|
||||
// Extract from the st_info
|
||||
#define SYM_TYPE(x) ((x)&0xF)
|
||||
#define SYM_BIND(x) ((x)>>4)
|
||||
|
||||
|
||||
// Symbol binding values from st_info
|
||||
#define STB_LOCAL 0 /* Symbol not visible outside object */
|
||||
#define STB_GLOBAL 1 /* Symbol visible to all object files */
|
||||
#define STB_WEAK 2 /* Similar to STB_GLOBAL */
|
||||
|
||||
// Symbol type values from st_info
|
||||
#define STT_NOTYPE 0 /* Not specified */
|
||||
#define STT_OBJECT 1 /* Data object e.g. variable */
|
||||
#define STT_FUNC 2 /* Function */
|
||||
#define STT_SECTION 3 /* Section */
|
||||
#define STT_FILE 4 /* Source file associated with object file */
|
||||
|
||||
// Special section header index values from st_shndex
|
||||
#define SHN_UNDEF 0
|
||||
#define SHN_LOPROC 0xFF00 /* Extended values */
|
||||
#define SHN_ABS 0xFFF1 /* Absolute value: don't relocate */
|
||||
#define SHN_COMMON 0xFFF2 /* Common block. Not allocated yet */
|
||||
#define SHN_HIPROC 0xFF1F
|
||||
#define SHN_HIRESERVE 0xFFFF
|
||||
|
||||
// Relocation entry (info about how to relocate)
|
||||
typedef struct {
|
||||
Elf32_Addr r_offset; /* Address */
|
||||
Elf32_Word r_info; /* Relocation type and symbol index */
|
||||
} Elf32_Rel;
|
||||
|
||||
// Access macros for the relocation info
|
||||
#define REL_TYPE(x) ((x)&0xFF) /* Extract relocation type */
|
||||
#define REL_INDEX(x) ((x)>>8) /* Extract relocation index into symbol table */
|
||||
|
||||
// MIPS relocation types
|
||||
#define R_MIPS_NONE 0
|
||||
#define R_MIPS_16 1
|
||||
#define R_MIPS_32 2
|
||||
#define R_MIPS_REL32 3
|
||||
#define R_MIPS_26 4
|
||||
#define R_MIPS_HI16 5
|
||||
#define R_MIPS_LO16 6
|
||||
#define R_MIPS_GPREL16 7
|
||||
#define R_MIPS_LITERAL 8
|
||||
#define R_MIPS_GOT16 9
|
||||
#define R_MIPS_PC16 10
|
||||
#define R_MIPS_CALL16 11
|
||||
#define R_MIPS_GPREL32 12
|
||||
#define R_MIPS_GOTHI16 13
|
||||
#define R_MIPS_GOTLO16 14
|
||||
#define R_MIPS_CALLHI16 15
|
||||
#define R_MIPS_CALLLO16 16
|
||||
|
||||
// Mock function to get value of global pointer
|
||||
#define getGP() ({ \
|
||||
unsigned int __valgp; \
|
||||
__asm__ ("add %0, $gp, $0" : "=r"(__valgp) : ); \
|
||||
__valgp; \
|
||||
})
|
||||
|
||||
#endif /* BACKENDS_ELF_H */
|
253
backends/platform/ps2/main_prog.ld
Normal file
253
backends/platform/ps2/main_prog.ld
Normal file
|
@ -0,0 +1,253 @@
|
|||
OUTPUT_FORMAT("elf32-littlemips", "elf32-bigmips",
|
||||
"elf32-littlemips")
|
||||
OUTPUT_ARCH(mips:allegrex)
|
||||
ENTRY(_start)
|
||||
/* Do we need any of these for elf?
|
||||
__DYNAMIC = 0; */
|
||||
SECTIONS
|
||||
{
|
||||
/* Read-only sections, merged into text segment: */
|
||||
PROVIDE (__executable_start = 0x08900000); . = 0x08900000;
|
||||
.interp : { *(.interp) }
|
||||
.reginfo : { *(.reginfo) }
|
||||
.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. TODO: works for PS2 as well? */
|
||||
.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. TODO: works for PS2 as well? */
|
||||
.sceStub.text : { *(.sceStub.text) *(SORT(.sceStub.text.*)) }
|
||||
PROVIDE (__etext = .);
|
||||
PROVIDE (_etext = .);
|
||||
PROVIDE (etext = .);
|
||||
/* PSP library entry table and library stub table. TODO: works for PS2 as well? */
|
||||
.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. TODO: Works for PS2 as well? */
|
||||
.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 :
|
||||
{
|
||||
/* gcc uses crtbegin.o to find the start of
|
||||
the constructors, so we make sure it is
|
||||
first. Because this is a wildcard, it
|
||||
doesn't matter if the user does not
|
||||
actually link against crtbegin.o; the
|
||||
linker won't look for a file to match a
|
||||
wildcard. The wildcard also means that it
|
||||
doesn't matter which directory crtbegin.o
|
||||
is in. */
|
||||
KEEP (*crtbegin*.o(.ctors))
|
||||
/* We don't want to include the .ctor section from
|
||||
from the crtend.o file until after the sorted ctors.
|
||||
The .ctor section from the crtend file contains the
|
||||
end of ctors marker and it must be last */
|
||||
KEEP (*(EXCLUDE_FILE (*crtend*.o ) .ctors))
|
||||
KEEP (*(SORT(.ctors.*)))
|
||||
KEEP (*(.ctors))
|
||||
}
|
||||
.dtors :
|
||||
{
|
||||
KEEP (*crtbegin*.o(.dtors))
|
||||
KEEP (*(EXCLUDE_FILE (*crtend*.o ) .dtors))
|
||||
KEEP (*(SORT(.dtors.*)))
|
||||
KEEP (*(.dtors))
|
||||
}
|
||||
.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) }
|
||||
. = .;
|
||||
_gp = ALIGN(16) + 0x7ff0;
|
||||
.got : { *(.got.plt) *(.got) }
|
||||
/* 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 = .);
|
||||
}
|
||||
/* make a gap to put the plugins' short data here */
|
||||
__plugin_hole_start = .;
|
||||
. = _gp + 0x7ff0;
|
||||
__plugin_hole_end = .;
|
||||
COMMON :
|
||||
{
|
||||
*(COMMON)
|
||||
}
|
||||
. = ALIGN(32 / 8);
|
||||
.bss :
|
||||
{
|
||||
*(.dynbss)
|
||||
*(.bss .bss.* .gnu.linkonce.b.*)
|
||||
/* 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) }
|
||||
}
|
239
backends/platform/ps2/plugin.ld
Normal file
239
backends/platform/ps2/plugin.ld
Normal file
|
@ -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. TODO: Do these work for PS2 as well? */
|
||||
.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. TODO: Work for PS2 as well? */
|
||||
.sceStub.text : { *(.sceStub.text) *(SORT(.sceStub.text.*)) }
|
||||
PROVIDE (__etext = .);
|
||||
PROVIDE (_etext = .);
|
||||
PROVIDE (etext = .);
|
||||
/* PSP library entry table and library stub table. TODO: Works for PS2 as well? */
|
||||
.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. TODO: Works for the ps2 as well? */
|
||||
.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 = .);
|
||||
}
|
||||
|
||||
|
||||
}
|
8
backends/platform/ps2/plugin.syms
Normal file
8
backends/platform/ps2/plugin.syms
Normal file
|
@ -0,0 +1,8 @@
|
|||
PLUGIN_getVersion
|
||||
PLUGIN_getType
|
||||
PLUGIN_getTypeVersion
|
||||
PLUGIN_getObject
|
||||
___plugin_ctors
|
||||
___plugin_ctors_end
|
||||
___plugin_dtors
|
||||
___plugin_dtors_end
|
721
backends/platform/ps2/ps2loader.cpp
Normal file
721
backends/platform/ps2/ps2loader.cpp
Normal file
|
@ -0,0 +1,721 @@
|
|||
/* 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: https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/branches/gsoc2010-plugins/backends/platform/ps2/ps2loader.cpp $
|
||||
* TODO: $ID
|
||||
*
|
||||
*/
|
||||
|
||||
#if defined(DYNAMIC_MODULES) && defined(__PS2__)
|
||||
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <malloc.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/_default_fcntl.h>
|
||||
|
||||
#include <ps2utils.h>
|
||||
|
||||
#include "backends/platform/ps2/ps2loader.h"
|
||||
//#include "backends/platform/ps2/powerman.h" //TODO
|
||||
|
||||
//#define __PS2_DEBUG_PLUGINS__
|
||||
|
||||
#ifdef __PS2_DEBUG_PLUGINS__
|
||||
#define DBG(x,...) fprintf(stderr,x, ## __VA_ARGS__)
|
||||
#else
|
||||
#define DBG(x,...)
|
||||
#endif
|
||||
|
||||
#define seterror(x,...) fprintf(stderr,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 fd File Descriptor
|
||||
* @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(int fd, 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 (lseek(fd, offset, SEEK_SET) < 0 ||
|
||||
read(fd, 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(int fd, Elf32_Ehdr *ehdr) {
|
||||
// Start reading the elf header. Check for errors
|
||||
if (read(fd, 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(int fd, Elf32_Ehdr *ehdr, Elf32_Phdr *phdr, int num) {
|
||||
// Read program header
|
||||
if (lseek(fd, ehdr->e_phoff + sizeof(*phdr)*num, SEEK_SET) < 0 ||
|
||||
read(fd, 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(int fd, 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 (lseek(fd, phdr->p_offset, SEEK_SET) < 0 ||
|
||||
read(fd, baseAddress, phdr->p_filesz) != (ssize_t)phdr->p_filesz) {
|
||||
seterror("Segment load failed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
Elf32_Shdr * DLObject::loadSectionHeaders(int fd, 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 (lseek(fd, ehdr->e_shoff, SEEK_SET) < 0 ||
|
||||
read(fd, 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(int fd, 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 (lseek(fd, shdr[_symtab_sect].sh_offset, SEEK_SET) < 0 ||
|
||||
read(fd, _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(int fd, 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 (lseek(fd, shdr[string_sect].sh_offset, SEEK_SET) < 0 ||
|
||||
read(fd, _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(int fd, 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(fd, curShdr->sh_offset, curShdr->sh_size, _segment)) {
|
||||
return false;
|
||||
}
|
||||
} else { // In Shorts segment
|
||||
if (!relocate(fd, curShdr->sh_offset, curShdr->sh_size, (void *)_shortsSegment->getOffset())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool DLObject::load(int fd) {
|
||||
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(fd, &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(fd, &ehdr, &phdr, i) == false)
|
||||
return false;
|
||||
|
||||
if (!loadSegment(fd, &phdr))
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((shdr = loadSectionHeaders(fd, &ehdr)) == NULL)
|
||||
ret = false;
|
||||
|
||||
if (ret && ((_symtab_sect = loadSymbolTable(fd, &ehdr, shdr)) < 0))
|
||||
ret = false;
|
||||
|
||||
if (ret && (loadStringTable(fd, shdr) == false))
|
||||
ret = false;
|
||||
|
||||
if (ret)
|
||||
relocateSymbols((Elf32_Addr)_segment, _shortsSegment->getOffset()); // Offset by our segment allocated address
|
||||
|
||||
if (ret && (relocateRels(fd, &ehdr, shdr) == false))
|
||||
ret = false;
|
||||
|
||||
free(shdr);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool DLObject::open(const char *path) {
|
||||
int fd;
|
||||
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);
|
||||
|
||||
PowerMan.beginCriticalSection();
|
||||
|
||||
if ((fd = ::open(path, O_RDONLY)) < 0) {
|
||||
seterror("%s not found.", path);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Try to load and relocate
|
||||
if (!load(fd)) {
|
||||
::close(fd);
|
||||
unload();
|
||||
return false;
|
||||
}
|
||||
|
||||
::close(fd);
|
||||
|
||||
PowerMan.endCriticalSection();
|
||||
|
||||
// flush data cache
|
||||
sceKernelDcacheWritebackAll();
|
||||
|
||||
// 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<Segment *>::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 && __PS2__ */
|
137
backends/platform/ps2/ps2loader.h
Normal file
137
backends/platform/ps2/ps2loader.h
Normal file
|
@ -0,0 +1,137 @@
|
|||
/* 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: https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/branches/gsoc2010-plugins/backends/platform/ps2/ps2loader.h $
|
||||
* TODO: $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<ShortSegmentManager> {
|
||||
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<ShortSegmentManager>;
|
||||
Common::List<Segment *> _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(int fd, unsigned long offset, unsigned long size, void *);
|
||||
bool load(int fd);
|
||||
|
||||
bool readElfHeader(int fd, Elf32_Ehdr *ehdr);
|
||||
bool readProgramHeaders(int fd, Elf32_Ehdr *ehdr, Elf32_Phdr *phdr, int num);
|
||||
bool loadSegment(int fd, Elf32_Phdr *phdr);
|
||||
Elf32_Shdr *loadSectionHeaders(int fd, Elf32_Ehdr *ehdr);
|
||||
int loadSymbolTable(int fd, Elf32_Ehdr *ehdr, Elf32_Shdr *shdr);
|
||||
bool loadStringTable(int fd, Elf32_Shdr *shdr);
|
||||
void relocateSymbols(Elf32_Addr offset, Elf32_Addr shortsOffset);
|
||||
bool relocateRels(int fd, 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 */
|
|
@ -1,3 +1,28 @@
|
|||
/* 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: https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/branches/gsoc2010-plugins/backends/plugins/ps2/ps2-provider.cpp $
|
||||
* $Id: ps2-provider.cpp 49253 2010-05-26 5:17:18Z Toneman $
|
||||
*
|
||||
*/
|
||||
|
||||
#if defined(DYNAMIC_MODULES) && defined(__PS2__)
|
||||
|
||||
#include "backends/plugins/ps2/ps2-provider.h"
|
||||
|
|
|
@ -1,3 +1,28 @@
|
|||
/* 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: https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/branches/gsoc2010-plugins/backends/plugins/ps2/ps2-provider.h $
|
||||
* $Id: ps2-provider.h 49253 2010-05-26 5:17:18Z Toneman $
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef BACKENDS_PLUGINS_PS2_PS2_PROVIDER_H
|
||||
#define BACKENDS_PLUGINS_PS2_PS2_PROVIDER_H
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue