1360 lines
		
	
	
		
			36 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			1360 lines
		
	
	
		
			36 KiB
		
	
	
	
		
			C
		
	
	
	
/* $XFree86: xc/programs/Xserver/hw/xfree86/loader/coffloader.c,v 1.21tsi Exp $ */
 | 
						|
 | 
						|
/*
 | 
						|
 *
 | 
						|
 * Copyright 1995,96 by Metro Link, Inc.
 | 
						|
 *
 | 
						|
 * Permission to use, copy, modify, distribute, and sell this software and its
 | 
						|
 * documentation for any purpose is hereby granted without fee, provided that
 | 
						|
 * the above copyright notice appear in all copies and that both that
 | 
						|
 * copyright notice and this permission notice appear in supporting
 | 
						|
 * documentation, and that the name of Metro Link, Inc. not be used in
 | 
						|
 * advertising or publicity pertaining to distribution of the software without
 | 
						|
 * specific, written prior permission.  Metro Link, Inc. makes no
 | 
						|
 * representations about the suitability of this software for any purpose.
 | 
						|
 *  It is provided "as is" without express or implied warranty.
 | 
						|
 *
 | 
						|
 * METRO LINK, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 | 
						|
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
 | 
						|
 * EVENT SHALL METRO LINK, INC. BE LIABLE FOR ANY SPECIAL, INDIRECT OR
 | 
						|
 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
 | 
						|
 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
 | 
						|
 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 | 
						|
 * PERFORMANCE OF THIS SOFTWARE.
 | 
						|
 */
 | 
						|
#ifdef HAVE_XORG_CONFIG_H
 | 
						|
#include <xorg-config.h>
 | 
						|
#endif
 | 
						|
 | 
						|
#include <sys/types.h>
 | 
						|
#include <unistd.h>
 | 
						|
#include <stdlib.h>
 | 
						|
#ifdef __QNX__
 | 
						|
#include <fcntl.h>
 | 
						|
#else
 | 
						|
#include <sys/fcntl.h>
 | 
						|
#endif
 | 
						|
#include <sys/stat.h>
 | 
						|
 | 
						|
#ifdef DBMALLOC
 | 
						|
#include <debug/malloc.h>
 | 
						|
#define Xalloc(size) malloc(size)
 | 
						|
#define Xcalloc(size) calloc(1,(size))
 | 
						|
#define Xfree(size) free(size)
 | 
						|
#endif
 | 
						|
 | 
						|
#include <X11/Xos.h>
 | 
						|
#include "os.h"
 | 
						|
#include "coff.h"
 | 
						|
 | 
						|
#include "sym.h"
 | 
						|
#include "loader.h"
 | 
						|
#include "coffloader.h"
 | 
						|
 | 
						|
#include "compiler.h"
 | 
						|
 | 
						|
#ifndef LOADERDEBUG
 | 
						|
#define LOADERDEBUG 0
 | 
						|
#endif
 | 
						|
 | 
						|
#if LOADERDEBUG
 | 
						|
#define COFFDEBUG ErrorF
 | 
						|
#endif
 | 
						|
 | 
						|
/*
 | 
						|
 * This structure contains all of the information about a module
 | 
						|
 * that has been loaded.
 | 
						|
 */
 | 
						|
 | 
						|
typedef struct {
 | 
						|
    int handle;
 | 
						|
    long module;		/* Id of the module used to find inter module calls */
 | 
						|
    int fd;
 | 
						|
    loader_funcs *funcs;
 | 
						|
    FILHDR *header;		/* file header */
 | 
						|
    AOUTHDR *optheader;		/* optional file header */
 | 
						|
    unsigned short numsh;
 | 
						|
    SCNHDR *sections;		/* Start address of the section table */
 | 
						|
    int secsize;		/* size of the section table */
 | 
						|
    unsigned char **saddr;	/* Start addresss of the sections table */
 | 
						|
    unsigned char **reladdr;	/* Start addresss of the relocation table */
 | 
						|
    unsigned char *strtab;	/* Start address of the string table */
 | 
						|
    int strsize;		/* size of the string table */
 | 
						|
    unsigned char *text;	/* Start address of the .text section */
 | 
						|
    int txtndx;			/* index of the .text section */
 | 
						|
    long txtaddr;		/* offset of the .text section */
 | 
						|
    int txtsize;		/* size of the .text section */
 | 
						|
    int txtrelsize;		/* size of the .rel.text section */
 | 
						|
    unsigned char *data;	/* Start address of the .data section */
 | 
						|
    int datndx;			/* index of the .data section */
 | 
						|
    long dataddr;		/* offset of the .data section */
 | 
						|
    int datsize;		/* size of the .data section */
 | 
						|
    int datrelsize;		/* size of the .rel.data section */
 | 
						|
    unsigned char *bss;		/* Start address of the .bss section */
 | 
						|
    int bssndx;			/* index of the .bss section */
 | 
						|
    long bssaddr;		/* offset of the .bss section */
 | 
						|
    int bsssize;		/* size of the .bss section */
 | 
						|
    SYMENT *symtab;		/* Start address of the .symtab section */
 | 
						|
    int symndx;			/* index of the .symtab section */
 | 
						|
    int symsize;		/* size of the .symtab section */
 | 
						|
    unsigned char *common;	/* Start address of the .common section */
 | 
						|
    int comsize;		/* size of the .common section */
 | 
						|
    long toc;			/* Offset of the TOC csect */
 | 
						|
    unsigned char *tocaddr;	/* Address of the TOC csect */
 | 
						|
} COFFModuleRec, *COFFModulePtr;
 | 
						|
 | 
						|
/*
 | 
						|
 * If any relocation is unable to be satisfied, then put it on a list
 | 
						|
 * to try later after more modules have been loaded.
 | 
						|
 */
 | 
						|
typedef struct _coff_reloc {
 | 
						|
    COFFModulePtr file;
 | 
						|
    RELOC *rel;
 | 
						|
    int secndx;
 | 
						|
    struct _coff_reloc *next;
 | 
						|
} COFFRelocRec;
 | 
						|
 | 
						|
/*
 | 
						|
 * Symbols with a section number of 0 (N_UNDEF) but a value of non-zero
 | 
						|
 * need to have space allocated for them.
 | 
						|
 *
 | 
						|
 * Gather all of these symbols together, and allocate one chunk when we
 | 
						|
 * are done.
 | 
						|
 */
 | 
						|
 | 
						|
typedef struct _coff_COMMON {
 | 
						|
    SYMENT *sym;
 | 
						|
    int index;
 | 
						|
    struct _coff_COMMON *next;
 | 
						|
} COFFCommonRec;
 | 
						|
 | 
						|
static COFFCommonPtr listCOMMON = NULL;
 | 
						|
 | 
						|
/* Prototypes for static functions */
 | 
						|
static int COFFhashCleanOut(void *, itemPtr);
 | 
						|
static char *COFFGetSymbolName(COFFModulePtr, int);
 | 
						|
static COFFCommonPtr COFFAddCOMMON(SYMENT *, int);
 | 
						|
static LOOKUP *COFFCreateCOMMON(COFFModulePtr);
 | 
						|
static COFFRelocPtr COFFDelayRelocation(COFFModulePtr, int, RELOC *);
 | 
						|
static SYMENT *COFFGetSymbol(COFFModulePtr, int);
 | 
						|
#if defined(i386) || defined(__powerpc__)
 | 
						|
static unsigned char *COFFGetSymbolValue(COFFModulePtr, int);
 | 
						|
#endif
 | 
						|
static COFFRelocPtr COFF_RelocateEntry(COFFModulePtr, int, RELOC *);
 | 
						|
static LOOKUP *COFF_GetSymbols(COFFModulePtr);
 | 
						|
static void COFFCollectSections(COFFModulePtr);
 | 
						|
static COFFRelocPtr COFFCollectRelocations(COFFModulePtr);
 | 
						|
 | 
						|
/*
 | 
						|
 * Utility Functions
 | 
						|
 */
 | 
						|
 | 
						|
static int
 | 
						|
COFFhashCleanOut(void *voidptr, itemPtr item)
 | 
						|
{
 | 
						|
    COFFModulePtr module = (COFFModulePtr) voidptr;
 | 
						|
 | 
						|
    return (module->handle == item->handle);
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * Manage listResolv
 | 
						|
 */
 | 
						|
static COFFRelocPtr
 | 
						|
COFFDelayRelocation(COFFModulePtr cofffile, int secndx, RELOC *rel)
 | 
						|
{
 | 
						|
    COFFRelocPtr reloc;
 | 
						|
 | 
						|
    if ((reloc = xf86loadermalloc(sizeof(COFFRelocRec))) == NULL) {
 | 
						|
	ErrorF("COFFDelayRelocation() Unable to allocate memory!!!!\n");
 | 
						|
	return 0;
 | 
						|
    }
 | 
						|
 | 
						|
    reloc->file = cofffile;
 | 
						|
    reloc->secndx = secndx;
 | 
						|
    reloc->rel = rel;
 | 
						|
    reloc->next = 0;
 | 
						|
 | 
						|
    return reloc;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * Manage listCOMMON
 | 
						|
 */
 | 
						|
 | 
						|
static COFFCommonPtr
 | 
						|
COFFAddCOMMON(SYMENT *sym, int index)
 | 
						|
{
 | 
						|
    COFFCommonPtr common;
 | 
						|
 | 
						|
    if ((common = xf86loadermalloc(sizeof(COFFCommonRec))) == NULL) {
 | 
						|
	ErrorF("COFFAddCOMMON() Unable to allocate memory!!!!\n");
 | 
						|
	return 0;
 | 
						|
    }
 | 
						|
    common->sym = sym;
 | 
						|
    common->index = index;
 | 
						|
    common->next = 0;
 | 
						|
 | 
						|
    return common;
 | 
						|
}
 | 
						|
 | 
						|
static LOOKUP *
 | 
						|
COFFCreateCOMMON(COFFModulePtr cofffile)
 | 
						|
{
 | 
						|
    int numsyms = 0, size = 0, l = 0;
 | 
						|
    int offset = 0;
 | 
						|
    LOOKUP *lookup;
 | 
						|
    COFFCommonPtr common;
 | 
						|
 | 
						|
    if (listCOMMON == NULL)
 | 
						|
	return NULL;
 | 
						|
 | 
						|
    common = listCOMMON;
 | 
						|
    for (common = listCOMMON; common; common = common->next) {
 | 
						|
	/* Ensure long word alignment */
 | 
						|
	if (common->sym->n_value != 2 && common->sym->n_value != 1)	/* But not for short and char ;-)(mr) */
 | 
						|
	    if (common->sym->n_value % 4 != 0)
 | 
						|
		common->sym->n_value += 4 - (common->sym->n_value % 4);
 | 
						|
 | 
						|
	/* accumulate the sizes */
 | 
						|
	size += common->sym->n_value;
 | 
						|
	numsyms++;
 | 
						|
    }
 | 
						|
 | 
						|
#ifdef COFFDEBUG
 | 
						|
    COFFDEBUG("COFFCreateCOMMON() %d entries (%d bytes) of COMMON data\n",
 | 
						|
	      numsyms, size);
 | 
						|
#endif
 | 
						|
 | 
						|
    if ((lookup = xf86loadermalloc((numsyms + 1) * sizeof(LOOKUP))) == NULL) {
 | 
						|
	ErrorF("COFFCreateCOMMON() Unable to allocate memory!!!!\n");
 | 
						|
	return NULL;
 | 
						|
    }
 | 
						|
 | 
						|
    cofffile->comsize = size;
 | 
						|
    if ((cofffile->common = xf86loadercalloc(1, size)) == NULL) {
 | 
						|
	ErrorF("COFFCreateCOMMON() Unable to allocate memory!!!!\n");
 | 
						|
	return NULL;
 | 
						|
    }
 | 
						|
 | 
						|
    /* Traverse the common list and create a lookup table with all the
 | 
						|
     * common symbols.  Destroy the common list in the process.
 | 
						|
     * See also ResolveSymbols.
 | 
						|
     */
 | 
						|
    while (listCOMMON) {
 | 
						|
	common = listCOMMON;
 | 
						|
	lookup[l].symName = COFFGetSymbolName(cofffile, common->index);
 | 
						|
	lookup[l].offset = (funcptr) (cofffile->common + offset);
 | 
						|
#ifdef COFFDEBUG
 | 
						|
	COFFDEBUG("Adding %p %s\n", (void *)lookup[l].offset,
 | 
						|
		  lookup[l].symName);
 | 
						|
#endif
 | 
						|
	listCOMMON = common->next;
 | 
						|
	offset += common->sym->n_value;
 | 
						|
	xf86loaderfree(common);
 | 
						|
	l++;
 | 
						|
    }
 | 
						|
    /* listCOMMON == NULL */
 | 
						|
 | 
						|
    lookup[l].symName = NULL;	/* Terminate the list */
 | 
						|
    return lookup;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * Symbol Table
 | 
						|
 */
 | 
						|
 | 
						|
/*
 | 
						|
 * Get symbol name
 | 
						|
 */
 | 
						|
static char *
 | 
						|
COFFGetSymbolName(COFFModulePtr cofffile, int index)
 | 
						|
{
 | 
						|
    char *name;
 | 
						|
    SYMENT *sym;
 | 
						|
 | 
						|
    sym = (SYMENT *) (((unsigned char *)cofffile->symtab) + (index * SYMESZ));
 | 
						|
 | 
						|
#ifdef COFFDEBUG
 | 
						|
    COFFDEBUG("COFFGetSymbolName(%p,%x) %lx", (void *)cofffile, index,
 | 
						|
	      sym->n_zeroes);
 | 
						|
#endif
 | 
						|
 | 
						|
    name = xf86loadermalloc(sym->n_zeroes ? SYMNMLEN + 1
 | 
						|
			    : strlen((const char *)&cofffile->
 | 
						|
				     strtab[(int)sym->n_offset - 4]) + 1);
 | 
						|
    if (!name)
 | 
						|
	FatalError("COFFGetSymbolName: Out of memory\n");
 | 
						|
 | 
						|
    if (sym->n_zeroes) {
 | 
						|
	strncpy(name, sym->n_name, SYMNMLEN);
 | 
						|
	name[SYMNMLEN] = '\000';
 | 
						|
    } else {
 | 
						|
	strcpy(name, (const char *)&cofffile->strtab[(int)sym->n_offset - 4]);
 | 
						|
    }
 | 
						|
#ifdef COFFDEBUG
 | 
						|
    COFFDEBUG(" %s\n", name);
 | 
						|
#endif
 | 
						|
    return name;
 | 
						|
}
 | 
						|
 | 
						|
static SYMENT *
 | 
						|
COFFGetSymbol(COFFModulePtr file, int index)
 | 
						|
{
 | 
						|
    return (SYMENT *) (((unsigned char *)file->symtab) + (index * SYMESZ));
 | 
						|
}
 | 
						|
 | 
						|
#if defined(i386) || defined(__powerpc__)
 | 
						|
static unsigned char *
 | 
						|
COFFGetSymbolValue(COFFModulePtr cofffile, int index)
 | 
						|
{
 | 
						|
    unsigned char *symval = 0;	/* value of the indicated symbol */
 | 
						|
    itemPtr symbol;		/* name/value of symbol */
 | 
						|
    char *symname;
 | 
						|
 | 
						|
    symname = COFFGetSymbolName(cofffile, index);
 | 
						|
 | 
						|
#ifdef COFFDEBUG
 | 
						|
    COFFDEBUG("COFFGetSymbolValue() for %s=", symname);
 | 
						|
#endif
 | 
						|
 | 
						|
    symbol = LoaderHashFind(symname);
 | 
						|
 | 
						|
    if (symbol)
 | 
						|
	symval = (unsigned char *)symbol->address;
 | 
						|
 | 
						|
#ifdef COFFDEBUG
 | 
						|
    COFFDEBUG("%p\n", symval);
 | 
						|
#endif
 | 
						|
 | 
						|
    xf86loaderfree(symname);
 | 
						|
    return symval;
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
#if defined(__powerpc__)
 | 
						|
/*
 | 
						|
 * This function returns the address of the glink routine for a symbol. This
 | 
						|
 * address is used in cases where the function being called is not in the
 | 
						|
 * same module as the calling function.
 | 
						|
 */
 | 
						|
static unsigned char *
 | 
						|
COFFGetSymbolGlinkValue(COFFModulePtr cofffile, int index)
 | 
						|
{
 | 
						|
    unsigned char *symval = 0;	/* value of the indicated symbol */
 | 
						|
    itemPtr symbol;		/* name/value of symbol */
 | 
						|
    char *name;
 | 
						|
 | 
						|
    name = COFFGetSymbolName(cofffile, index);
 | 
						|
 | 
						|
#ifdef COFFDEBUG
 | 
						|
    COFFDEBUG("COFFGetSymbolGlinkValue() for %s=", name);
 | 
						|
#endif
 | 
						|
 | 
						|
    symbol = LoaderHashFind(name + 1);	/* Eat the '.' so we get the
 | 
						|
					 * Function descriptor instead */
 | 
						|
 | 
						|
/* Here we are building up a glink function that will change the TOC
 | 
						|
 * pointer before calling a function that resides in a different module.
 | 
						|
 * The following code is being used to implement this.
 | 
						|
 | 
						|
	1 00000000 3d80xxxx	lis   r12,hi16(funcdesc)
 | 
						|
	2 00000004 618cxxxx	ori   r12,r12,lo16(funcdesc)
 | 
						|
	3 00000008 90410014	st    r2,20(r1)	# save old TOC pointer
 | 
						|
	4 0000000c 804c0000 	l     r2,0(r12)	# Get address of functions
 | 
						|
	5 00000010 7c4903a6	mtctr  r2	# load destination address
 | 
						|
	6 00000014 804c0004	l     r2,4(r12)	# get TOC of function
 | 
						|
	7 00000018 4e800420	bctr		# branch to it
 | 
						|
 | 
						|
 */
 | 
						|
    if (symbol) {
 | 
						|
	symval = (unsigned char *)&symbol->code.glink;
 | 
						|
#ifdef COFFDEBUG
 | 
						|
	COFFDEBUG("%x\n", symval);
 | 
						|
	COFFDEBUG("glink_%s=%x\n", name, symval);
 | 
						|
#endif
 | 
						|
	symbol->code.glink[0] = 0x3d80;	/* lis r12 */
 | 
						|
	symbol->code.glink[1] =
 | 
						|
		((unsigned long)symbol->address & 0xffff0000) >> 16;
 | 
						|
	symbol->code.glink[2] = 0x618c;	/* ori r12 */
 | 
						|
	symbol->code.glink[3] = ((unsigned long)symbol->address & 0x0000ffff);
 | 
						|
	symbol->code.glink[4] = 0x9041;	/* st r2,20(r1) */
 | 
						|
	symbol->code.glink[5] = 0x0014;
 | 
						|
	symbol->code.glink[6] = 0x804c;	/* l r2,0(r12) */
 | 
						|
	symbol->code.glink[7] = 0x0000;
 | 
						|
	symbol->code.glink[8] = 0x7c49;	/* mtctr r2 */
 | 
						|
	symbol->code.glink[9] = 0x03a6;
 | 
						|
	symbol->code.glink[10] = 0x804c;	/* l r2,4(r12) */
 | 
						|
	symbol->code.glink[11] = 0x0004;
 | 
						|
	symbol->code.glink[12] = 0x4e80;	/* bctr */
 | 
						|
	symbol->code.glink[13] = 0x0420;
 | 
						|
	ppc_flush_icache(&symbol->code.glink[0]);
 | 
						|
	ppc_flush_icache(&symbol->code.glink[12]);
 | 
						|
    }
 | 
						|
 | 
						|
    xf86loaderfree(name);
 | 
						|
    return symval;
 | 
						|
}
 | 
						|
#endif /* __powerpc__ */
 | 
						|
 | 
						|
/*
 | 
						|
 * Fix all of the relocation for the given section.
 | 
						|
 */
 | 
						|
static COFFRelocPtr
 | 
						|
COFF_RelocateEntry(COFFModulePtr cofffile, int secndx, RELOC *rel)
 | 
						|
{
 | 
						|
    SYMENT *symbol;		/* value of the indicated symbol */
 | 
						|
    unsigned long *dest32;	/* address of the place being modified */
 | 
						|
 | 
						|
#if defined(__powerpc__)
 | 
						|
    unsigned short *dest16;	/* address of the place being modified */
 | 
						|
    itemPtr symitem;		/* symbol structure from has table */
 | 
						|
    char *name;
 | 
						|
#endif
 | 
						|
    unsigned char *symval;	/* value of the indicated symbol */
 | 
						|
 | 
						|
/*
 | 
						|
 * Note: Section numbers are 1 biased, while the cofffile->saddr[] array
 | 
						|
 * of pointer is 0 biased, so alway have to account for the difference.
 | 
						|
 */
 | 
						|
 | 
						|
/* 
 | 
						|
 * Reminder: secndx is the section to which the relocation is applied.
 | 
						|
 *           symbol->n_scnum is the section in which the symbol value resides.
 | 
						|
 */
 | 
						|
 | 
						|
#ifdef COFFDEBUG
 | 
						|
    COFFDEBUG("%lx %ld %o ", (unsigned long)rel->r_vaddr,
 | 
						|
	      rel->r_symndx, rel->r_type);
 | 
						|
#if defined(__powerpc__)
 | 
						|
    COFFDEBUG("[%x %x %x] ",
 | 
						|
	      RELOC_RSIGN(*rel), RELOC_RFIXUP(*rel), RELOC_RLEN(*rel));
 | 
						|
#endif
 | 
						|
#endif
 | 
						|
    symbol = COFFGetSymbol(cofffile, rel->r_symndx);
 | 
						|
#ifdef COFFDEBUG
 | 
						|
    COFFDEBUG("%d %lx %d-%d\n", symbol->n_sclass, symbol->n_value,
 | 
						|
	      symbol->n_scnum, secndx);
 | 
						|
#endif
 | 
						|
 | 
						|
/*
 | 
						|
 * Check to see if the relocation offset is part of the .text segment.
 | 
						|
 * If not, we must change the offset to be relative to the .data section
 | 
						|
 * which is NOT contiguous.
 | 
						|
 */
 | 
						|
    switch (secndx + 1) {	/* change the bias */
 | 
						|
    case N_TEXT:
 | 
						|
	if ((long)rel->r_vaddr < cofffile->txtaddr ||
 | 
						|
	    (long)rel->r_vaddr >
 | 
						|
	    (long)(cofffile->txtaddr + cofffile->txtsize)) {
 | 
						|
	    FatalError("Relocation against N_TEXT not in .text section\n");
 | 
						|
	}
 | 
						|
	dest32 = (unsigned long *)((long)(cofffile->saddr[secndx]) +
 | 
						|
				   ((unsigned char *)rel->r_vaddr -
 | 
						|
				    cofffile->txtaddr));
 | 
						|
	break;
 | 
						|
    case N_DATA:
 | 
						|
	if ((long)rel->r_vaddr < cofffile->dataddr ||
 | 
						|
	    (long)rel->r_vaddr >
 | 
						|
	    (long)(cofffile->dataddr + cofffile->datsize)) {
 | 
						|
	    FatalError("Relocation against N_DATA not in .data section\n");
 | 
						|
	}
 | 
						|
	dest32 = (unsigned long *)((long)(cofffile->saddr[secndx]) +
 | 
						|
				   ((unsigned char *)rel->r_vaddr -
 | 
						|
				    cofffile->dataddr));
 | 
						|
	break;
 | 
						|
    case N_BSS:
 | 
						|
	if ((long)rel->r_vaddr < cofffile->bssaddr ||
 | 
						|
	    (long)rel->r_vaddr >
 | 
						|
	    (long)(cofffile->bssaddr + cofffile->bsssize)) {
 | 
						|
	    FatalError("Relocation against N_TEXT not in .bss section\n");
 | 
						|
	}
 | 
						|
	dest32 = (unsigned long *)((long)(cofffile->saddr[secndx]) +
 | 
						|
				   ((unsigned char *)rel->r_vaddr -
 | 
						|
				    cofffile->bssaddr));
 | 
						|
	break;
 | 
						|
    default:
 | 
						|
	FatalError("Relocation against unknown section %d\n", secndx);
 | 
						|
    }
 | 
						|
 | 
						|
    if (symbol->n_sclass == 0) {
 | 
						|
	symval = (unsigned char *)(symbol->n_value + (*dest32) -
 | 
						|
				   symbol->n_type);
 | 
						|
#ifdef COFFDEBUG
 | 
						|
	COFFDEBUG("symbol->n_sclass==0\n");
 | 
						|
	COFFDEBUG("dest32=%p\t", (void *)dest32);
 | 
						|
	COFFDEBUG("symval=%p\t", symval);
 | 
						|
	COFFDEBUG("*dest32=%8.8lx\t", *dest32);
 | 
						|
#endif
 | 
						|
	*dest32 = (unsigned long)symval;
 | 
						|
	return 0;
 | 
						|
    }
 | 
						|
 | 
						|
    switch (rel->r_type) {
 | 
						|
#if defined(i386)
 | 
						|
    case R_DIR32:
 | 
						|
	symval = COFFGetSymbolValue(cofffile, rel->r_symndx);
 | 
						|
	if (symval) {
 | 
						|
#ifdef COFFDEBUG
 | 
						|
	    char *namestr;
 | 
						|
 | 
						|
	    COFFDEBUG("R_DIR32 %s\n",
 | 
						|
		      namestr = COFFGetSymbolName(cofffile, rel->r_symndx));
 | 
						|
	    xf86loaderfree(namestr);
 | 
						|
	    COFFDEBUG("txtsize=%x\t", cofffile->txtsize);
 | 
						|
	    COFFDEBUG("dest32=%p\t", (void *)dest32);
 | 
						|
	    COFFDEBUG("symval=%p\t", symval);
 | 
						|
	    COFFDEBUG("*dest32=%8.8lx\t", *dest32);
 | 
						|
#endif
 | 
						|
	    *dest32 = (unsigned long)(symval + (*dest32) - symbol->n_value);
 | 
						|
	} else {
 | 
						|
	    switch (symbol->n_scnum) {
 | 
						|
	    case N_UNDEF:
 | 
						|
#ifdef COFFDEBUG
 | 
						|
		COFFDEBUG("R_DIR32 N_UNDEF\n");
 | 
						|
#endif
 | 
						|
		return COFFDelayRelocation(cofffile, secndx, rel);
 | 
						|
	    case N_ABS:
 | 
						|
#ifdef COFFDEBUG
 | 
						|
		COFFDEBUG("R_DIR32 N_ABS\n");
 | 
						|
#endif
 | 
						|
		return 0;
 | 
						|
	    case N_DEBUG:
 | 
						|
#ifdef COFFDEBUG
 | 
						|
		COFFDEBUG("R_DIR32 N_DEBUG\n");
 | 
						|
#endif
 | 
						|
		return 0;
 | 
						|
	    case N_COMMENT:
 | 
						|
#ifdef COFFDEBUG
 | 
						|
		COFFDEBUG("R_DIR32 N_COMMENT\n");
 | 
						|
#endif
 | 
						|
		return 0;
 | 
						|
	    case N_TEXT:
 | 
						|
#ifdef COFFDEBUG
 | 
						|
		COFFDEBUG("R_DIR32 N_TEXT\n");
 | 
						|
		COFFDEBUG("dest32=%p\t", (void *)dest32);
 | 
						|
		COFFDEBUG("symval=%p\t", symval);
 | 
						|
		COFFDEBUG("*dest32=%8.8lx\t", *dest32);
 | 
						|
#endif
 | 
						|
		*dest32 = (unsigned long)((*dest32) +
 | 
						|
					  (unsigned long)(cofffile->
 | 
						|
							  saddr[N_TEXT - 1]));
 | 
						|
		break;
 | 
						|
	    case N_DATA:
 | 
						|
#ifdef COFFDEBUG
 | 
						|
		COFFDEBUG("R_DIR32 N_DATA\n");
 | 
						|
		COFFDEBUG("txtsize=%x\t", cofffile->txtsize);
 | 
						|
		COFFDEBUG("dest32=%p\t", (void *)dest32);
 | 
						|
		COFFDEBUG("symval=%p\t", symval);
 | 
						|
		COFFDEBUG("*dest32=%8.8lx\t", *dest32);
 | 
						|
#endif
 | 
						|
		*dest32 = (unsigned long)((*dest32) +
 | 
						|
					  ((unsigned long)(cofffile->
 | 
						|
							   saddr[N_DATA -
 | 
						|
								 1])) -
 | 
						|
					  cofffile->dataddr);
 | 
						|
		break;
 | 
						|
	    case N_BSS:
 | 
						|
#ifdef COFFDEBUG
 | 
						|
		COFFDEBUG("R_DIR32 N_BSS\n");
 | 
						|
		COFFDEBUG("dest32=%p\t", (void *)dest32);
 | 
						|
		COFFDEBUG("symval=%p\t", symval);
 | 
						|
		COFFDEBUG("*dest32=%8.8lx\t", *dest32);
 | 
						|
#endif
 | 
						|
		*dest32 = (unsigned long)((*dest32) +
 | 
						|
					  (unsigned long)(cofffile->
 | 
						|
							  saddr[N_BSS - 1]) -
 | 
						|
					  (cofffile->bssaddr));
 | 
						|
		break;
 | 
						|
	    default:
 | 
						|
		ErrorF("R_DIR32 with unexpected section %d\n",
 | 
						|
		       symbol->n_scnum);
 | 
						|
	    }
 | 
						|
 | 
						|
	}
 | 
						|
#ifdef COFFDEBUG
 | 
						|
	COFFDEBUG("*dest32=%8.8lx\n", *dest32);
 | 
						|
#endif
 | 
						|
	break;
 | 
						|
    case R_PCRLONG:
 | 
						|
	if (symbol->n_scnum == N_TEXT)
 | 
						|
	    break;
 | 
						|
 | 
						|
	symval = COFFGetSymbolValue(cofffile, rel->r_symndx);
 | 
						|
#ifdef COFFDEBUG
 | 
						|
	COFFDEBUG("R_PCRLONG ");
 | 
						|
	COFFDEBUG("dest32=%p\t", (void *)dest32);
 | 
						|
	COFFDEBUG("symval=%p\t", symval);
 | 
						|
	COFFDEBUG("*dest32=%8.8lx\t", *dest32);
 | 
						|
#endif
 | 
						|
	if (symval == 0) {
 | 
						|
#ifdef COFFDEBUG
 | 
						|
	    char *name;
 | 
						|
 | 
						|
	    COFFDEBUG("***Unable to resolve symbol %s\n",
 | 
						|
		      name = COFFGetSymbolName(cofffile, rel->r_symndx));
 | 
						|
	    xf86loaderfree(name);
 | 
						|
#endif
 | 
						|
	    return COFFDelayRelocation(cofffile, secndx, rel);
 | 
						|
	}
 | 
						|
	*dest32 = (unsigned long)(symval - ((long)dest32 + sizeof(long)));
 | 
						|
 | 
						|
#ifdef COFFDEBUG
 | 
						|
	COFFDEBUG("*dest32=%8.8lx\n", *dest32);
 | 
						|
#endif
 | 
						|
	break;
 | 
						|
    case R_ABS:
 | 
						|
	/*
 | 
						|
	 * Nothing to really do here.
 | 
						|
	 * Usually, a dummy relocation for .file
 | 
						|
	 */
 | 
						|
	break;
 | 
						|
#endif /* i386 */
 | 
						|
#if defined(__powerpc__)
 | 
						|
    case R_POS:
 | 
						|
	/*
 | 
						|
	 * Positive Relocation
 | 
						|
	 */
 | 
						|
	if (RELOC_RLEN(*rel) != 0x1f)
 | 
						|
	    FatalError("R_POS with size != 32 bits");
 | 
						|
	symval = COFFGetSymbolValue(cofffile, rel->r_symndx);
 | 
						|
	if (symval) {
 | 
						|
#ifdef COFFDEBUG
 | 
						|
	    COFFDEBUG("R_POS ");
 | 
						|
	    COFFDEBUG("dest32=%x\t", dest32);
 | 
						|
	    COFFDEBUG("symval=%x\t", symval);
 | 
						|
	    COFFDEBUG("*dest32=%8.8x\t", *dest32);
 | 
						|
#endif
 | 
						|
	    *dest32 = (unsigned long)(symval + (*dest32) - symbol->n_value);
 | 
						|
	    ppc_flush_icache(dest32);
 | 
						|
	} else {
 | 
						|
	    switch (symbol->n_scnum) {
 | 
						|
	    case N_UNDEF:
 | 
						|
#ifdef COFFDEBUG
 | 
						|
		COFFDEBUG("R_POS N_UNDEF\n");
 | 
						|
#endif
 | 
						|
		return COFFDelayRelocation(cofffile, secndx, rel);
 | 
						|
	    case N_ABS:
 | 
						|
#ifdef COFFDEBUG
 | 
						|
		COFFDEBUG("R_POS N_ABS\n");
 | 
						|
#endif
 | 
						|
		return 0;
 | 
						|
	    case N_DEBUG:
 | 
						|
#ifdef COFFDEBUG
 | 
						|
		COFFDEBUG("R_POS N_DEBUG\n");
 | 
						|
#endif
 | 
						|
		return 0;
 | 
						|
	    case N_COMMENT:
 | 
						|
#ifdef COFFDEBUG
 | 
						|
		COFFDEBUG("R_POS N_COMMENT\n");
 | 
						|
#endif
 | 
						|
		return 0;
 | 
						|
	    case N_TEXT:
 | 
						|
#ifdef COFFDEBUG
 | 
						|
		COFFDEBUG("R_POS N_TEXT\n");
 | 
						|
		COFFDEBUG("dest32=%x\t", dest32);
 | 
						|
		COFFDEBUG("symval=%x\t", symval);
 | 
						|
		COFFDEBUG("*dest32=%8.8x\t", *dest32);
 | 
						|
#endif
 | 
						|
		*dest32 = (unsigned long)((*dest32) +
 | 
						|
					  ((unsigned long)(cofffile->
 | 
						|
							   saddr[N_TEXT -
 | 
						|
								 1])) -
 | 
						|
					  cofffile->txtaddr);
 | 
						|
		ppc_flush_icache(dest32);
 | 
						|
		break;
 | 
						|
	    case N_DATA:
 | 
						|
#ifdef COFFDEBUG
 | 
						|
		COFFDEBUG("R_POS N_DATA\n");
 | 
						|
		COFFDEBUG("txtsize=%x\t", cofffile->txtsize);
 | 
						|
		COFFDEBUG("dest32=%x\t", dest32);
 | 
						|
		COFFDEBUG("symval=%x\t", symval);
 | 
						|
		COFFDEBUG("*dest32=%8.8x\t", *dest32);
 | 
						|
#endif
 | 
						|
		*dest32 = (unsigned long)((*dest32) +
 | 
						|
					  ((unsigned long)(cofffile->
 | 
						|
							   saddr[N_DATA -
 | 
						|
								 1])) -
 | 
						|
					  cofffile->dataddr);
 | 
						|
		ppc_flush_icache(dest32);
 | 
						|
		break;
 | 
						|
	    case N_BSS:
 | 
						|
#ifdef COFFDEBUG
 | 
						|
		COFFDEBUG("R_POS N_BSS\n");
 | 
						|
		COFFDEBUG("dest32=%x\t", dest32);
 | 
						|
		COFFDEBUG("symval=%x\t", symval);
 | 
						|
		COFFDEBUG("*dest32=%8.8x\t", *dest32);
 | 
						|
#endif
 | 
						|
		*dest32 = (unsigned long)((*dest32) +
 | 
						|
					  (unsigned long)(cofffile->
 | 
						|
							  saddr[N_BSS - 1]) -
 | 
						|
					  (cofffile->bssaddr));
 | 
						|
		ppc_flush_icache(dest32);
 | 
						|
		break;
 | 
						|
	    default:
 | 
						|
		ErrorF("R_POS with unexpected section %d\n", symbol->n_scnum);
 | 
						|
	    }
 | 
						|
	}
 | 
						|
#ifdef COFFDEBUG
 | 
						|
	COFFDEBUG("*dest32=%8.8x\t", *dest32);
 | 
						|
	COFFDEBUG("\n");
 | 
						|
#endif
 | 
						|
	break;
 | 
						|
    case R_TOC:
 | 
						|
	/*
 | 
						|
	 * Relative to TOC
 | 
						|
	 */
 | 
						|
	{
 | 
						|
	    dest16 = (unsigned short *)dest32;
 | 
						|
	    if (RELOC_RLEN(*rel) != 0x0f)
 | 
						|
		FatalError("R_TOC with size != 16 bits");
 | 
						|
#ifdef COFFDEBUG
 | 
						|
	    COFFDEBUG("R_TOC ");
 | 
						|
	    COFFDEBUG("dest16=%x\t", dest16);
 | 
						|
	    COFFDEBUG("symbol=%x\t", symbol);
 | 
						|
	    COFFDEBUG("symbol->n_value=%x\t", symbol->n_value);
 | 
						|
	    COFFDEBUG("cofffile->toc=%x\t", cofffile->toc);
 | 
						|
	    COFFDEBUG("*dest16=%8.8x\t", *dest16);
 | 
						|
#endif
 | 
						|
	    *dest16 = (unsigned long)((symbol->n_value - cofffile->toc));
 | 
						|
	    ppc_flush_icache(dest16);
 | 
						|
	}
 | 
						|
#ifdef COFFDEBUG
 | 
						|
	COFFDEBUG("*dest16=%8.8x\t", *dest16);
 | 
						|
	COFFDEBUG("\n");
 | 
						|
#endif
 | 
						|
	break;
 | 
						|
    case R_BR:
 | 
						|
	/*
 | 
						|
	 * Branch relative to self, non-modifiable
 | 
						|
	 */
 | 
						|
 | 
						|
	if (RELOC_RLEN(*rel) != 0x19)
 | 
						|
	    FatalError("R_BR with size != 24 bits");
 | 
						|
	name = COFFGetSymbolName(cofffile, rel->r_symndx);
 | 
						|
	symitem = LoaderHashFind(name);
 | 
						|
	if (symitem == 0) {
 | 
						|
	    name++;
 | 
						|
	    symitem = LoaderHashFind(name);
 | 
						|
	}
 | 
						|
	if (symitem && cofffile->module != symitem->module) {
 | 
						|
#ifdef COFFDEBUG
 | 
						|
	    COFFDEBUG("Symbol module %d != file module %d\n",
 | 
						|
		      symitem->module, cofffile->module);
 | 
						|
#endif
 | 
						|
	    symval = COFFGetSymbolGlinkValue(cofffile, rel->r_symndx);
 | 
						|
	} else
 | 
						|
	    symval = COFFGetSymbolValue(cofffile, rel->r_symndx);
 | 
						|
	if (symval == 0) {
 | 
						|
#ifdef COFFDEBUG
 | 
						|
	    char *name;
 | 
						|
 | 
						|
	    COFFDEBUG("***Unable to resolve symbol %s\n",
 | 
						|
		      name = COFFGetSymbolName(cofffile, rel->r_symndx));
 | 
						|
	    xf86loaderfree(name);
 | 
						|
#endif
 | 
						|
	    return COFFDelayRelocation(cofffile, secndx, rel);
 | 
						|
	}
 | 
						|
#ifdef COFFDEBUG
 | 
						|
	COFFDEBUG("R_BR ");
 | 
						|
	COFFDEBUG("dest32=%x\t", dest32);
 | 
						|
	COFFDEBUG("symval=%x\t", symval);
 | 
						|
	COFFDEBUG("*dest32=%8.8x\t", *dest32);
 | 
						|
#endif
 | 
						|
	{
 | 
						|
	    unsigned long val;
 | 
						|
 | 
						|
	    val = ((unsigned long)symval - (unsigned long)dest32);
 | 
						|
#ifdef COFFDEBUG
 | 
						|
	    COFFDEBUG("val=%8.8x\n", val);
 | 
						|
#endif
 | 
						|
	    val = val >> 2;
 | 
						|
	    if ((val & 0x3f000000) != 0x3f000000 &&
 | 
						|
		(val & 0x3f000000) != 0x00000000) {
 | 
						|
		FatalError("R_BR offset %x too large\n", val << 2);
 | 
						|
		break;
 | 
						|
	    }
 | 
						|
	    val &= 0x00ffffff;
 | 
						|
#ifdef COFFDEBUG
 | 
						|
	    COFFDEBUG("val=%8.8x\n", val);
 | 
						|
#endif
 | 
						|
	    /*
 | 
						|
	     * The address part contains the offset to the beginning
 | 
						|
	     * of the .text section. Disreguard this since we have
 | 
						|
	     * calculated the correct offset already.
 | 
						|
	     */
 | 
						|
	    (*dest32) = ((*dest32) & 0xfc000003) | (val << 2);
 | 
						|
#ifdef COFFDEBUG
 | 
						|
	    COFFDEBUG("*dest32=%8.8x\n", *dest32);
 | 
						|
#endif
 | 
						|
	    if (cofffile->module != symitem->module) {
 | 
						|
		(*++dest32) = 0x80410014;	/* lwz r2,20(r1) */
 | 
						|
	    }
 | 
						|
	    ppc_flush_icache(--dest32);
 | 
						|
	}
 | 
						|
 | 
						|
	break;
 | 
						|
#endif /* __powerpc__ */
 | 
						|
    default:
 | 
						|
	ErrorF("COFF_RelocateEntry() Unsupported relocation type %o\n",
 | 
						|
	       rel->r_type);
 | 
						|
	break;
 | 
						|
    }
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
static COFFRelocPtr
 | 
						|
COFFCollectRelocations(COFFModulePtr cofffile)
 | 
						|
{
 | 
						|
    unsigned short i, j;
 | 
						|
    RELOC *rel;
 | 
						|
    SCNHDR *sec;
 | 
						|
    COFFRelocPtr reloc_head = NULL;
 | 
						|
    COFFRelocPtr tmp;
 | 
						|
 | 
						|
    for (i = 0; i < cofffile->numsh; i++) {
 | 
						|
	if (cofffile->saddr[i] == NULL)
 | 
						|
	    continue;		/* Section not loaded!! */
 | 
						|
	sec = &(cofffile->sections[i]);
 | 
						|
	for (j = 0; j < sec->s_nreloc; j++) {
 | 
						|
	    rel = (RELOC *) (cofffile->reladdr[i] + (j * RELSZ));
 | 
						|
	    tmp = COFFDelayRelocation(cofffile, i, rel);
 | 
						|
	    tmp->next = reloc_head;
 | 
						|
	    reloc_head = tmp;
 | 
						|
	}
 | 
						|
    }
 | 
						|
 | 
						|
    return reloc_head;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * COFF_GetSymbols()
 | 
						|
 *
 | 
						|
 * add the symbols to the symbol table maintained by the loader.
 | 
						|
 */
 | 
						|
 | 
						|
static LOOKUP *
 | 
						|
COFF_GetSymbols(COFFModulePtr cofffile)
 | 
						|
{
 | 
						|
    SYMENT *sym;
 | 
						|
    AUXENT *aux = NULL;
 | 
						|
    int i, l, numsyms;
 | 
						|
    LOOKUP *lookup, *lookup_common, *p;
 | 
						|
    char *symname;
 | 
						|
 | 
						|
/*
 | 
						|
 * Load the symbols into memory
 | 
						|
 */
 | 
						|
    numsyms = cofffile->header->f_nsyms;
 | 
						|
 | 
						|
#ifdef COFFDEBUG
 | 
						|
    COFFDEBUG("COFF_GetSymbols(): %d symbols\n", numsyms);
 | 
						|
#endif
 | 
						|
 | 
						|
    cofffile->symsize = (numsyms * SYMESZ);
 | 
						|
    cofffile->symtab =
 | 
						|
	    (SYMENT *) _LoaderFileToMem(cofffile->fd,
 | 
						|
					cofffile->header->f_symptr,
 | 
						|
					(numsyms * SYMESZ), "symbols");
 | 
						|
 | 
						|
    if ((lookup = xf86loadermalloc((numsyms + 1) * sizeof(LOOKUP))) == NULL)
 | 
						|
	return NULL;
 | 
						|
 | 
						|
    for (i = 0, l = 0; i < numsyms; i++) {
 | 
						|
	sym = (SYMENT *) (((unsigned char *)cofffile->symtab) + (i * SYMESZ));
 | 
						|
	symname = COFFGetSymbolName(cofffile, i);
 | 
						|
	if (sym->n_numaux > 0)
 | 
						|
	    aux = (AUXENT *) (((unsigned char *)cofffile->symtab) +
 | 
						|
			      ((i + 1) * SYMESZ));
 | 
						|
	else
 | 
						|
	    aux = NULL;
 | 
						|
#ifdef COFFDEBUG
 | 
						|
	COFFDEBUG("\t%d %d %lx %x %d %d %s\n",
 | 
						|
		  i, sym->n_scnum, sym->n_value, sym->n_type,
 | 
						|
		  sym->n_sclass, sym->n_numaux, symname);
 | 
						|
	if (aux)
 | 
						|
	    COFFDEBUG("aux=\t%ld %lx %x %x %x %lx %x\n",
 | 
						|
		      aux->x_scnlen, aux->x_parmhash, aux->x_snhash,
 | 
						|
		      aux->x_smtyp, aux->x_smclas, aux->x_stab,
 | 
						|
		      aux->x_snstab);
 | 
						|
#endif
 | 
						|
	i += sym->n_numaux;
 | 
						|
	/*
 | 
						|
	 * check for TOC csect before discarding C_HIDEXT below
 | 
						|
	 */
 | 
						|
	if (aux && aux->x_smclas == XMC_TC0) {
 | 
						|
	    if (sym->n_scnum != N_DATA)
 | 
						|
		FatalError("TOC not in N_DATA section");
 | 
						|
	    cofffile->toc = sym->n_value;
 | 
						|
	    cofffile->tocaddr = (cofffile->saddr[sym->n_scnum - 1] +
 | 
						|
				 sym->n_value - (cofffile->dataddr));
 | 
						|
#ifdef COFFDEBUG
 | 
						|
	    COFFDEBUG("TOC=%lx\n", cofffile->toc);
 | 
						|
	    COFFDEBUG("TOCaddr=%p\n", cofffile->tocaddr);
 | 
						|
#endif
 | 
						|
	    continue;
 | 
						|
	}
 | 
						|
	if (sym->n_sclass == C_HIDEXT) {
 | 
						|
/*
 | 
						|
		&& aux && !(aux->x_smclas == XMC_DS
 | 
						|
		&& aux->x_smtyp == XTY_SD) ) ) {
 | 
						|
*/
 | 
						|
#ifdef COFFDEBUG
 | 
						|
	    COFFDEBUG("Skipping C_HIDEXT class symbol %s\n", symname);
 | 
						|
#endif
 | 
						|
	    continue;
 | 
						|
	}
 | 
						|
	switch (sym->n_scnum) {
 | 
						|
	case N_UNDEF:
 | 
						|
	    if (sym->n_value != 0) {
 | 
						|
		char *name;
 | 
						|
		COFFCommonPtr tmp;
 | 
						|
 | 
						|
		name = COFFGetSymbolName(cofffile, i);
 | 
						|
#ifdef COFFDEBUG
 | 
						|
		COFFDEBUG("Adding COMMON space for %s\n", name);
 | 
						|
#endif
 | 
						|
		if (!LoaderHashFind(name)) {
 | 
						|
		    tmp = COFFAddCOMMON(sym, i);
 | 
						|
		    if (tmp) {
 | 
						|
			tmp->next = listCOMMON;
 | 
						|
			listCOMMON = tmp;
 | 
						|
		    }
 | 
						|
		}
 | 
						|
		xf86loaderfree(name);
 | 
						|
	    }
 | 
						|
	    xf86loaderfree(symname);
 | 
						|
	    break;
 | 
						|
	case N_ABS:
 | 
						|
	case N_DEBUG:
 | 
						|
	case N_COMMENT:
 | 
						|
#ifdef COFFDEBUG
 | 
						|
	    COFFDEBUG("Freeing %s, section %d\n", symname, sym->n_scnum);
 | 
						|
#endif
 | 
						|
	    xf86loaderfree(symname);
 | 
						|
	    break;
 | 
						|
	case N_TEXT:
 | 
						|
	    if ((sym->n_sclass == C_EXT || sym->n_sclass == C_HIDEXT)
 | 
						|
		&& cofffile->saddr[sym->n_scnum - 1]) {
 | 
						|
		lookup[l].symName = symname;
 | 
						|
		lookup[l].offset = (funcptr)
 | 
						|
			(cofffile->saddr[sym->n_scnum - 1] +
 | 
						|
			 sym->n_value - cofffile->txtaddr);
 | 
						|
#ifdef COFFDEBUG
 | 
						|
		COFFDEBUG("Adding %p %s\n",
 | 
						|
			  (void *)lookup[l].offset, lookup[l].symName);
 | 
						|
#endif
 | 
						|
		l++;
 | 
						|
	    } else {
 | 
						|
#ifdef COFFDEBUG
 | 
						|
		COFFDEBUG("TEXT Section not loaded %d\n", sym->n_scnum - 1);
 | 
						|
#endif
 | 
						|
		xf86loaderfree(symname);
 | 
						|
	    }
 | 
						|
	    break;
 | 
						|
	case N_DATA:
 | 
						|
	    /*
 | 
						|
	     * Note: COFF expects .data to be contiguous with
 | 
						|
	     * .data, so that offsets for .data are relative to
 | 
						|
	     * .text. We need to adjust for this, and make them
 | 
						|
	     * relative to .data so that the relocation can be
 | 
						|
	     * properly applied. This is needed becasue we allocate
 | 
						|
	     * .data seperately from .text.
 | 
						|
	     */
 | 
						|
	    if ((sym->n_sclass == C_EXT || sym->n_sclass == C_HIDEXT)
 | 
						|
		&& cofffile->saddr[sym->n_scnum - 1]) {
 | 
						|
		lookup[l].symName = symname;
 | 
						|
		lookup[l].offset = (funcptr)
 | 
						|
			(cofffile->saddr[sym->n_scnum - 1] +
 | 
						|
			 sym->n_value - cofffile->dataddr);
 | 
						|
#ifdef COFFDEBUG
 | 
						|
		COFFDEBUG("Adding %p %s\n",
 | 
						|
			  (void *)lookup[l].offset, lookup[l].symName);
 | 
						|
#endif
 | 
						|
		l++;
 | 
						|
	    } else {
 | 
						|
#ifdef COFFDEBUG
 | 
						|
		COFFDEBUG("DATA Section not loaded %d\n", sym->n_scnum - 1);
 | 
						|
#endif
 | 
						|
		xf86loaderfree(symname);
 | 
						|
	    }
 | 
						|
	    break;
 | 
						|
	case N_BSS:
 | 
						|
	    /*
 | 
						|
	     * Note: COFF expects .bss to be contiguous with
 | 
						|
	     * .data, so that offsets for .bss are relative to
 | 
						|
	     * .text. We need to adjust for this, and make them
 | 
						|
	     * relative to .bss so that the relocation can be
 | 
						|
	     * properly applied. This is needed becasue we allocate
 | 
						|
	     * .bss seperately from .text and .data.
 | 
						|
	     */
 | 
						|
	    if ((sym->n_sclass == C_EXT || sym->n_sclass == C_HIDEXT)
 | 
						|
		&& cofffile->saddr[sym->n_scnum - 1]) {
 | 
						|
		lookup[l].symName = symname;
 | 
						|
		lookup[l].offset = (funcptr)
 | 
						|
			(cofffile->saddr[sym->n_scnum - 1] +
 | 
						|
			 sym->n_value - cofffile->bssaddr);
 | 
						|
#ifdef COFFDEBUG
 | 
						|
		COFFDEBUG("Adding %p %s\n",
 | 
						|
			  (void *)lookup[l].offset, lookup[l].symName);
 | 
						|
#endif
 | 
						|
		l++;
 | 
						|
	    } else {
 | 
						|
#ifdef COFFDEBUG
 | 
						|
		COFFDEBUG("BSS Section not loaded %d\n", sym->n_scnum - 1);
 | 
						|
#endif
 | 
						|
		xf86loaderfree(symname);
 | 
						|
	    }
 | 
						|
	    break;
 | 
						|
	default:
 | 
						|
	    ErrorF("Unknown Section number %d\n", sym->n_scnum);
 | 
						|
	    xf86loaderfree(symname);
 | 
						|
	    break;
 | 
						|
	}
 | 
						|
    }
 | 
						|
 | 
						|
    lookup[l].symName = NULL;	/* Terminate the list */
 | 
						|
 | 
						|
    lookup_common = COFFCreateCOMMON(cofffile);
 | 
						|
    if (lookup_common) {
 | 
						|
	for (i = 0, p = lookup_common; p->symName; i++, p++) ;
 | 
						|
	memcpy(&(lookup[l]), lookup_common, i * sizeof(LOOKUP));
 | 
						|
 | 
						|
	xf86loaderfree(lookup_common);
 | 
						|
	l += i;
 | 
						|
	lookup[l].symName = NULL;
 | 
						|
    }
 | 
						|
 | 
						|
/*
 | 
						|
 * remove the COFF symbols that will show up in every module
 | 
						|
 */
 | 
						|
    for (i = 0, p = lookup; p->symName; i++, p++) {
 | 
						|
	while (p->symName && (!strcmp(lookup[i].symName, ".text")
 | 
						|
			      || !strcmp(lookup[i].symName, ".data")
 | 
						|
			      || !strcmp(lookup[i].symName, ".bss")
 | 
						|
	       )) {
 | 
						|
	    memmove(&(lookup[i]), &(lookup[i + 1]),
 | 
						|
		    (l-- - i) * sizeof(LOOKUP));
 | 
						|
	}
 | 
						|
    }
 | 
						|
 | 
						|
    return lookup;
 | 
						|
}
 | 
						|
 | 
						|
#define SecOffset(index) cofffile->sections[index].s_scnptr
 | 
						|
#define SecSize(index) cofffile->sections[index].s_size
 | 
						|
#define SecAddr(index) cofffile->sections[index].s_paddr
 | 
						|
#define RelOffset(index) cofffile->sections[index].s_relptr
 | 
						|
#define RelSize(index) (cofffile->sections[index].s_nreloc*RELSZ)
 | 
						|
 | 
						|
/*
 | 
						|
 * COFFCollectSections
 | 
						|
 *
 | 
						|
 * Do the work required to load each section into memory.
 | 
						|
 */
 | 
						|
static void
 | 
						|
COFFCollectSections(COFFModulePtr cofffile)
 | 
						|
{
 | 
						|
    unsigned short i;
 | 
						|
 | 
						|
/*
 | 
						|
 * Find and identify all of the Sections
 | 
						|
 */
 | 
						|
 | 
						|
#ifdef COFFDEBUG
 | 
						|
    COFFDEBUG("COFFCollectSections(): %d sections\n", cofffile->numsh);
 | 
						|
#endif
 | 
						|
 | 
						|
    for (i = 0; i < cofffile->numsh; i++) {
 | 
						|
#ifdef COFFDEBUG
 | 
						|
	COFFDEBUG("%d %s\n", i, cofffile->sections[i].s_name);
 | 
						|
#endif
 | 
						|
	/* .text */
 | 
						|
	if (strcmp(cofffile->sections[i].s_name, ".text") == 0) {
 | 
						|
	    cofffile->text = _LoaderFileToMem(cofffile->fd,
 | 
						|
					      SecOffset(i), SecSize(i),
 | 
						|
					      ".text");
 | 
						|
	    cofffile->saddr[i] = cofffile->text;
 | 
						|
	    cofffile->txtndx = i;
 | 
						|
	    cofffile->txtaddr = SecAddr(i);
 | 
						|
	    cofffile->txtsize = SecSize(i);
 | 
						|
	    cofffile->txtrelsize = RelSize(i);
 | 
						|
	    cofffile->reladdr[i] = _LoaderFileToMem(cofffile->fd,
 | 
						|
						    RelOffset(i), RelSize(i),
 | 
						|
						    ".rel.text");
 | 
						|
#ifdef COFFDEBUG
 | 
						|
	    COFFDEBUG(".text starts at %p (%x bytes)\n", cofffile->text,
 | 
						|
		      cofffile->txtsize);
 | 
						|
#endif
 | 
						|
	    continue;
 | 
						|
	}
 | 
						|
	/* .data */
 | 
						|
	if (strcmp(cofffile->sections[i].s_name, ".data") == 0) {
 | 
						|
	    cofffile->data = _LoaderFileToMem(cofffile->fd,
 | 
						|
					      SecOffset(i), SecSize(i),
 | 
						|
					      ".data");
 | 
						|
	    cofffile->saddr[i] = cofffile->data;
 | 
						|
	    cofffile->datndx = i;
 | 
						|
	    cofffile->dataddr = SecAddr(i);
 | 
						|
	    cofffile->datsize = SecSize(i);
 | 
						|
	    cofffile->datrelsize = RelSize(i);
 | 
						|
	    cofffile->reladdr[i] = _LoaderFileToMem(cofffile->fd,
 | 
						|
						    RelOffset(i), RelSize(i),
 | 
						|
						    ".rel.data");
 | 
						|
#ifdef COFFDEBUG
 | 
						|
	    COFFDEBUG(".data starts at %p (%x bytes)\n", cofffile->data,
 | 
						|
		      cofffile->datsize);
 | 
						|
#endif
 | 
						|
	    continue;
 | 
						|
	}
 | 
						|
	/* .bss */
 | 
						|
	if (strcmp(cofffile->sections[i].s_name, ".bss") == 0) {
 | 
						|
	    if (SecSize(i))
 | 
						|
		cofffile->bss = xf86loadercalloc(1, SecSize(i));
 | 
						|
	    else
 | 
						|
		cofffile->bss = NULL;
 | 
						|
	    cofffile->saddr[i] = cofffile->bss;
 | 
						|
	    cofffile->bssndx = i;
 | 
						|
	    cofffile->bssaddr = SecAddr(i);
 | 
						|
	    cofffile->bsssize = SecSize(i);
 | 
						|
#ifdef COFFDEBUG
 | 
						|
	    COFFDEBUG(".bss starts at %p (%x bytes)\n", cofffile->bss,
 | 
						|
		      cofffile->bsssize);
 | 
						|
#endif
 | 
						|
	    continue;
 | 
						|
	}
 | 
						|
	/* .comment */
 | 
						|
	if (strncmp(cofffile->sections[i].s_name,
 | 
						|
		    ".comment", strlen(".comment")) == 0) {
 | 
						|
	    continue;
 | 
						|
	}
 | 
						|
	/* .stab */
 | 
						|
	if (strcmp(cofffile->sections[i].s_name, ".stab") == 0) {
 | 
						|
	    continue;
 | 
						|
	}
 | 
						|
	/* .stabstr */
 | 
						|
	if (strcmp(cofffile->sections[i].s_name, ".stabstr") == 0) {
 | 
						|
	    continue;
 | 
						|
	}
 | 
						|
	/* .stab.* */
 | 
						|
	if (strncmp(cofffile->sections[i].s_name,
 | 
						|
		    ".stab.", strlen(".stab.")) == 0) {
 | 
						|
	    continue;
 | 
						|
	}
 | 
						|
	ErrorF("COFF: Not loading %s\n", cofffile->sections[i].s_name);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * Public API for the COFF implementation of the loader.
 | 
						|
 */
 | 
						|
void *
 | 
						|
COFFLoadModule(loaderPtr modrec, int cofffd, LOOKUP **ppLookup, int flags)
 | 
						|
{
 | 
						|
    COFFModulePtr cofffile;
 | 
						|
    FILHDR *header;
 | 
						|
    int stroffset;		/* offset of string table */
 | 
						|
    COFFRelocPtr coff_reloc, tail;
 | 
						|
    void *v;
 | 
						|
 | 
						|
#ifdef COFFDEBUG
 | 
						|
    COFFDEBUG("COFFLoadModule(%s,%x,%x)\n", modrec->name, modrec->handle,
 | 
						|
	      cofffd);
 | 
						|
#endif
 | 
						|
 | 
						|
    if ((cofffile = xf86loadercalloc(1, sizeof(COFFModuleRec))) == NULL) {
 | 
						|
	ErrorF("Unable to allocate COFFModuleRec\n");
 | 
						|
	return NULL;
 | 
						|
    }
 | 
						|
 | 
						|
    cofffile->handle = modrec->handle;
 | 
						|
    cofffile->module = modrec->module;
 | 
						|
    cofffile->fd = cofffd;
 | 
						|
    v = cofffile->funcs = modrec->funcs;
 | 
						|
 | 
						|
/*
 | 
						|
 *  Get the COFF header
 | 
						|
 */
 | 
						|
    cofffile->header =
 | 
						|
	    (FILHDR *) _LoaderFileToMem(cofffd, 0, sizeof(FILHDR), "header");
 | 
						|
    header = (FILHDR *) cofffile->header;
 | 
						|
 | 
						|
    if (header->f_symptr == 0 || header->f_nsyms == 0) {
 | 
						|
	ErrorF("No symbols found in module\n");
 | 
						|
	_LoaderFreeFileMem(header, sizeof(FILHDR));
 | 
						|
	xf86loaderfree(cofffile);
 | 
						|
	return NULL;
 | 
						|
    }
 | 
						|
/*
 | 
						|
 * Get the section table
 | 
						|
 */
 | 
						|
    cofffile->numsh = header->f_nscns;
 | 
						|
    cofffile->secsize = (header->f_nscns * SCNHSZ);
 | 
						|
    cofffile->sections =
 | 
						|
	    (SCNHDR *) _LoaderFileToMem(cofffd, FILHSZ + header->f_opthdr,
 | 
						|
					cofffile->secsize, "sections");
 | 
						|
    cofffile->saddr =
 | 
						|
	    xf86loadercalloc(cofffile->numsh, sizeof(unsigned char *));
 | 
						|
    cofffile->reladdr =
 | 
						|
	    xf86loadercalloc(cofffile->numsh, sizeof(unsigned char *));
 | 
						|
 | 
						|
/*
 | 
						|
 * Load the optional header if we need it ?????
 | 
						|
 */
 | 
						|
 | 
						|
/*
 | 
						|
 * Load the rest of the desired sections
 | 
						|
 */
 | 
						|
    COFFCollectSections(cofffile);
 | 
						|
 | 
						|
/*
 | 
						|
 * load the string table (must be done before we process symbols).
 | 
						|
 */
 | 
						|
    stroffset = header->f_symptr + (header->f_nsyms * SYMESZ);
 | 
						|
 | 
						|
    _LoaderFileRead(cofffd, stroffset, &(cofffile->strsize), sizeof(int));
 | 
						|
 | 
						|
    stroffset += 4;		/* Move past the size */
 | 
						|
    cofffile->strsize -= sizeof(int);	/* size includes itself, so reduce by 4 */
 | 
						|
    cofffile->strtab =
 | 
						|
	    _LoaderFileToMem(cofffd, stroffset, cofffile->strsize, "strings");
 | 
						|
 | 
						|
/*
 | 
						|
 * add symbols
 | 
						|
 */
 | 
						|
    *ppLookup = COFF_GetSymbols(cofffile);
 | 
						|
 | 
						|
/*
 | 
						|
 * Do relocations
 | 
						|
 */
 | 
						|
    coff_reloc = COFFCollectRelocations(cofffile);
 | 
						|
    if (coff_reloc) {
 | 
						|
	for (tail = coff_reloc; tail->next; tail = tail->next) ;
 | 
						|
	tail->next = _LoaderGetRelocations(v)->coff_reloc;
 | 
						|
	_LoaderGetRelocations(v)->coff_reloc = coff_reloc;
 | 
						|
    }
 | 
						|
 | 
						|
    return (void *)cofffile;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
COFFResolveSymbols(void *mod)
 | 
						|
{
 | 
						|
    COFFRelocPtr newlist, p, tmp;
 | 
						|
 | 
						|
    /* Try to relocate everything.  Build a new list containing entries
 | 
						|
     * which we failed to relocate.  Destroy the old list in the process.
 | 
						|
     */
 | 
						|
    newlist = 0;
 | 
						|
    for (p = _LoaderGetRelocations(mod)->coff_reloc; p;) {
 | 
						|
	tmp = COFF_RelocateEntry(p->file, p->secndx, p->rel);
 | 
						|
	if (tmp) {
 | 
						|
	    /* Failed to relocate.  Keep it in the list. */
 | 
						|
	    tmp->next = newlist;
 | 
						|
	    newlist = tmp;
 | 
						|
	}
 | 
						|
	tmp = p;
 | 
						|
	p = p->next;
 | 
						|
	xf86loaderfree(tmp);
 | 
						|
    }
 | 
						|
    _LoaderGetRelocations(mod)->coff_reloc = newlist;
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
COFFCheckForUnresolved(void *mod)
 | 
						|
{
 | 
						|
    char *name;
 | 
						|
    COFFRelocPtr crel;
 | 
						|
    int flag, fatalsym = 0;
 | 
						|
 | 
						|
    if ((crel = _LoaderGetRelocations(mod)->coff_reloc) == NULL)
 | 
						|
	return 0;
 | 
						|
 | 
						|
    while (crel) {
 | 
						|
	name = COFFGetSymbolName(crel->file, crel->rel->r_symndx);
 | 
						|
	flag = _LoaderHandleUnresolved(name,
 | 
						|
				       _LoaderHandleToName(crel->file->
 | 
						|
							   handle));
 | 
						|
	if (flag)
 | 
						|
	    fatalsym = 1;
 | 
						|
	xf86loaderfree(name);
 | 
						|
	crel = crel->next;
 | 
						|
    }
 | 
						|
    return fatalsym;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
COFFUnloadModule(void *modptr)
 | 
						|
{
 | 
						|
    COFFModulePtr cofffile = (COFFModulePtr) modptr;
 | 
						|
    COFFRelocPtr relptr, reltptr, *brelptr;
 | 
						|
 | 
						|
/*
 | 
						|
 * Delete any unresolved relocations
 | 
						|
 */
 | 
						|
 | 
						|
    relptr = _LoaderGetRelocations(cofffile->funcs)->coff_reloc;
 | 
						|
    brelptr = &(_LoaderGetRelocations(cofffile->funcs)->coff_reloc);
 | 
						|
 | 
						|
    while (relptr) {
 | 
						|
	if (relptr->file == cofffile) {
 | 
						|
	    *brelptr = relptr->next;	/* take it out of the list */
 | 
						|
	    reltptr = relptr;	/* save pointer to this node */
 | 
						|
	    relptr = relptr->next;	/* advance the pointer */
 | 
						|
	    xf86loaderfree(reltptr);	/* free the node */
 | 
						|
	} else {
 | 
						|
	    brelptr = &(relptr->next);
 | 
						|
	    relptr = relptr->next;	/* advance the pointer */
 | 
						|
	}
 | 
						|
    }
 | 
						|
 | 
						|
/*
 | 
						|
 * Delete any symbols in the symbols table.
 | 
						|
 */
 | 
						|
 | 
						|
    LoaderHashTraverse((void *)cofffile, COFFhashCleanOut);
 | 
						|
 | 
						|
/*
 | 
						|
 * Free the sections that were allocated.
 | 
						|
 */
 | 
						|
#define CheckandFree(ptr,size)	if(ptr) _LoaderFreeFileMem((ptr),(size))
 | 
						|
 | 
						|
    CheckandFree(cofffile->strtab, cofffile->strsize);
 | 
						|
    CheckandFree(cofffile->symtab, cofffile->symsize);
 | 
						|
    CheckandFree(cofffile->text, cofffile->txtsize);
 | 
						|
    CheckandFree(cofffile->reladdr[cofffile->txtndx], cofffile->txtrelsize);
 | 
						|
    CheckandFree(cofffile->data, cofffile->datsize);
 | 
						|
    CheckandFree(cofffile->reladdr[cofffile->datndx], cofffile->datrelsize);
 | 
						|
    CheckandFree(cofffile->bss, cofffile->bsssize);
 | 
						|
    if (cofffile->common)
 | 
						|
	xf86loaderfree(cofffile->common);
 | 
						|
/*
 | 
						|
 * Free the section table, and section pointer array
 | 
						|
 */
 | 
						|
    _LoaderFreeFileMem(cofffile->sections, cofffile->secsize);
 | 
						|
    xf86loaderfree(cofffile->saddr);
 | 
						|
    xf86loaderfree(cofffile->reladdr);
 | 
						|
    _LoaderFreeFileMem(cofffile->header, sizeof(FILHDR));
 | 
						|
/*
 | 
						|
 * Free the COFFModuleRec
 | 
						|
 */
 | 
						|
    xf86loaderfree(cofffile);
 | 
						|
 | 
						|
    return;
 | 
						|
}
 | 
						|
 | 
						|
char *
 | 
						|
COFFAddressToSection(void *modptr, unsigned long address)
 | 
						|
{
 | 
						|
    COFFModulePtr cofffile = (COFFModulePtr) modptr;
 | 
						|
    int i;
 | 
						|
 | 
						|
    for (i = 1; i < cofffile->numsh; i++) {
 | 
						|
	if (address >= (unsigned long)cofffile->saddr[i] &&
 | 
						|
	    address <= (unsigned long)cofffile->saddr[i] + SecSize(i)) {
 | 
						|
	    return cofffile->sections[i].s_name;
 | 
						|
	}
 | 
						|
    }
 | 
						|
    return NULL;
 | 
						|
}
 |