xserver-multidpi/hw/xfree86/loader/aoutloader.c

863 lines
22 KiB
C
Raw Normal View History

2004-04-23 21:54:30 +02:00
/* $XFree86: xc/programs/Xserver/hw/xfree86/loader/aoutloader.c,v 1.19 2003/10/15 16:58:34 dawes Exp $ */
2003-11-14 17:48:57 +01:00
/*
*
* Copyright (c) 1997 Matthieu Herrb
* Copyright 1995-1998 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.
*
* Modified 21/02/97 by Sebastien Marineau to support OS/2 a.out objects
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#ifdef __QNX__
#include <fcntl.h>
#else
#include <sys/fcntl.h>
#endif
#include <sys/stat.h>
#include <netinet/in.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 "Xos.h"
#include "os.h"
#include "aout.h"
#include "sym.h"
#include "loader.h"
#include "aoutloader.h"
#ifndef LOADERDEBUG
#define LOADERDEBUG 0
#endif
2003-11-14 17:48:57 +01:00
#if LOADERDEBUG
#define AOUTDEBUG ErrorF
#endif
2003-11-14 17:48:57 +01:00
#ifndef MIN
#define MIN(a,b) ((a)<(b)?(a):(b))
#endif
/*
* This structure contains all of the information about a module
* that has been loaded.
*/
typedef struct {
int handle;
int module;
int fd;
loader_funcs *funcs;
AOUTHDR *header; /* file header */
unsigned char *text; /* Start address of the text section */
unsigned int textsize; /* Size of the text section */
unsigned char *data; /* Start address of the data section */
unsigned int datasize; /* Size of the data section */
unsigned char *bss; /* Start address of the bss data */
unsigned int bsssize; /* Size of the bss section */
struct relocation_info *txtrel; /* Start address of the text relocation table */
struct relocation_info *datarel; /* Start address of the data relocation table */
AOUT_nlist *symtab; /* Start address of the symbol table */
unsigned char *strings; /* Start address of the string table */
unsigned long strsize; /* size of string table */
2003-11-14 17:48:57 +01:00
unsigned char *common; /* Start address of the common data */
unsigned long comsize; /* size of common data */
} AOUTModuleRec, *AOUTModulePtr;
/*
* If an relocation is unable to be satisfied, then put it on a list
* to try later after more modules have been loaded.
*/
typedef struct AOUT_RELOC {
AOUTModulePtr file;
struct relocation_info *rel;
int type; /* AOUT_TEXT or AOUT_DATA */
struct AOUT_RELOC *next;
} AOUTRelocRec;
/*
* Symbols with a section number of 0 (N_UNDF) 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 AOUT_COMMON {
struct AOUT_nlist *sym;
int index;
struct AOUT_COMMON *next;
} AOUTCommonRec;
static AOUTCommonPtr listCOMMON = NULL;
/* prototypes for static functions */
static int AOUTHashCleanOut(void *, itemPtr);
static char *AOUTGetSymbolName(AOUTModulePtr, struct AOUT_nlist *);
static void *AOUTGetSymbolValue(AOUTModulePtr, int);
static AOUTCommonPtr AOUTAddCommon(struct AOUT_nlist *, int);
static LOOKUP *AOUTCreateCommon(AOUTModulePtr);
static LOOKUP *AOUT_GetSymbols(AOUTModulePtr);
static AOUTRelocPtr AOUTDelayRelocation(AOUTModulePtr, int,
struct relocation_info_i386 *);
2003-11-14 17:48:57 +01:00
static AOUTRelocPtr AOUTCollectRelocations(AOUTModulePtr);
static void AOUT_Relocate(unsigned long *, unsigned long, int);
static AOUTRelocPtr AOUT_RelocateEntry(AOUTModulePtr, int,
struct relocation_info_i386 *);
2003-11-14 17:48:57 +01:00
/*
* Return 1 if the symbol in item belongs to aoutfile
*/
static int
AOUTHashCleanOut(void *voidptr, itemPtr item)
{
AOUTModulePtr aoutfile = (AOUTModulePtr) voidptr;
2003-11-14 17:48:57 +01:00
return (aoutfile->handle == item->handle);
}
/*
* Manage listResolv
*/
static AOUTRelocPtr
AOUTDelayRelocation(AOUTModulePtr aoutfile, int type,
struct relocation_info *rel)
2003-11-14 17:48:57 +01:00
{
AOUTRelocPtr reloc;
if ((reloc = xf86loadermalloc(sizeof(AOUTRelocRec))) == NULL) {
ErrorF("AOUTDelayRelocation() Unable to allocate memory\n");
return NULL;
}
if ((unsigned long)rel < 0x200) {
ErrorF("bug");
}
reloc->file = aoutfile;
reloc->type = type;
reloc->rel = rel;
reloc->next = 0;
return reloc;
}
/*
* Manage listCOMMON
*/
static AOUTCommonPtr
AOUTAddCommon(struct AOUT_nlist *sym, int index)
{
AOUTCommonPtr common;
if ((common = xf86loadermalloc(sizeof(AOUTCommonRec))) == NULL) {
ErrorF("AOUTAddCommon() Unable to allocate memory\n");
2003-11-14 17:48:57 +01:00
return 0;
}
common->sym = sym;
common->index = index;
common->next = 0;
return common;
}
static LOOKUP *
AOUTCreateCommon(AOUTModulePtr aoutfile)
{
int numsyms = 0, size = 0, l = 0;
int offset = 0;
2003-11-14 17:48:57 +01:00
AOUTCommonPtr common;
LOOKUP *lookup;
if (listCOMMON == NULL)
return NULL;
common = listCOMMON;
for (common = listCOMMON; common; common = common->next) {
/* Ensure long word alignment */
if ((common->sym->n_value & (sizeof(long) - 1)) != 0)
common->sym->n_value = (common->sym->n_value + (sizeof(long) - 1))
& ~(sizeof(long) - 1);
2003-11-14 17:48:57 +01:00
/* accumulate the sizes */
size += common->sym->n_value;
numsyms++;
} /* while */
2003-11-14 17:48:57 +01:00
#ifdef AOUTDEBUG
AOUTDEBUG("AOUTCreateCommon() %d entries (%d bytes) of COMMON data\n",
numsyms, size);
2003-11-14 17:48:57 +01:00
#endif
if ((lookup = xf86loadermalloc((numsyms + 1) * sizeof(LOOKUP))) == NULL) {
ErrorF("AOUTCreateCommon() Unable to allocate memory\n");
return NULL;
2003-11-14 17:48:57 +01:00
}
2003-11-14 17:48:57 +01:00
aoutfile->comsize = size;
if ((aoutfile->common = xf86loadercalloc(1, size)) == NULL) {
ErrorF("AOUTCreateCommon() Unable to allocate memory\n");
return NULL;
2003-11-14 17:48:57 +01:00
}
2003-11-14 17:48:57 +01:00
while (listCOMMON) {
common = listCOMMON;
lookup[l].symName = AOUTGetSymbolName(aoutfile, common->sym);
lookup[l].offset = (funcptr) (aoutfile->common + offset);
2003-11-14 17:48:57 +01:00
#ifdef AOUTDEBUG
AOUTDEBUG("Adding %p %s\n", (void *)lookup[l].offset,
lookup[l].symName);
2003-11-14 17:48:57 +01:00
#endif
listCOMMON = common->next;
offset += common->sym->n_value;
xf86loaderfree(common);
l++;
} /* while */
2003-11-14 17:48:57 +01:00
/* listCOMMON == NULL */
lookup[l].symName = NULL; /* Terminate the list */
2003-11-14 17:48:57 +01:00
return lookup;
}
/*
* Symbol Table
*/
static char *
AOUTGetString(AOUTModulePtr aoutfile, int index)
{
char *symname = (char *)&(aoutfile->strings[index]);
2003-11-14 17:48:57 +01:00
if (symname[0] == '_') {
symname++;
}
return symname;
}
2003-11-14 17:48:57 +01:00
/*
* Return the name of a symbol
*/
static char *
AOUTGetSymbolName(AOUTModulePtr aoutfile, struct AOUT_nlist *sym)
{
char *symname = AOUTGetString(aoutfile, sym->n_un.n_strx);
2003-11-14 17:48:57 +01:00
char *name;
name = xf86loadermalloc(strlen(symname) + 1);
2003-11-14 17:48:57 +01:00
if (!name)
FatalError("AOUTGetSymbolName: Out of memory\n");
strcpy(name, symname);
2003-11-14 17:48:57 +01:00
return name;
}
/*
* Return the value of a symbol in the loader's symbol table
*/
static void *
AOUTGetSymbolValue(AOUTModulePtr aoutfile, int index)
{
void *symval = NULL; /* value of the indicated symbol */
itemPtr symbol = NULL; /* name/value of symbol */
2003-11-14 17:48:57 +01:00
char *name = NULL;
name = AOUTGetSymbolName(aoutfile, aoutfile->symtab + index);
if (name)
2003-11-14 17:48:57 +01:00
symbol = LoaderHashFind(name);
if (symbol)
symval = (unsigned char *)symbol->address;
xf86loaderfree(name);
return symval;
}
/*
* Perform the actual relocation
*/
static void
AOUT_Relocate(unsigned long *destl, unsigned long val, int pcrel)
{
#ifdef AOUTDEBUG
AOUTDEBUG("AOUT_Relocate %p : %08lx %s",
(void *)destl, *destl, pcrel == 1 ? "rel" : "abs");
2003-11-14 17:48:57 +01:00
#endif
if (pcrel) {
/* relative to PC */
*destl = val - ((unsigned long)destl + sizeof(long));
2003-11-14 17:48:57 +01:00
} else {
*destl += val;
}
#ifdef AOUTDEBUG
AOUTDEBUG(" -> %08lx\n", *destl);
2003-11-14 17:48:57 +01:00
#endif
}
/*
* Fix the relocation for text or data section
*/
static AOUTRelocPtr
AOUT_RelocateEntry(AOUTModulePtr aoutfile, int type,
struct relocation_info *rel)
2003-11-14 17:48:57 +01:00
{
AOUTHDR *header = aoutfile->header;
AOUT_nlist *symtab = aoutfile->symtab;
int symnum;
void *symval;
unsigned long *destl; /* address of the location to be modified */
symnum = rel->r_symbolnum;
#ifdef AOUTDEBUG
2003-11-14 17:48:57 +01:00
{
char *name;
if (rel->r_extern) {
AOUTDEBUG("AOUT_RelocateEntry: extern %s\n",
name = AOUTGetSymbolName(aoutfile, symtab + symnum));
xf86loaderfree(name);
} else {
AOUTDEBUG("AOUT_RelocateEntry: intern\n");
}
AOUTDEBUG(" pcrel: %d", rel->r_pcrel);
AOUTDEBUG(" length: %d", rel->r_length);
AOUTDEBUG(" baserel: %d", rel->r_baserel);
AOUTDEBUG(" jmptable: %d", rel->r_jmptable);
AOUTDEBUG(" relative: %d", rel->r_relative);
AOUTDEBUG(" copy: %d\n", rel->r_copy);
2003-11-14 17:48:57 +01:00
}
#endif /* AOUTDEBUG */
if (rel->r_length != 2) {
ErrorF("AOUT_ReloateEntry: length != 2\n");
}
/*
* First find the address to modify
*/
switch (type) {
case AOUT_TEXT:
2003-11-14 17:48:57 +01:00
/* Check that the relocation offset is in the text segment */
if (rel->r_address > header->a_text) {
ErrorF("AOUT_RelocateEntry(): "
"text relocation out of text section\n");
}
2003-11-14 17:48:57 +01:00
destl = (unsigned long *)(aoutfile->text + rel->r_address);
break;
case AOUT_DATA:
2003-11-14 17:48:57 +01:00
/* Check that the relocation offset is in the data segment */
if (rel->r_address > header->a_data) {
ErrorF("AOUT_RelocateEntry():"
"data relocation out of data section\n");
}
destl = (unsigned long *)(aoutfile->data + rel->r_address);
break;
default:
2003-11-14 17:48:57 +01:00
ErrorF("AOUT_RelocateEntry(): unknown section type %d\n", type);
return 0;
} /* switch */
2003-11-14 17:48:57 +01:00
/*
* Now handle the relocation
*/
if (rel->r_extern) {
/* Lookup the symbol in the loader's symbol table */
symval = AOUTGetSymbolValue(aoutfile, symnum);
if (symval != 0) {
/* we've got the value */
AOUT_Relocate(destl, (unsigned long)symval, rel->r_pcrel);
2003-11-14 17:48:57 +01:00
return 0;
} else {
/* The symbol should be undefined */
switch (symtab[symnum].n_type & AOUT_TYPE) {
case AOUT_UNDF:
2003-11-14 17:48:57 +01:00
#ifdef AOUTDEBUG
AOUTDEBUG(" extern AOUT_UNDEF\n");
#endif
/* Add this relocation back to the global list */
return AOUTDelayRelocation(aoutfile, type, rel);
2003-11-14 17:48:57 +01:00
default:
2003-11-14 17:48:57 +01:00
ErrorF("AOUT_RelocateEntry():"
" impossible intern relocation type: %d\n",
2003-11-14 17:48:57 +01:00
symtab[symnum].n_type);
return 0;
} /* switch */
2003-11-14 17:48:57 +01:00
}
} else {
/* intern */
switch (rel->r_symbolnum) {
case AOUT_TEXT:
2003-11-14 17:48:57 +01:00
#ifdef AOUTDEBUG
AOUTDEBUG(" AOUT_TEXT\n");
#endif
/* Only absolute intern text relocations need to be handled */
if (rel->r_pcrel == 0)
AOUT_Relocate(destl, (unsigned long)aoutfile->text,
2003-11-14 17:48:57 +01:00
rel->r_pcrel);
return 0;
case AOUT_DATA:
2003-11-14 17:48:57 +01:00
#ifdef AOUTDEBUG
AOUTDEBUG(" AOUT_DATA\n");
#endif
if (rel->r_pcrel == 0)
2003-11-14 17:48:57 +01:00
AOUT_Relocate(destl, (unsigned long)aoutfile->data
- header->a_text, rel->r_pcrel);
else
ErrorF("AOUT_RelocateEntry(): "
"don't know how to handle data pc-relative reloc\n");
2003-11-14 17:48:57 +01:00
return 0;
case AOUT_BSS:
2003-11-14 17:48:57 +01:00
#ifdef AOUTDEBUG
AOUTDEBUG(" AOUT_BSS\n");
#endif
if (rel->r_pcrel == 0)
AOUT_Relocate(destl, (unsigned long)aoutfile->bss
- header->a_text - header->a_data,
2003-11-14 17:48:57 +01:00
rel->r_pcrel);
else
ErrorF("AOUT_RelocateEntry(): "
"don't know how to handle bss pc-relative reloc\n");
2003-11-14 17:48:57 +01:00
return 0;
default:
2003-11-14 17:48:57 +01:00
ErrorF("AOUT_RelocateEntry():"
" unknown intern relocation type: %d\n", rel->r_symbolnum);
return 0;
} /* switch */
2003-11-14 17:48:57 +01:00
}
} /* AOUT_RelocateEntry */
2003-11-14 17:48:57 +01:00
static AOUTRelocPtr
AOUTCollectRelocations(AOUTModulePtr aoutfile)
{
AOUTHDR *header = aoutfile->header;
int i, nreloc;
struct relocation_info *rel;
AOUTRelocPtr reloc_head = NULL;
AOUTRelocPtr tmp;
/* Text relocations */
if (aoutfile->text != NULL && aoutfile->txtrel != NULL) {
nreloc = header->a_trsize / sizeof(struct relocation_info);
2003-11-14 17:48:57 +01:00
for (i = 0; i < nreloc; i++) {
rel = aoutfile->txtrel + i;
tmp = AOUTDelayRelocation(aoutfile, AOUT_TEXT, rel);
if (tmp) {
tmp->next = reloc_head;
reloc_head = tmp;
}
} /* for */
2003-11-14 17:48:57 +01:00
}
/* Data relocations */
if (aoutfile->data != NULL && aoutfile->datarel != NULL) {
nreloc = header->a_drsize / sizeof(struct relocation_info);
2003-11-14 17:48:57 +01:00
for (i = 0; i < nreloc; i++) {
rel = aoutfile->datarel + i;
tmp = AOUTDelayRelocation(aoutfile, AOUT_DATA, rel);
tmp->next = reloc_head;
reloc_head = tmp;
} /* for */
2003-11-14 17:48:57 +01:00
}
return reloc_head;
} /* AOUTCollectRelocations */
2003-11-14 17:48:57 +01:00
/*
* AOUT_GetSymbols()
*
* add the symbols to the loader's symbol table
*/
static LOOKUP *
2003-11-14 17:48:57 +01:00
AOUT_GetSymbols(AOUTModulePtr aoutfile)
{
int fd = aoutfile->fd;
AOUTHDR *header = aoutfile->header;
int nsyms, soff, i, l;
char *symname;
AOUT_nlist *s;
LOOKUP *lookup, *lookup_common;
AOUTCommonPtr tmp;
aoutfile->symtab = (AOUT_nlist *) _LoaderFileToMem(fd,
AOUT_SYMOFF(header),
header->a_syms,
"symbols");
nsyms = header->a_syms / sizeof(AOUT_nlist);
2003-11-14 17:48:57 +01:00
lookup = xf86loadermalloc(nsyms * sizeof(LOOKUP));
if (lookup == NULL) {
ErrorF("AOUT_GetSymbols(): can't allocate memory\n");
return NULL;
}
for (i = 0, l = 0; i < nsyms; i++) {
s = aoutfile->symtab + i;
soff = s->n_un.n_strx;
if (soff == 0 || (s->n_type & AOUT_STAB) != 0)
2003-11-14 17:48:57 +01:00
continue;
symname = AOUTGetSymbolName(aoutfile, s);
2003-11-14 17:48:57 +01:00
#ifdef AOUTDEBUG
AOUTDEBUG("AOUT_GetSymbols(): %s %02x %02x %08lx\n",
symname, s->n_type, s->n_other, s->n_value);
2003-11-14 17:48:57 +01:00
#endif
switch (s->n_type & AOUT_TYPE) {
case AOUT_UNDF:
2003-11-14 17:48:57 +01:00
if (s->n_value != 0) {
if (!LoaderHashFind(symname)) {
#ifdef AOUTDEBUG
AOUTDEBUG("Adding common %s\n", symname);
#endif
tmp = AOUTAddCommon(s, i);
if (tmp) {
tmp->next = listCOMMON;
listCOMMON = tmp;
}
}
} else {
#ifdef AOUTDEBUG
AOUTDEBUG("Adding undef %s\n", symname);
#endif
}
xf86loaderfree(symname);
break;
case AOUT_TEXT:
2003-11-14 17:48:57 +01:00
if (s->n_type & AOUT_EXT) {
lookup[l].symName = symname;
/* text symbols start at 0 */
lookup[l].offset = (funcptr) (aoutfile->text + s->n_value);
2003-11-14 17:48:57 +01:00
#ifdef AOUTDEBUG
AOUTDEBUG("Adding text %s %p\n", symname,
(void *)lookup[l].offset);
2003-11-14 17:48:57 +01:00
#endif
l++;
} else {
xf86loaderfree(symname);
}
break;
case AOUT_DATA:
2003-11-14 17:48:57 +01:00
if (s->n_type & AOUT_EXT) {
lookup[l].symName = symname;
/* data symbols are following text */
lookup[l].offset = (funcptr) (aoutfile->data +
s->n_value - header->a_text);
2003-11-14 17:48:57 +01:00
#ifdef AOUTDEBUG
AOUTDEBUG("Adding data %s %p\n", symname,
(void *)lookup[l].offset);
2003-11-14 17:48:57 +01:00
#endif
l++;
} else {
xf86loaderfree(symname);
}
break;
case AOUT_BSS:
2003-11-14 17:48:57 +01:00
if (s->n_type & AOUT_EXT) {
lookup[l].symName = symname;
/* bss symbols follow both text and data */
lookup[l].offset = (funcptr) (aoutfile->bss + s->n_value
- (header->a_data
+ header->a_text));
2003-11-14 17:48:57 +01:00
#ifdef AOUTDEBUG
AOUTDEBUG("Adding bss %s %p\n", symname,
(void *)lookup[l].offset);
2003-11-14 17:48:57 +01:00
#endif
l++;
} else {
xf86loaderfree(symname);
}
break;
case AOUT_FN:
2003-11-14 17:48:57 +01:00
#ifdef AOUTDEBUG
if (s->n_type & AOUT_EXT) {
2003-11-14 17:48:57 +01:00
AOUTDEBUG("Ignoring AOUT_FN %s\n", symname);
} else {
AOUTDEBUG("Ignoring AOUT_WARN %s\n", symname);
}
#endif
xf86loaderfree(symname);
break;
default:
ErrorF("Unknown symbol type %x\n", s->n_type & AOUT_TYPE);
xf86loaderfree(symname);
} /* switch */
} /* for */
2003-11-14 17:48:57 +01:00
lookup[l].symName = NULL;
2003-11-14 17:48:57 +01:00
lookup_common = AOUTCreateCommon(aoutfile);
if (lookup_common) {
LOOKUP *p;
for (i = 0, p = lookup_common; p->symName; i++, p++) ;
memcpy(&(lookup[l]), lookup_common, i * sizeof(LOOKUP));
2003-11-14 17:48:57 +01:00
xf86loaderfree(lookup_common);
l += i;
lookup[l].symName = NULL;
}
return lookup;
} /* AOUT_GetSymbols */
2003-11-14 17:48:57 +01:00
/*
* Public API for the a.out implementation of the loader
*/
void *
AOUTLoadModule(loaderPtr modrec, int aoutfd, LOOKUP ** ppLookup)
2003-11-14 17:48:57 +01:00
{
AOUTModulePtr aoutfile = NULL;
AOUTHDR *header;
AOUTRelocPtr reloc, tail;
void *v;
2003-11-14 17:48:57 +01:00
#ifdef AOUTDEBUG
AOUTDEBUG("AOUTLoadModule(%s, %d, %d)\n",
modrec->name, modrec->handle, aoutfd);
#endif
if ((aoutfile = xf86loadercalloc(1, sizeof(AOUTModuleRec))) == NULL) {
ErrorF("Unable to allocate AOUTModuleRec\n");
2003-11-14 17:48:57 +01:00
return NULL;
}
aoutfile->handle = modrec->handle;
aoutfile->module = modrec->module;
aoutfile->fd = aoutfd;
v = aoutfile->funcs = modrec->funcs;
2003-11-14 17:48:57 +01:00
/*
* Get the a.out header
*/
aoutfile->header =
(AOUTHDR *) _LoaderFileToMem(aoutfd, 0, sizeof(AOUTHDR),
"header");
header = (AOUTHDR *) aoutfile->header;
2003-11-14 17:48:57 +01:00
/*
* Load the 6 other sections
*/
/* text */
if (header->a_text != 0) {
aoutfile->text = _LoaderFileToMem(aoutfile->fd,
2003-11-14 17:48:57 +01:00
AOUT_TXTOFF(header),
header->a_text, "text");
aoutfile->textsize = header->a_text;
} else {
aoutfile->text = NULL;
}
/* data */
if (header->a_data != 0) {
aoutfile->data = _LoaderFileToMem(aoutfile->fd,
AOUT_DATOFF(header),
header->a_data, "data");
aoutfile->datasize = header->a_data;
} else {
aoutfile->data = NULL;
}
/* bss */
if (header->a_bss != 0) {
aoutfile->bss = xf86loadercalloc(1, header->a_bss);
aoutfile->bsssize = header->a_bss;
} else {
aoutfile->bss = NULL;
}
/* Text Relocations */
if (header->a_trsize != 0) {
aoutfile->txtrel = _LoaderFileToMem(aoutfile->fd,
AOUT_TRELOFF(header),
header->a_trsize, "txtrel");
} else {
aoutfile->txtrel = NULL;
}
/* Data Relocations */
if (header->a_drsize != 0) {
aoutfile->datarel = _LoaderFileToMem(aoutfile->fd,
AOUT_DRELOFF(header),
header->a_drsize, "datarel");
2003-11-14 17:48:57 +01:00
} else {
aoutfile->datarel = NULL;
}
/* String table */
_LoaderFileRead(aoutfile->fd, AOUT_STROFF(header),
2003-11-14 17:48:57 +01:00
&(aoutfile->strsize), sizeof(int));
if (aoutfile->strsize != 0) {
aoutfile->strings = _LoaderFileToMem(aoutfile->fd,
AOUT_STROFF(header),
aoutfile->strsize, "strings");
} else {
aoutfile->strings = NULL;
}
/* load symbol table */
*ppLookup = AOUT_GetSymbols(aoutfile);
/* Do relocations */
reloc = AOUTCollectRelocations(aoutfile);
if (reloc) {
for (tail = reloc; tail->next; tail = tail->next) ;
2003-11-14 17:48:57 +01:00
tail->next = _LoaderGetRelocations(v)->aout_reloc;
_LoaderGetRelocations(v)->aout_reloc = reloc;
}
return (void *)aoutfile;
}
void
AOUTResolveSymbols(void *mod)
2003-11-14 17:48:57 +01:00
{
AOUTRelocPtr newlist, p, tmp;
#ifdef AOUTDEBUG
AOUTDEBUG("AOUTResolveSymbols()\n");
#endif
newlist = 0;
for (p = _LoaderGetRelocations(mod)->aout_reloc; p;) {
2003-11-14 17:48:57 +01:00
tmp = AOUT_RelocateEntry(p->file, p->type, 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)->aout_reloc = newlist;
} /* AOUTResolveSymbols */
2003-11-14 17:48:57 +01:00
int
AOUTCheckForUnresolved(void *mod)
2003-11-14 17:48:57 +01:00
{
int symnum;
AOUTRelocPtr crel;
char *name;
int fatalsym = 0, flag;
#ifdef AOUTDEBUG
AOUTDEBUG("AOUTCheckForUnResolved()\n");
#endif
if ((crel = _LoaderGetRelocations(mod)->aout_reloc) == NULL)
return 0;
while (crel) {
if (crel->type == AOUT_TEXT) {
/* Attempt to make unresolved text references
* point to a default function */
AOUT_Relocate((unsigned long *)(crel->file->text
+ crel->rel->r_address),
(unsigned long)LoaderDefaultFunc,
2003-11-14 17:48:57 +01:00
crel->rel->r_pcrel);
}
symnum = crel->rel->r_symbolnum;
name = AOUTGetSymbolName(crel->file, crel->file->symtab + symnum);
flag = _LoaderHandleUnresolved(name,
_LoaderHandleToName(crel->file->
handle));
2003-11-14 17:48:57 +01:00
xf86loaderfree(name);
if (flag)
fatalsym = 1;
2003-11-14 17:48:57 +01:00
crel = crel->next;
}
return fatalsym;
}
void
AOUTUnloadModule(void *modptr)
{
AOUTModulePtr aoutfile = (AOUTModulePtr) modptr;
2003-11-14 17:48:57 +01:00
AOUTRelocPtr relptr, *prevptr;
2003-11-14 17:48:57 +01:00
#ifdef AOUTDEBUG
AOUTDEBUG("AOUTUnLoadModule(0x%p)\n", modptr);
#endif
/*
* Delete any unresolved relocations
*/
relptr = _LoaderGetRelocations(aoutfile->funcs)->aout_reloc;
prevptr = &(_LoaderGetRelocations(aoutfile->funcs)->aout_reloc);
2003-11-14 17:48:57 +01:00
while (relptr) {
if (relptr->file == aoutfile) {
*prevptr = relptr->next;
xf86loaderfree(relptr);
relptr = *prevptr;
} else {
prevptr = &(relptr->next);
relptr = relptr->next;
}
} /* while */
2003-11-14 17:48:57 +01:00
/* clean the symbols table */
LoaderHashTraverse((void *)aoutfile, AOUTHashCleanOut);
#define CheckandFree(ptr,size) if(ptr) _LoaderFreeFileMem((ptr),(size))
CheckandFree(aoutfile->strings, aoutfile->strsize);
CheckandFree(aoutfile->symtab, aoutfile->header->a_syms);
CheckandFree(aoutfile->datarel, aoutfile->header->a_drsize);
CheckandFree(aoutfile->txtrel, aoutfile->header->a_trsize);
CheckandFree(aoutfile->data, aoutfile->header->a_data);
CheckandFree(aoutfile->text, aoutfile->header->a_text);
2003-11-14 17:48:57 +01:00
/* Free allocated sections */
if (aoutfile->bss != NULL) {
xf86loaderfree(aoutfile->bss);
}
if (aoutfile->common != NULL) {
xf86loaderfree(aoutfile->common);
}
/* Free header */
_LoaderFreeFileMem(aoutfile->header, sizeof(AOUTHDR));
/* Free the module structure itself */
xf86loaderfree(aoutfile);
return;
}
char *
AOUTAddressToSection(void *modptr, unsigned long address)
{
AOUTModulePtr aoutfile = (AOUTModulePtr) modptr;
if (address >= (unsigned long)aoutfile->text &&
address <= (unsigned long)aoutfile->text + aoutfile->textsize) {
return "text";
}
if (address >= (unsigned long)aoutfile->data &&
address <= (unsigned long)aoutfile->data + aoutfile->datasize) {
return "data";
}
if (address >= (unsigned long)aoutfile->bss &&
address <= (unsigned long)aoutfile->bss + aoutfile->bsssize) {
return "bss";
}
2003-11-14 17:48:57 +01:00
return NULL;
}