[Scummvm-cvs-logs] CVS: scummvm/backends/dc cache.S,NONE,1.1 dcloader.cpp,NONE,1.1 dcloader.h,NONE,1.1 plugin.syms,NONE,1.1 plugin.x,NONE,1.1 .cvsignore,1.9,1.10 Makefile,1.23,1.24

Marcus Comstedt marcus_c at users.sourceforge.net
Sun Aug 22 14:48:00 CEST 2004


Update of /cvsroot/scummvm/scummvm/backends/dc
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv12463

Modified Files:
	.cvsignore Makefile 
Added Files:
	cache.S dcloader.cpp dcloader.h plugin.syms plugin.x 
Log Message:
Support dynamic plugins on Dreamcast.

--- NEW FILE: cache.S ---

	.globl	_flush_instruction_cache
	
	.align 2

	! Flush the SH instruction cache

_flush_instruction_cache:
	mova	fcc,r0
	mov.l	p2_mask,r1
	or	r1,r0
	jmp	@r0
	nop
	nop
fcc:
	mov.l	ccr_addr,r0
	mov.l	ccr_data,r1
	mov.l	r1, at r0
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	rts
	nop

	.align	2

p2_mask:
	.long	0xa0000000
ccr_addr:
	.long	0xff00001c
ccr_data:
	.word	0x0905


--- NEW FILE: dcloader.cpp ---
/* ScummVM - Scumm Interpreter
 * Dreamcast port
 * Copyright (C) 2002-2004  Marcus Comstedt
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.

 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.

 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 * $Header: /cvsroot/scummvm/scummvm/backends/dc/dcloader.cpp,v 1.1 2004/08/22 21:47:20 marcus_c Exp $
 *
 */

#include <stdafx.h>
#include <ronin/ronin.h>
#include <string.h>
#include <stdarg.h>

#include "dcloader.h"

#ifdef DL_DEBUG
#define DBG(...) reportf(__VA_ARGS__)
#else
#define DBG(...) 0
#endif


/* ELF stuff */

typedef unsigned short Elf32_Half, Elf32_Section;
typedef unsigned long Elf32_Word, Elf32_Addr, Elf32_Off;
typedef signed long  Elf32_Sword;
typedef Elf32_Half Elf32_Versym;

#define EI_NIDENT (16)
#define ELFMAG          "\177ELF\1\1"
#define SELFMAG         6

typedef struct
{
  unsigned char e_ident[EI_NIDENT];     /* Magic number and other info */
  Elf32_Half    e_type;                 /* Object file type */
  Elf32_Half    e_machine;              /* Architecture */
  Elf32_Word    e_version;              /* Object file version */
  Elf32_Addr    e_entry;                /* Entry point virtual address */
  Elf32_Off     e_phoff;                /* Program header table file offset */
  Elf32_Off     e_shoff;                /* Section header table file offset */
  Elf32_Word    e_flags;                /* Processor-specific flags */
  Elf32_Half    e_ehsize;               /* ELF header size in bytes */
  Elf32_Half    e_phentsize;            /* Program header table entry size */
  Elf32_Half    e_phnum;                /* Program header table entry count */
  Elf32_Half    e_shentsize;            /* Section header table entry size */
  Elf32_Half    e_shnum;                /* Section header table entry count */
  Elf32_Half    e_shstrndx;             /* Section header string table index */
} Elf32_Ehdr;

typedef struct
{
  Elf32_Word    p_type;                 /* Segment type */
  Elf32_Off     p_offset;               /* Segment file offset */
  Elf32_Addr    p_vaddr;                /* Segment virtual address */
  Elf32_Addr    p_paddr;                /* Segment physical address */
  Elf32_Word    p_filesz;               /* Segment size in file */
  Elf32_Word    p_memsz;                /* Segment size in memory */
  Elf32_Word    p_flags;                /* Segment flags */
  Elf32_Word    p_align;                /* Segment alignment */
} Elf32_Phdr;

typedef struct
{
  Elf32_Word    sh_name;                /* Section name (string tbl index) */
  Elf32_Word    sh_type;                /* Section type */
  Elf32_Word    sh_flags;               /* Section flags */
  Elf32_Addr    sh_addr;                /* Section virtual addr at execution */
  Elf32_Off     sh_offset;              /* Section file offset */
  Elf32_Word    sh_size;                /* Section size in bytes */
  Elf32_Word    sh_link;                /* Link to another section */
  Elf32_Word    sh_info;                /* Additional section information */
  Elf32_Word    sh_addralign;           /* Section alignment */
  Elf32_Word    sh_entsize;             /* Entry size if section holds table */
} Elf32_Shdr;

typedef struct
{
  Elf32_Word    st_name;                /* Symbol name (string tbl index) */
  Elf32_Addr    st_value;               /* Symbol value */
  Elf32_Word    st_size;                /* Symbol size */
  unsigned char st_info;                /* Symbol type and binding */
  unsigned char st_other;               /* Symbol visibility */
  Elf32_Section st_shndx;               /* Section index */
} Elf32_Sym;

typedef struct
{
  Elf32_Addr    r_offset;               /* Address */
  Elf32_Word    r_info;                 /* Relocation type and symbol index */
  Elf32_Sword   r_addend;               /* Addend */
} Elf32_Rela;



extern "C" void flush_instruction_cache();

static void purge_copyback()
{
  int i;
  for(i=0; i!=(1<<14); i+=(1<<5))
    *(volatile unsigned int *)(0xf4000000+i) &= ~3;
}


void DLObject::seterror(const char *fmt, ...)
{
  if(errbuf) {
    va_list va;
    va_start(va, fmt);
    vsnprintf(errbuf, MAXDLERRLEN, fmt, va);
    va_end(va);
  }
}

void DLObject::discard_symtab()
{
  free(symtab);
  free(strtab);
  symtab = NULL;
  strtab = NULL;
  symbol_cnt = 0;
}

void DLObject::unload()
{
  discard_symtab();
  free(segment);
  segment = NULL;
}

bool DLObject::relocate(int fd, unsigned long offset, unsigned long size)
{
  Elf32_Rela *rela;

  if(!(rela = (Elf32_Rela *)malloc(size))) {
    seterror("Out of memory.");
    return false;
  }

  if(lseek(fd, offset, SEEK_SET)<0 ||
     read(fd, rela, size) != size) {
    seterror("Relocation table load failed.");
    free(rela);
    return false;
  }

  int cnt = size / sizeof(*rela);
  for(int i=0; i<cnt; i++) {

    Elf32_Sym *sym = (Elf32_Sym *)(((char *)symtab)+(rela[i].r_info>>4));

    void *target = ((char *)segment)+rela[i].r_offset;

    switch(rela[i].r_info & 0xf) {
    case 1: /* DIR32 */
      if(sym->st_shndx < 0xff00)
	*(unsigned long *)target += (unsigned long)segment;
      break;
    default:
      seterror("Unknown relocation type %d.", rela[i].r_info & 0xf);
      free(rela);
      return false;
    }

  }

  free(rela);
  return true;  
}


bool DLObject::load(int fd)
{
  Elf32_Ehdr ehdr;
  Elf32_Phdr phdr;
  Elf32_Shdr *shdr;
  int symtab_sect = -1;

  if(read(fd, &ehdr, sizeof(ehdr)) != sizeof(ehdr) ||
     memcmp(ehdr.e_ident, ELFMAG, SELFMAG) ||
     ehdr.e_type != 2 ||  ehdr.e_machine != 42 ||
     ehdr.e_phentsize < sizeof(phdr) || ehdr.e_shentsize != sizeof(*shdr) ||
     ehdr.e_phnum != 1) {
    seterror("Invalid file type.");
    return false;
  }

  DBG("phoff = %d, phentsz = %d, phnum = %d\n",
      ehdr.e_phoff, ehdr.e_phentsize, ehdr.e_phnum);

  if(lseek(fd, ehdr.e_phoff, SEEK_SET)<0 ||
     read(fd, &phdr, sizeof(phdr)) != sizeof(phdr)) {
    seterror("Program header load failed.");
    return false;
  }

  if(phdr.p_type != 1 || phdr.p_vaddr != 0 || phdr.p_paddr != 0 ||
     phdr.p_filesz > phdr.p_memsz) {
    seterror("Invalid program header.");
    return false;
  }

  DBG("offs = %d, filesz = %d, memsz = %d, align = %d\n",
      phdr.p_offset, phdr.p_filesz, phdr.p_memsz, phdr.p_align);

  if(!(segment = memalign(phdr.p_align, phdr.p_memsz))) {
    seterror("Out of memory.");
    return false;
  }

  DBG("segment @ %p\n", segment);

  if(lseek(fd, phdr.p_offset, SEEK_SET)<0 ||
     read(fd, segment, phdr.p_filesz) != phdr.p_filesz) {
    seterror("Segment load failed.");
    return false;
  }  

  DBG("shoff = %d, shentsz = %d, shnum = %d\n",
      ehdr.e_shoff, ehdr.e_shentsize, ehdr.e_shnum);

  if(!(shdr = (Elf32_Shdr *)malloc(ehdr.e_shnum * sizeof(*shdr)))) {
    seterror("Out of memory.");
    return false;
  }

  if(lseek(fd, ehdr.e_shoff, SEEK_SET)<0 ||
     read(fd, shdr, ehdr.e_shnum * sizeof(*shdr)) !=
     ehdr.e_shnum * sizeof(*shdr)) {
    seterror("Section headers load failed.");
    free(shdr);
    return false;
  }

  for(int i=0; i<ehdr.e_shnum; i++) {
    DBG("Section %d: type = %d, size = %d, entsize = %d, link = %d\n",
	i, shdr[i].sh_type, shdr[i].sh_size, shdr[i].sh_entsize, shdr[i].sh_link);
    if(shdr[i].sh_type == 2 && shdr[i].sh_entsize == sizeof(Elf32_Sym) &&
       shdr[i].sh_link < ehdr.e_shnum && shdr[shdr[i].sh_link].sh_type == 3 &&
       symtab_sect < 0)
      symtab_sect = i;
  }

  if(symtab_sect < 0) {
    seterror("No symbol table.");
    free(shdr);
    return false;
  }

  if(!(symtab = malloc(shdr[symtab_sect].sh_size))) {
    seterror("Out of memory.");
    free(shdr);
    return false;
  }

  if(lseek(fd, shdr[symtab_sect].sh_offset, SEEK_SET)<0 ||
     read(fd, symtab, shdr[symtab_sect].sh_size) != shdr[symtab_sect].sh_size){
    seterror("Symbol table load failed.");
    free(shdr);
    return false;
  }

  if(!(strtab = (char *)malloc(shdr[shdr[symtab_sect].sh_link].sh_size))) {
    seterror("Out of memory.");
    free(shdr);
    return false;
  }

  if(lseek(fd, shdr[shdr[symtab_sect].sh_link].sh_offset, SEEK_SET)<0 ||
     read(fd, strtab, shdr[shdr[symtab_sect].sh_link].sh_size) !=
     shdr[shdr[symtab_sect].sh_link].sh_size){
    seterror("Symbol table strings load failed.");
    free(shdr);
    return false;
  }

  symbol_cnt = shdr[symtab_sect].sh_size / sizeof(Elf32_Sym);
  DBG("Loaded %d symbols.\n", symbol_cnt);

  Elf32_Sym *s = (Elf32_Sym *)symtab;
  for(int c = symbol_cnt; c--; s++)
    if(s->st_shndx < 0xff00)
      s->st_value += (Elf32_Addr)segment;

  for(int i=0; i<ehdr.e_shnum; i++)
    if(shdr[i].sh_type == 4 && shdr[i].sh_entsize == sizeof(Elf32_Rela) &&
       shdr[i].sh_link == symtab_sect)
      if(!relocate(fd, shdr[i].sh_offset, shdr[i].sh_size)) {
	free(shdr);
	return false;
      }
  
  free(shdr);

  return true;
}

bool DLObject::open(const char *path)
{
  int fd;
  void *ctors_start, *ctors_end;

  DBG("open(\"%s\")\n", path);

  if((fd = ::open(path, O_RDONLY))<0) {
    seterror("%s not found.", path);
    return false;
  }

  if(!load(fd)) {
    ::close(fd);
    unload();
    return false;
  }

  ::close(fd);

  purge_copyback();
  flush_instruction_cache();

  ctors_start = symbol("__plugin_ctors");
  ctors_end = symbol("__plugin_ctors_end");
  dtors_start = symbol("__plugin_dtors");
  dtors_end = symbol("__plugin_dtors_end");

  if(ctors_start == NULL || ctors_end == NULL || dtors_start == NULL ||
     dtors_end == NULL) {
    seterror("Missing ctors/dtors.");
    dtors_start = dtors_end = NULL;
    unload();
    return false;    
  }

  DBG("Calling constructors.\n");
  for(void (**f)(void) = (void (**)(void))ctors_start; f != ctors_end; f++)
    (**f)();

  DBG("%s opened ok.\n", path);
  return true;
}

bool DLObject::close()
{
  if(dtors_start != NULL && dtors_end != NULL)
    for(void (**f)(void) = (void (**)(void))dtors_start; f != dtors_end; f++)
      (**f)();
  dtors_start = dtors_end = NULL;
  unload();
  return true;
}

void *DLObject::symbol(const char *name)
{
  DBG("symbol(\"%s\")\n", name);

  if(symtab == NULL || strtab == NULL || symbol_cnt < 1) {
    seterror("No symbol table loaded.");
    return NULL;
  }

  Elf32_Sym *s = (Elf32_Sym *)symtab;
  for(int c = symbol_cnt; c--; s++)
    if((s->st_info>>4 == 1 || s->st_info>>4 == 2) &&
       strtab[s->st_name] == '_' && !strcmp(name, strtab+s->st_name+1)) {
      DBG("=> %p\n", (void*)s->st_value);
      return (void*)s->st_value;
    }

  seterror("Symbol \"%s\" not found.", name);
  return NULL;  
}


static char dlerr[MAXDLERRLEN];

void *dlopen(const char *filename, int flags)
{
  DLObject *obj = new DLObject(dlerr);
  if(obj->open(filename))
    return (void *)obj;
  delete obj;
  return NULL;
}

int dlclose(void *handle)
{
  DLObject *obj = (DLObject *)handle;
  if(obj == NULL) {
    strcpy(dlerr, "Handle is NULL.");
    return -1;
  }
  if(obj->close()) {
    delete obj;
    return 0;
  }
  return -1;
}

void *dlsym(void *handle, const char *symbol)
{
  if(handle == NULL) {
    strcpy(dlerr, "Handle is NULL.");
    return NULL;
  }
  return ((DLObject *)handle)->symbol(symbol);
}

const char *dlerror()
{
  return dlerr;
}

void dlforgetsyms(void *handle)
{
  if(handle != NULL)
    ((DLObject *)handle)->discard_symtab();
}

--- NEW FILE: dcloader.h ---
/* ScummVM - Scumm Interpreter
 * Dreamcast port
 * Copyright (C) 2002-2004  Marcus Comstedt
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.

 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.

 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 * $Header: /cvsroot/scummvm/scummvm/backends/dc/dcloader.h,v 1.1 2004/08/22 21:47:20 marcus_c Exp $
 *
 */

#ifndef DC_DCLOADER_H
#define DC_DCLOADER_H

#include "dc.h"

#define MAXDLERRLEN 80

class DLObject {
 private:
  char *errbuf; /* For error messages, at least MAXDLERRLEN in size */

  void *segment, *symtab;
  char *strtab;
  int symbol_cnt;
  void *dtors_start, *dtors_end;

  void seterror(const char *fmt, ...);
  void unload();
  bool relocate(int fd, unsigned long offset, unsigned long size);
  bool load(int fd);

 public:
  bool open(const char *path);
  bool close();
  void *symbol(const char *name);
  void discard_symtab();

  DLObject(char *_errbuf = NULL) : errbuf(_errbuf), segment(NULL),symtab(NULL),
    strtab(NULL), symbol_cnt(0), dtors_start(NULL), dtors_end(NULL) {}
};

#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

--- NEW FILE: plugin.syms ---
_PLUGIN_createEngine
_PLUGIN_detectGames
_PLUGIN_getSupportedGames
_PLUGIN_name
___plugin_ctors
___plugin_ctors_end
___plugin_dtors
___plugin_dtors_end

--- NEW FILE: plugin.x ---
OUTPUT_FORMAT("elf32-shl", "elf32-shl", "elf32-shl")
OUTPUT_ARCH(sh)
SECTIONS
{
  . = 0;
  .text           :
  {
    *(.text .stub .text.* .gnu.linkonce.t.*)
    *(.gnu.warning)
  } =0
  .rodata         : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
  .rodata1        : { *(.rodata1) }
  .sdata2         : { *(.sdata2 .sdata2.* .gnu.linkonce.s2.*) }
  .sbss2          : { *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) }
  .data           :
  {
    *(.data .data.* .gnu.linkonce.d.*)
    SORT(CONSTRUCTORS)
  }
  .data1          : { *(.data1) }
  .tdata	  : { *(.tdata .tdata.* .gnu.linkonce.td.*) }
  .tbss		  : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
  .eh_frame       : { KEEP (*(.eh_frame)) }
  .gcc_except_table   : { *(.gcc_except_table) }
  .ctors          :
  {
    ___plugin_ctors = .;
    KEEP (*(SORT(.ctors.*)))
    KEEP (*(.ctors))
    ___plugin_ctors_end = .;
  }
  .dtors          :
  {
    ___plugin_dtors = .;
    KEEP (*(SORT(.dtors.*)))
    KEEP (*(.dtors))
    ___plugin_dtors_end = .;
  }
  .sdata          :
  {
    *(.sdata .sdata.* .gnu.linkonce.s.*)
  }
  .sbss           :
  {
    *(.dynsbss)
    *(.sbss .sbss.* .gnu.linkonce.sb.*)
    *(.scommon)
  }
  .bss            :
  {
   *(.dynbss)
   *(.bss .bss.* .gnu.linkonce.b.*)
   *(COMMON)
  }
}

Index: .cvsignore
===================================================================
RCS file: /cvsroot/scummvm/scummvm/backends/dc/.cvsignore,v
retrieving revision 1.9
retrieving revision 1.10
diff -u -d -r1.9 -r1.10
--- .cvsignore	20 Aug 2004 21:44:07 -0000	1.9
+++ .cvsignore	22 Aug 2004 21:47:20 -0000	1.10
@@ -14,3 +14,4 @@
 base
 backends
 scummvm.elf
+*.plg

Index: Makefile
===================================================================
RCS file: /cvsroot/scummvm/scummvm/backends/dc/Makefile,v
retrieving revision 1.23
retrieving revision 1.24
diff -u -d -r1.23 -r1.24
--- Makefile	14 Mar 2004 22:16:22 -0000	1.23
+++ Makefile	22 Aug 2004 21:47:20 -0000	1.24
@@ -2,9 +2,12 @@
 
 ronindir = /usr/local/ronin
 
+# BUILD_PLUGINS = 1
+
 srcdir = ../..
 VPATH = $(srcdir)
 
+CC      = sh-elf-gcc -ml -m4-single-only
 CXX     = sh-elf-g++ -ml -m4-single-only
 CXXFLAGS= -O3 -Wno-multichar -funroll-loops -fschedule-insns2 -fomit-frame-pointer -fdelete-null-pointer-checks -fno-exceptions
 DEFINES = -D__DC__ -DNONSTANDARD_PORT
@@ -12,6 +15,10 @@
 INCLUDES= -I./ -I$(srcdir) -I$(srcdir)/common -I$(ronindir)/include/
 LIBS	= -L$(ronindir)/lib -lronin-netcd -lz -lm
 EXECUTABLE = scummvm.elf
+PLUGIN_PREFIX =
+PLUGIN_SUFFIX = .plg
+PLUGIN_EXTRA_DEPS = plugin.x plugin.syms scummvm.elf
+PLUGIN_LDFLAGS = -nostartfiles -Wl,-q,-Tplugin.x,--just-symbols,scummvm.elf,--retain-symbols-file,plugin.syms -L$(ronindir)/lib
 MKDIR = mkdir -p
 RM = rm -f
 RM_REC = rm -rf
@@ -19,10 +26,17 @@
 RANLIB = sh-elf-ranlib
 HAVE_GCC3 = true
 
+ifdef BUILD_PLUGINS
+DEFINES += -DDYNAMIC_MODULES
+endif
+
 OBJS :=	dcmain.o time.o display.o audio.o input.o selector.o icon.o \
-	label.o vmsave.o softkbd.o
+	label.o vmsave.o softkbd.o dcloader.o cache.o
 
 MODULE_DIRS += .
 
 include $(srcdir)/Makefile.common
 
+scummvm.bin : scummvm.elf
+	sh-elf-objcopy -S -R .stack -O binary $< $@
+





More information about the Scummvm-git-logs mailing list