diff options
author | Daniel Stone <daniel@fooishbar.org> | 2006-06-01 20:18:30 +0000 |
---|---|---|
committer | Daniel Stone <daniel@fooishbar.org> | 2006-06-01 20:18:30 +0000 |
commit | c9468177486833d521ec62c7b0266b4be8200de7 (patch) | |
tree | 5d6976c35147d5d16c22350032661a37f53d8f5f /hw/xfree86/loader/elfloader.c | |
parent | a3a4221495dfe4cc0a3874a08dd5364ef45a7f2e (diff) |
Kill a.out, COFF and ELF loaders with FIRE.
Diffstat (limited to 'hw/xfree86/loader/elfloader.c')
-rw-r--r-- | hw/xfree86/loader/elfloader.c | 3335 |
1 files changed, 0 insertions, 3335 deletions
diff --git a/hw/xfree86/loader/elfloader.c b/hw/xfree86/loader/elfloader.c deleted file mode 100644 index bcc6686f4..000000000 --- a/hw/xfree86/loader/elfloader.c +++ /dev/null @@ -1,3335 +0,0 @@ -/* $XdotOrg: xserver/xorg/hw/xfree86/loader/elfloader.c,v 1.10.12.1 2006/02/24 05:49:34 krh Exp $ */ -/* $XFree86: xc/programs/Xserver/hw/xfree86/loader/elfloader.c,v 1.61tsi Exp $ */ - -/* - * - * Copyright 1995-1998 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> -#ifndef __UNIXOS2__ -#include <sys/mman.h> -#endif -#include <unistd.h> -#include <stdlib.h> -#ifdef __QNX__ -# include <fcntl.h> -#else -# include <sys/fcntl.h> -#endif -#include <sys/stat.h> -#if defined(linux) && defined (__ia64__) -#include <sys/mman.h> -#endif - -#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 "elf.h" - -#include "sym.h" -#include "loader.h" - -#include "compiler.h" - -#ifndef LOADERDEBUG -#define LOADERDEBUG 0 -#endif - -#if LOADERDEBUG -# define ELFDEBUG ErrorF -#endif - -#if defined(__ia64__) - -/* - * R_IA64_LTOFF22X and R_IA64_LDXMOV are relocation optimizations for - * IA64. Conforming implementations must recognize them and may either - * implement the optimization or may fallback to previous - * non-optimized behavior by treating R_IA64_LTOFF22X as a - * R_IA64_LTOFF22 and ignoring R_IA64_LDXMOV. The - * IA64_LDX_OPTIMIZATION conditional controls the fallback behavior, - * if defined the optimizations are performed. - * - * To implement the optimization we want to change is the sequence on - * the left to that on the right, without regard to any intervening - * instructions: - * - * 1) addl t1=@ltoff(var),gp ==> addl t1=@gprel(var),gp - * 2) ld8 t2=[t1] ==> mov t2=t1 - * 3) ld8 loc0=[t2] ==> ld8 loc0=[t2] - * - * The relocations that match the above instructions are: - * - * 1) R_IA64_LTOFF22 ==> R_IA64_LTOFF22X - * 2) -- ==> R_IA64_LDXMOV - * 3) -- ==> -- - * - * First lets look at left hand column to understand the original - * mechanism. The virtual address of a symbol is stored in the GOT, - * when that symbol is referenced the following sequence occurs, - * instruction 1 loads the address of the GOT entry containing the - * virtural address of the symbol into t1. Instruction 2 loads the - * virtual address of the symbol into t2 by dereferencing t1. Finally - * the symbol is loaded in instruction 3 by dereferencing its virtual - * address in t2. - * - * The optimization that LTOFF22X/LDXMOV introduces is based on the - * observation we are doing an extra load (instruction 2) if we can - * generate the virtual address for the symbol without doing a lookup in - * the GOT. This is possible if the virtual address of the symbol can be - * computed via GP relative addressing. In other words the virtual - * address of the symbol is a fixed offset from the GP. This fixed offset - * must be within the limits of the signed 22 bit immediate offset in the - * ld8 instruction, otherwise the original indirect GOT lookup must be - * performed (LTOFF22). - * - * If we can use GP relative addressing for the symbol then the - * instruction that loaded the virtual address of the symbol into t2 must - * also be patched, hence the introduction of the LDXMOV relocation. The - * LDXMOV essentially turns the GOT lookup into a no-op by changing the - * ld8 into a register move that preserves the register location of the - * symbol's virtual address (e.g. t2). - * - * The important point to recognize when implementing the LTOFF22X/LDXMOV - * optimization is that relocations are interdependent, the LDXMOV is - * only applied if the LTOFF22X is applied. It is also worth noting that - * there is no relationship between LDXMOV relocations and LTOFF22X in - * the ELF relocation section other than they share the same - * symbol+addend value. - */ - -#define IA64_LDX_OPTIMIZATION 1 -#endif - -#ifndef UseMMAP -# if defined (__ia64__) || defined (__sparc__) -# define MergeSectionAlloc -# endif -#endif - -#if defined (DoMMAPedMerge) -# include <sys/mman.h> -# define MergeSectionAlloc -# define MMAP_PROT (PROT_READ | PROT_WRITE | PROT_EXEC) -# if !defined(linux) -# error No MAP_ANON? -# endif -# if !defined (__amd64__) || !defined(__linux__) -# define MMAP_FLAGS (MAP_PRIVATE | MAP_ANON) -# else -# define MMAP_FLAGS (MAP_PRIVATE | MAP_ANON | MAP_32BIT) -# endif -# if defined (MmapPageAlign) -# define MMAP_ALIGN(size) do { \ - int pagesize = getpagesize(); \ - size = ( size + pagesize - 1) / pagesize; \ - size *= pagesize; \ - } while (0); -# else -# define MMAP_ALIGN(size) -# endif -#endif - -#if defined (__alpha__) || \ - defined (__ia64__) || \ - defined (__amd64__) || \ - (defined (__sparc__) && \ - (defined (__arch64__) || \ - defined (__sparcv9))) -typedef Elf64_Ehdr Elf_Ehdr; -typedef Elf64_Shdr Elf_Shdr; -typedef Elf64_Sym Elf_Sym; -typedef Elf64_Rel Elf_Rel; -typedef Elf64_Rela Elf_Rela; -typedef Elf64_Addr Elf_Addr; -typedef Elf64_Half Elf_Half; -typedef Elf64_Off Elf_Off; -typedef Elf64_Sword Elf_Sword; -typedef Elf64_Word Elf_Word; - -#define ELF_ST_BIND ELF64_ST_BIND -#define ELF_ST_TYPE ELF64_ST_TYPE -#define ELF_R_SYM ELF64_R_SYM -#define ELF_R_TYPE ELF64_R_TYPE - -# if defined (__alpha__) || defined (__ia64__) -/* - * The GOT is allocated dynamically. We need to keep a list of entries that - * have already been added to the GOT. - * - */ -typedef struct _elf_GOT_Entry { - Elf_Rela *rel; - int offset; - struct _elf_GOT_Entry *next; -} ELFGotEntryRec, *ELFGotEntryPtr; - -typedef struct _elf_GOT { - unsigned int size; - unsigned int nuses; - unsigned char *freeptr; - struct _elf_GOT *next; - unsigned char section[1]; -} ELFGotRec, *ELFGotPtr; - -# ifdef MergeSectionAlloc -static ELFGotPtr ELFSharedGOTs; -# endif -# endif - -# if defined (__ia64__) -/* - * The PLT is allocated dynamically. We need to keep a list of entries that - * have already been added to the PLT. - */ -typedef struct _elf_PLT_Entry { - Elf_Rela *rel; - int offset; - int gotoffset; - struct _elf_PLT_Entry *next; -} ELFPltEntryRec, *ELFPltEntryPtr; - -/* - * The OPD is allocated dynamically within the GOT. We need to keep a list - * of entries that have already been added to the OPD. - */ -typedef struct _elf_OPD { - LOOKUP *l; - int index; - int offset; - struct _elf_OPD *next; -} ELFOpdRec, *ELFOpdPtr; -# endif - -#else -typedef Elf32_Ehdr Elf_Ehdr; -typedef Elf32_Shdr Elf_Shdr; -typedef Elf32_Sym Elf_Sym; -typedef Elf32_Rel Elf_Rel; -typedef Elf32_Rela Elf_Rela; -typedef Elf32_Addr Elf_Addr; -typedef Elf32_Half Elf_Half; -typedef Elf32_Off Elf_Off; -typedef Elf32_Sword Elf_Sword; -typedef Elf32_Word Elf_Word; - -#define ELF_ST_BIND ELF32_ST_BIND -#define ELF_ST_TYPE ELF32_ST_TYPE -#define ELF_R_SYM ELF32_R_SYM -#define ELF_R_TYPE ELF32_R_TYPE -#endif - -#if defined(__powerpc__) || \ - defined(__mc68000__) || \ - defined(__alpha__) || \ - defined(__sparc__) || \ - defined(__ia64__) || \ - defined(__amd64__) -typedef Elf_Rela Elf_Rel_t; -#else -typedef Elf_Rel Elf_Rel_t; -#endif - -typedef struct { - void *saddr; - char *name; - int ndx; - int size; - int flags; -} LoadSection; - -#define RELOC_SECTION 0x1 -#define LOADED_SECTION 0x2 - -/* - * 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; - Elf_Ehdr *header; /* file header */ - int numsh; - Elf_Shdr *sections; /* Address of the section header table */ - int secsize; /* size of the section table */ - unsigned char **saddr; /* Start addresss of the section pointer table */ - unsigned char *shstraddr; /* Start address of the section header string table */ - int shstrndx; /* index of the section header string table */ - int shstrsize; /* size of the section header string table */ -#if defined(__alpha__) || defined(__ia64__) - unsigned char *got; /* Start address of the .got section */ - ELFGotEntryPtr got_entries; /* List of entries in the .got section */ - int gotndx; /* index of the .got section */ - int gotsize; /* actual size of the .got section */ - ELFGotPtr shared_got; /* Pointer to ELFGotRec if shared */ -#endif /*(__alpha__) || (__ia64__) */ -#if defined(__ia64__) - ELFOpdPtr opd_entries; /* List of entries in the .opd section */ - unsigned char *plt; /* Start address of the .plt section */ - ELFPltEntryPtr plt_entries; /* List of entries in the .plt section */ - int pltndx; /* index of the .plt section */ - int pltsize; /* size of the .plt section */ -#endif /*__ia64__*/ - Elf_Sym *symtab; /* Start address of the .symtab section */ - int symndx; /* index of the .symtab section */ - unsigned char *common; /* Start address of the SHN_COMMON space */ - int comsize; /* size of the SHN_COMMON space */ - - unsigned char *base; /* Alloced address of section block */ - unsigned long baseptr; /* Pointer to next free space in base */ - int basesize; /* Size of that allocation */ - unsigned char *straddr; /* Start address of the string table */ - int strndx; /* index of the string table */ - int strsize; /* size of the string table */ - LoadSection *lsection; - int lsectidx; -} ELFModuleRec, *ELFModulePtr; - -/* - * If a relocation is unable to be satisfied, then put it on a list - * to try later after more modules have been loaded. - */ -typedef struct _elf_reloc { - Elf_Rel_t *rel; - ELFModulePtr file; - Elf_Word secn; - struct _elf_reloc *next; -} ELFRelocRec; - -/* - * symbols with a st_shndx of COMMON need to have space allocated for them. - * - * Gather all of these symbols together, and allocate one chunk when we - * are done. - */ -typedef struct _elf_COMMON { - Elf_Sym *sym; - struct _elf_COMMON *next; -} ELFCommonRec; - -static ELFCommonPtr listCOMMON = NULL; - -/* Prototypes for static functions */ -static int ELFhashCleanOut(void *, itemPtr); -static char *ElfGetStringIndex(ELFModulePtr, int, int); -static char *ElfGetString(ELFModulePtr, int); -static char *ElfGetSectionName(ELFModulePtr, int); -static ELFRelocPtr ElfDelayRelocation(ELFModulePtr, Elf_Word, Elf_Rel_t *); -static ELFCommonPtr ElfAddCOMMON(Elf_Sym *); -static int ElfCOMMONSize(void); -static int ElfCreateCOMMON(ELFModulePtr, LOOKUP *); -static char *ElfGetSymbolNameIndex(ELFModulePtr, int, int); -static char *ElfGetSymbolName(ELFModulePtr, int); -static Elf_Addr ElfGetSymbolValue(ELFModulePtr, int); -static ELFRelocPtr Elf_RelocateEntry(ELFModulePtr, Elf_Word, Elf_Rel_t *, - int); -static ELFRelocPtr ELFCollectRelocations(ELFModulePtr, int); -static LOOKUP *ELF_GetSymbols(ELFModulePtr, unsigned short **); -static void ELFCollectSections(ELFModulePtr, int, int *, int *); - -#if defined(__alpha__) || defined(__ia64__) -static void ElfAddGOT(ELFModulePtr, Elf_Rel_t *); -static int ELFCreateGOT(ELFModulePtr, int); -#endif -#if defined(__ia64__) -static void ElfAddOPD(ELFModulePtr, int, LOOKUP *); -static void ELFCreateOPD(ELFModulePtr); -static void ElfAddPLT(ELFModulePtr, Elf_Rel_t *); -static void ELFCreatePLT(ELFModulePtr); -enum ia64_operand { - IA64_OPND_IMM22, - IA64_OPND_TGT25C, - IA64_OPND_LDXMOV -}; -static void IA64InstallReloc(unsigned long *, int, enum ia64_operand, long); -#endif /*__ia64__*/ - -#ifdef MergeSectionAlloc -static void * -ELFLoaderSectToMem(ELFModulePtr elffile, int align, unsigned long offset, - int size, char *label) -{ - void *ret; - - elffile->baseptr = (elffile->baseptr + align - 1) & ~(align - 1); - ret = (void *)elffile->baseptr; - _LoaderFileRead(elffile->fd, offset, ret, size); - elffile->baseptr += size; - return ret; -} - -static void * -ELFLoaderSectCalloc(ELFModulePtr elffile, int align, int size) -{ - void *ret; - - elffile->baseptr = (elffile->baseptr + align - 1) & ~(align - 1); - ret = (void *)elffile->baseptr; - elffile->baseptr += size; -#ifndef DoMMAPedMerge - memset(ret, 0, size); /* mmap() does this for us */ -#endif - return ret; -} -#else /* MergeSectionAlloc */ -# define ELFLoaderSectToMem(elffile,align,offset,size,label) \ -_LoaderFileToMem((elffile)->fd,offset,size,label) -# define ELFLoaderSectCalloc(elffile,align,size) xf86loadercalloc(1,size) -#endif - -/* - * Utility Functions - */ - -static int -ELFhashCleanOut(void *voidptr, itemPtr item) -{ - ELFModulePtr module = (ELFModulePtr) voidptr; - - return (module->handle == item->handle); -} - -/* - * Manage listResolv - */ -static ELFRelocPtr -ElfDelayRelocation(ELFModulePtr elffile, Elf_Word secn, Elf_Rel_t *rel) -{ - ELFRelocPtr reloc; - - if ((reloc = xf86loadermalloc(sizeof(ELFRelocRec))) == NULL) { - ErrorF("ElfDelayRelocation() Unable to allocate memory!!!!\n"); - return 0; - } - reloc->file = elffile; - reloc->secn = secn; - reloc->rel = rel; - reloc->next = 0; -#ifdef ELFDEBUG - ELFDEBUG("ElfDelayRelocation %p: file %p, sec %d," - " r_offset 0x%lx, r_info 0x%x", - (void *)reloc, (void *)elffile, secn, - (unsigned long)rel->r_offset, rel->r_info); -# if defined(__powerpc__) || \ - defined(__mc68000__) || \ - defined(__alpha__) || \ - defined(__sparc__) || \ - defined(__ia64__) || \ - defined(__amd64__) - ELFDEBUG(", r_addend 0x%lx", rel->r_addend); -# endif - ELFDEBUG("\n"); -#endif - return reloc; -} - -/* - * Manage listCOMMON - */ -static ELFCommonPtr -ElfAddCOMMON(Elf_Sym *sym) -{ - ELFCommonPtr common; - - if ((common = xf86loadermalloc(sizeof(ELFCommonRec))) == NULL) { - ErrorF("ElfAddCOMMON() Unable to allocate memory!!!!\n"); - return 0; - } - common->sym = sym; - common->next = 0; - return common; -} - -static int -ElfCOMMONSize(void) -{ - int size = 0; - ELFCommonPtr common; - - for (common = listCOMMON; common; common = common->next) { - size += common->sym->st_size; -#if defined(__alpha__) || \ - defined(__ia64__) || \ - defined(__amd64__) || \ - (defined(__sparc__) && \ - (defined(__arch64__) || \ - defined(__sparcv9))) - size = (size + 7) & ~0x7; -#endif - } - return size; -} - -static int -ElfCreateCOMMON(ELFModulePtr elffile, LOOKUP *pLookup) -{ - int numsyms = 0, size = 0, l = 0; - int offset = 0, firstcommon = 0; - ELFCommonPtr common; - - if (listCOMMON == NULL) - return TRUE; - - for (common = listCOMMON; common; common = common->next) { - size += common->sym->st_size; -#if defined(__alpha__) || \ - defined(__ia64__) || \ - defined(__amd64__) || \ - (defined(__sparc__) && \ - (defined(__arch64__) || \ - defined(__sparcv9))) - size = (size + 7) & ~0x7; -#endif - numsyms++; - } - -#ifdef ELFDEBUG - ELFDEBUG("ElfCreateCOMMON() %d entries (%d bytes) of COMMON data\n", - numsyms, size); -#endif - - elffile->comsize = size; - if ((elffile->common = ELFLoaderSectCalloc(elffile, 8, size)) == NULL) { - ErrorF("ElfCreateCOMMON() Unable to allocate memory!!!!\n"); - return FALSE; - } - - if (DebuggerPresent) { - ldrCommons = xf86loadermalloc(numsyms * sizeof(LDRCommon)); - nCommons = numsyms; - } - - for (l = 0; pLookup[l].symName; l++) ; - firstcommon = l; - - /* 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; - /* this is xstrdup because is should be more efficient. it is freed - * with xf86loaderfree - */ - pLookup[l].symName = - xf86loaderstrdup(ElfGetString(elffile, common->sym->st_name)); - pLookup[l].offset = (funcptr) (elffile->common + offset); -#ifdef ELFDEBUG - ELFDEBUG("Adding common %p %s\n", - (void *)pLookup[l].offset, pLookup[l].symName); -#endif - - /* Record the symbol address for gdb */ - if (DebuggerPresent && ldrCommons) { - ldrCommons[l - firstcommon].addr = (void *)pLookup[l].offset; - ldrCommons[l - firstcommon].name = pLookup[l].symName; - ldrCommons[l - firstcommon].namelen = strlen(pLookup[l].symName); - } - listCOMMON = common->next; - offset += common->sym->st_size; -#if defined(__alpha__) || \ - defined(__ia64__) || \ - defined(__amd64__) || \ - (defined(__sparc__) && \ - (defined(__arch64__) || \ - defined(__sparcv9))) - offset = (offset + 7) & ~0x7; -#endif - xf86loaderfree(common); - l++; - } - /* listCOMMON == 0 */ - pLookup[l].symName = NULL; /* Terminate the list. */ - return TRUE; -} - -/* - * String Table - */ -static char * -ElfGetStringIndex(ELFModulePtr file, int offset, int index) -{ - if (!offset || !index) - return ""; - - return (char *)(file->saddr[index] + offset); -} - -static char * -ElfGetString(ELFModulePtr file, int offset) -{ - return ElfGetStringIndex(file, offset, file->strndx); -} - -static char * -ElfGetSectionName(ELFModulePtr file, int offset) -{ - return (char *)(file->shstraddr + offset); -} - -/* - * Symbol Table - */ - -/* - * Get symbol name - */ -static char * -ElfGetSymbolNameIndex(ELFModulePtr elffile, int index, int secndx) -{ - Elf_Sym *syms; - -#ifdef ELFDEBUG - ELFDEBUG("ElfGetSymbolNameIndex(%x,%x) ", index, secndx); -#endif - - syms = (Elf_Sym *) elffile->saddr[secndx]; - -#ifdef ELFDEBUG - ELFDEBUG("%s ", ElfGetString(elffile, syms[index].st_name)); - ELFDEBUG("%x %x ", ELF_ST_BIND(syms[index].st_info), - ELF_ST_TYPE(syms[index].st_info)); - ELFDEBUG("%lx\n", (unsigned long)syms[index].st_value); -#endif - - return ElfGetString(elffile, syms[index].st_name); -} - -static char * -ElfGetSymbolName(ELFModulePtr elffile, int index) -{ - return ElfGetSymbolNameIndex(elffile, index, elffile->symndx); -} - -static Elf_Addr -ElfGetSymbolValue(ELFModulePtr elffile, int index) -{ - Elf_Sym *syms; - Elf_Addr symval = 0; /* value of the indicated symbol */ - char *symname = NULL; /* name of symbol in relocation */ - itemPtr symbol = NULL; /* name/value of symbol */ - - syms = (Elf_Sym *) elffile->saddr[elffile->symndx]; - - switch (ELF_ST_TYPE(syms[index].st_info)) { - case STT_NOTYPE: - case STT_OBJECT: - case STT_FUNC: - switch (ELF_ST_BIND(syms[index].st_info)) { - case STB_LOCAL: - symval = (Elf_Addr) (elffile->saddr[syms[index].st_shndx] + - syms[index].st_value); -#ifdef __ia64__ - if (ELF_ST_TYPE(syms[index].st_info) == STT_FUNC) { - ELFOpdPtr opdent; - - for (opdent = elffile->opd_entries; opdent; - opdent = opdent->next) - if (opdent->index == index) - break; - if (opdent) { - ((unsigned long *)(elffile->got + opdent->offset))[0] = - symval; - ((unsigned long *)(elffile->got + opdent->offset))[1] = - (long)elffile->got; - symval = (Elf_Addr) (elffile->got + opdent->offset); - } - } -#endif - break; - case STB_GLOBAL: - case STB_WEAK: /* STB_WEAK seems like a hack to cover for - * some other problem */ - symname = ElfGetString(elffile, syms[index].st_name); - symbol = LoaderHashFind(symname); - if (symbol == 0) { - return 0; - } - symval = (Elf_Addr) symbol->address; - break; - default: - symval = 0; - ErrorF("ElfGetSymbolValue(), unhandled symbol scope %x\n", - ELF_ST_BIND(syms[index].st_info)); - break; - } -#ifdef ELFDEBUG - ELFDEBUG("%p\t", (void *)symbol); - ELFDEBUG("%lx\t", (unsigned long)symval); - ELFDEBUG("%s\n", symname ? symname : "NULL"); -#endif - break; - case STT_SECTION: - symval = (Elf_Addr) elffile->saddr[syms[index].st_shndx]; -#ifdef ELFDEBUG - ELFDEBUG("ST_SECTION %lx\n", (unsigned long)symval); -#endif - break; - case STT_FILE: - case STT_LOPROC: - case STT_HIPROC: - default: - symval = 0; - ErrorF("ElfGetSymbolValue(), unhandled symbol type %x\n", - ELF_ST_TYPE(syms[index].st_info)); - break; - } - return symval; -} - -#if defined(__powerpc__) -/* - * This function returns the address of a pseudo PLT routine which can - * be used to compute a function offset. This is needed because loaded - * modules have an offset from the .text section of greater than 24 bits. - * The code generated makes the assumption that all function entry points - * will be within a 24 bit offset (non-PIC code). - */ -static Elf_Addr -ElfGetPltAddr(ELFModulePtr elffile, int index) -{ - Elf_Sym *syms; - Elf_Addr symval = 0; /* value of the indicated symbol */ - char *symname = NULL; /* name of symbol in relocation */ - itemPtr symbol; /* name/value of symbol */ - - syms = (Elf_Sym *) elffile->saddr[elffile->symndx]; - - switch (ELF_ST_TYPE(syms[index].st_info)) { - case STT_NOTYPE: - case STT_OBJECT: - case STT_FUNC: - switch (ELF_ST_BIND(syms[index].st_info)) { - case STB_GLOBAL: - symname = ElfGetString(elffile, syms[index].st_name); - symbol = LoaderHashFind(symname); - if (symbol == 0) - return 0; -/* - * Here we are building up a pseudo Plt function that can make a call to - * a function that has an offset greater than 24 bits. The following code - * is being used to implement this. - - 1 00000000 .extern realfunc - 2 00000000 .global pltfunc - 3 00000000 pltfunc: - 4 00000000 3d 80 00 00 lis r12,hi16(realfunc) - 5 00000004 61 8c 00 00 ori r12,r12,lo16(realfunc) - 6 00000008 7d 89 03 a6 mtctr r12 - 7 0000000c 4e 80 04 20 bctr - - */ - - symbol->code.plt[0] = 0x3d80; /* lis r12 */ - symbol->code.plt[1] = - (((Elf_Addr) symbol->address) & 0xffff0000) >> 16; - symbol->code.plt[2] = 0x618c; /* ori r12,r12 */ - symbol->code.plt[3] = (((Elf_Addr) symbol->address) & 0xffff); - symbol->code.plt[4] = 0x7d89; /* mtcr r12 */ - symbol->code.plt[5] = 0x03a6; - symbol->code.plt[6] = 0x4e80; /* bctr */ - symbol->code.plt[7] = 0x0420; - symbol->address = (char *)&symbol->code.plt[0]; - symval = (Elf_Addr) symbol->address; - ppc_flush_icache(&symbol->code.plt[0]); - ppc_flush_icache(&symbol->code.plt[6]); - break; - default: - symval = 0; - ErrorF("ElfGetPltAddr(), unhandled symbol scope %x\n", - ELF_ST_BIND(syms[index].st_info)); - break; - } -# ifdef ELFDEBUG - ELFDEBUG("ElfGetPlt: symbol=%lx\t", symbol); - ELFDEBUG("newval=%lx\t", symval); - ELFDEBUG("name=\"%s\"\n", symname ? symname : "NULL"); -# endif - break; - case STT_SECTION: - case STT_FILE: - case STT_LOPROC: - case STT_HIPROC: - default: - symval = 0; - ErrorF("ElfGetPltAddr(), Unexpected symbol type %x", - ELF_ST_TYPE(syms[index].st_info)); - ErrorF("for a Plt request\n"); - break; - } - return symval; -} -#endif /* __powerpc__ */ - -#if defined(__alpha__) || defined(__ia64__) -/* - * Manage GOT Entries - */ -static void -ElfAddGOT(ELFModulePtr elffile, Elf_Rel_t *rel) -{ - ELFGotEntryPtr gotent; - -# ifdef ELFDEBUG - { - Elf_Sym *sym; - - sym = (Elf_Sym *) & (elffile->symtab[ELF_R_SYM(rel->r_info)]); - if (sym->st_name) { - ELFDEBUG("ElfAddGOT: Adding GOT entry for %s\n", - ElfGetSymbolName(elffile, ELF_R_SYM(rel->r_info))); - } else - ELFDEBUG("ElfAddGOT: Adding GOT entry for %s\n", - ElfGetSectionName(elffile, - elffile->sections[sym->st_shndx]. - sh_name)); - } -# endif - - for (gotent = elffile->got_entries; gotent; gotent = gotent->next) { - if (ELF_R_SYM(gotent->rel->r_info) == ELF_R_SYM(rel->r_info) && - gotent->rel->r_addend == rel->r_addend) - break; - } - - if (gotent) { -# ifdef ELFDEBUG - ELFDEBUG("Entry already present in GOT\n"); -# endif - return; - } - - if ((gotent = xf86loadermalloc(sizeof(ELFGotEntryRec))) == NULL) { - ErrorF("ElfAddGOT() Unable to allocate memory!!!!\n"); - return; - } -# ifdef ELFDEBUG - ELFDEBUG("Entry added with offset %x\n", elffile->gotsize); -# endif - gotent->rel = rel; - gotent->offset = elffile->gotsize; - gotent->next = elffile->got_entries; - elffile->got_entries = gotent; - elffile->gotsize += 8; - return; -} - -static int -ELFCreateGOT(ELFModulePtr elffile, int maxalign) -{ -# ifdef MergeSectionAlloc - ELFGotPtr gots; -# endif - int gotsize; - - /* - * XXX: Is it REALLY needed to ensure GOT's are non-null? - */ -# ifdef ELFDEBUG - ELFDEBUG("ELFCreateGOT: %x entries in the GOT\n", elffile->gotsize / 8); - - /* - * Hmmm. Someone is getting here without any got entries, but they - * may still have R_ALPHA_GPDISP relocations against the got. - */ - if (elffile->gotsize == 0) - ELFDEBUG("Module %s doesn't have any GOT entries!\n", - _LoaderModuleToName(elffile->module)); -# endif - if (elffile->gotsize == 0) - elffile->gotsize = 8; - elffile->sections[elffile->gotndx].sh_size = elffile->gotsize; - gotsize = elffile->gotsize; - -# ifdef MergeSectionAlloc -# ifdef __alpha__ -# define GOTDistance 0x100000 -# endif -# ifdef __ia64__ -# define GOTDistance 0x200000 -# endif - for (gots = ELFSharedGOTs; gots; gots = gots->next) { - if (gots->freeptr + elffile->gotsize > gots->section + gots->size) - continue; - if (gots->section > elffile->base) { - if (gots->section + gots->size - elffile->base >= GOTDistance) - continue; - } else { - if (elffile->base + elffile->basesize - gots->section >= - GOTDistance) - continue; - } - elffile->got = gots->freeptr; - elffile->shared_got = gots; - gots->freeptr = gots->freeptr + elffile->gotsize; - gots->nuses++; -# ifdef ELFDEBUG - ELFDEBUG("ELFCreateGOT: GOT address %lx in shared GOT, nuses %d\n", - elffile->got, gots->nuses); -# endif - return TRUE; - } - - gotsize += 16383 + sizeof(ELFGotRec); -# endif /*MergeSectionAlloc */ - - if ((elffile->got = xf86loadermalloc(gotsize)) == NULL) { - ErrorF("ELFCreateGOT() Unable to allocate memory!!!!\n"); - return FALSE; - } -# ifdef MergeSectionAlloc - if (elffile->got > elffile->base) { - if (elffile->got + elffile->gotsize - elffile->base >= GOTDistance) - gotsize = 0; - } else { - if (elffile->base + elffile->basesize - elffile->got >= GOTDistance) - gotsize = 0; - } - - if (!gotsize) { - xf86loaderfree(elffile->got); -# if !defined(DoMMAPedMerge) - elffile->basesize += 8 + elffile->gotsize; - elffile->base = xf86loaderrealloc(elffile->base, elffile->basesize); - if (elffile->base == NULL) { - ErrorF("ELFCreateGOT() Unable to reallocate memory!!!!\n"); - return FALSE; - } -# if defined(linux) || defined(__OpenBSD__) || defined(sun) - { - unsigned long page_size = getpagesize(); - unsigned long round; - - round = (unsigned long)elffile->base & (page_size - 1); - mprotect(elffile->base - round, - (elffile->basesize + round + page_size - - 1) & ~(page_size - 1), - PROT_READ | PROT_WRITE | PROT_EXEC); - } -# endif -# else - { - int oldbasesize = elffile->basesize; - - elffile->basesize += 8 + elffile->gotsize; - MMAP_ALIGN(elffile->basesize); - elffile->base = mremap(elffile->base, oldbasesize, - elffile->basesize, MREMAP_MAYMOVE); - if (elffile->base == NULL) { - ErrorF("ELFCreateGOT() Unable to remap memory!!!!\n"); - return FALSE; - } - } -# endif - - elffile->baseptr = - ((long)elffile->base + (maxalign - 1)) & ~(maxalign - 1); - elffile->got = - (unsigned char - *)((long)(elffile->base + elffile->basesize - - elffile->gotsize) & ~7); - } else { - gots = (ELFGotPtr) elffile->got; - elffile->got = gots->section; - gots->size = gotsize - sizeof(ELFGotRec) + 1; - gots->nuses = 1; - gots->freeptr = gots->section + elffile->gotsize; - gots->next = ELFSharedGOTs; - ELFSharedGOTs = gots; - elffile->shared_got = gots; -# ifdef ELFDEBUG - ELFDEBUG("ELFCreateGOT: Created a shareable GOT with size %d\n", - gots->size); -# endif - } -# endif /*MergeSectionAlloc */ - -# ifdef ELFDEBUG - ELFDEBUG("ELFCreateGOT: GOT address %lx\n", elffile->got); -# endif - - return TRUE; -} -#endif /* defined(__alpha__) || defined(__ia64__) */ - -#if defined(__ia64__) -/* - * Manage OPD Entries - */ -static void -ElfAddOPD(ELFModulePtr elffile, int index, LOOKUP *l) -{ - ELFOpdPtr opdent; - - if (index != -1) { - for (opdent = elffile->opd_entries; opdent; opdent = opdent->next) - if (opdent->index == index) - return; - } - - if ((opdent = xf86loadermalloc(sizeof(ELFOpdRec))) == NULL) { - ErrorF("ElfAddOPD() Unable to allocate memory!!!!\n"); - return; - } -# ifdef ELFDEBUG - ELFDEBUG("OPD Entry %d added with offset %x\n", index, elffile->gotsize); -# endif - opdent->l = l; - opdent->index = index; - opdent->offset = elffile->gotsize; - opdent->next = elffile->opd_entries; - elffile->opd_entries = opdent; - elffile->gotsize += 16; - return; -} - -static void -ELFCreateOPD(ELFModulePtr elffile) -{ - ELFOpdPtr opdent; - - if (elffile->got == NULL) - ErrorF("ELFCreateOPD() Unallocated GOT!!!!\n"); - - for (opdent = elffile->opd_entries; opdent; opdent = opdent->next) { - if (opdent->index != -1) - continue; - ((unsigned long *)(elffile->got + opdent->offset))[0] = - (long)opdent->l->offset; - ((unsigned long *)(elffile->got + opdent->offset))[1] = - (long)elffile->got; - opdent->l->offset = (funcptr) (elffile->got + opdent->offset); - } -} - -/* - * Manage PLT Entries - */ -static void -ElfAddPLT(ELFModulePtr elffile, Elf_Rel_t *rel) -{ - ELFPltEntryPtr pltent; - -# ifdef ELFDEBUG - { - Elf_Sym *sym; - - sym = (Elf_Sym *) & (elffile->symtab[ELF_R_SYM(rel->r_info)]); - if (sym->st_name) { - ELFDEBUG("ElfAddPLT: Adding PLT entry for %s\n", - ElfGetSymbolName(elffile, ELF_R_SYM(rel->r_info))); - } else - ErrorF("ElfAddPLT: Add PLT entry for section??\n"); - } -# endif - - if (rel->r_addend) - ErrorF("ElfAddPLT: Add PLT entry with non-zero addend??\n"); - - for (pltent = elffile->plt_entries; pltent; pltent = pltent->next) { - if (ELF_R_SYM(pltent->rel->r_info) == ELF_R_SYM(rel->r_info)) - break; - } - - if (pltent) { -# ifdef ELFDEBUG - ELFDEBUG("Entry already present in PLT\n"); -# endif - return; - } - - if ((pltent = xf86loadermalloc(sizeof(ELFPltEntryRec))) == NULL) { - ErrorF("ElfAddPLT() Unable to allocate memory!!!!\n"); - return; - } -# ifdef ELFDEBUG - ELFDEBUG("Entry added with offset %x\n", elffile->pltsize); -# endif - pltent->rel = rel; - pltent->offset = elffile->pltsize; - pltent->gotoffset = elffile->gotsize; - pltent->next = elffile->plt_entries; - elffile->plt_entries = pltent; - elffile->pltsize += 32; - elffile->gotsize += 16; - return; -} - -static void -ELFCreatePLT(ELFModulePtr elffile) -{ -# ifdef ELFDEBUG - ELFDEBUG("ELFCreatePLT: %x entries in the PLT\n", elffile->pltsize / 8); -# endif - - if (elffile->pltsize == 0) - return; - - if ((elffile->plt = - ELFLoaderSectCalloc(elffile, 32, elffile->pltsize)) == NULL) { - ErrorF("ELFCreatePLT() Unable to allocate memory!!!!\n"); - return; - } -# if defined(linux) || defined(__OpenBSD__) || defined(sun) - { - unsigned long page_size = getpagesize(); - unsigned long round; - - round = (unsigned long)elffile->plt & (page_size - 1); - mprotect(elffile->plt - round, - (elffile->pltsize + round + page_size - 1) & ~(page_size - 1), - PROT_READ | PROT_WRITE | PROT_EXEC); - } -# endif - - elffile->sections[elffile->pltndx].sh_size = elffile->pltsize; -# ifdef ELFDEBUG - ELFDEBUG("ELFCreatePLT: PLT address %lx\n", elffile->plt); -# endif - - return; -} - -static void -IA64InstallReloc(unsigned long *data128, int slot, enum ia64_operand opnd, - long value) -{ - unsigned long data = 0; - -# ifdef ELFDEBUG - ELFDEBUG("\nIA64InstallReloc %p %d %d %016lx\n", data128, slot, opnd, - value); - ELFDEBUG("Before [%016lx%016lx]\n", data128[1], data128[0]); -# endif - switch (slot) { - case 0: - data = *data128; - break; - case 1: - memcpy(&data, (char *)data128 + 5, 8); - break; - case 2: - memcpy(&data, (char *)data128 + 10, 6); - break; - default: - FatalError("Unexpected slot in IA64InstallReloc()\n"); - } - switch (opnd) { - case IA64_OPND_IMM22: - data &= ~(0x3fff9fc0000UL << slot); - data |= (value & 0x7f) << (18 + slot); /* [13:19] + 5 + slot */ - data |= (value & 0xff80) << (25 + slot); /* [27:35] + 5 + slot */ - data |= (value & 0x1f0000) << (11 + slot); /* [22:26] + 5 + slot */ - data |= (value & 0x200000) << (20 + slot); /* [36:36] + 5 + slot */ - if (value << 42 >> 42 != value) - ErrorF("Relocation %016lx truncated to fit into IMM22\n", value); - break; - case IA64_OPND_TGT25C: - data &= ~(0x23ffffc0000UL << slot); - data |= (value & 0xfffff0) << (14 + slot); /* [13:32] + 5 + slot */ - data |= (value & 0x1000000) << (17 + slot); /* [36:36] + 5 + slot */ - if (value << 39 >> 39 != value || (value & 0xf)) - ErrorF("Relocation %016lx truncated to fit into TGT25C\n", value); - break; -#ifdef IA64_LDX_OPTIMIZATION - case IA64_OPND_LDXMOV: - /* - * Convert "ld8 t2=[t1]" to "mov t2=t1" which is really "add t2=0,t1" - * Mask all but the r3,r1,qp fields, - * then OR in the ALU opcode = 8 into the opcode field [40:37] - * - * Mask for the r3,r1,qp bit fields [26:20][12:6][5:0] = 0x7f01fff, - * This mask negated only within the 41 bit wide instruction and - * shifted left by 5 for the bundle template is 0x3FFF01FC0000 - * - * opcode field [40:37] with a value of 8 is 0x10000000000 - * shifted left by 5 for the bundle template is 0x200000000000 - * - */ - data &= ~(0x3FFF01FC0000 << slot); - data |= (0x200000000000 << slot); - break; -#endif - default: - FatalError("Unhandled operand in IA64InstallReloc()\n"); - } - switch (slot) { - case 0: - *data128 = data; - break; - case 1: - memcpy((char *)data128 + 5, &data, 8); - break; - case 2: - memcpy((char *)data128 + 10, &data, 6); - break; - default: - FatalError("Unexpected slot in IA64InstallReloc()\n"); - } - ia64_flush_cache(data128); -# ifdef ELFDEBUG - ELFDEBUG("After [%016lx%016lx]\n", data128[1], data128[0]); -# endif -} - -#endif /*__ia64__*/ - -/* - * Fix all of the relocations for the given section. - * If the argument 'force' is non-zero, then the relocation will be - * made even if the symbol can't be found (by substituting - * LoaderDefaultFunc) otherwise, the relocation will be deferred. - */ - -static ELFRelocPtr -Elf_RelocateEntry(ELFModulePtr elffile, Elf_Word secn, Elf_Rel_t *rel, - int force) -{ - unsigned char *secp = elffile->saddr[secn]; - -#if !defined(__ia64__) - unsigned int *dest32; /* address of the 32 bit place being modified */ -#endif -#if defined(__powerpc__) || defined(__sparc__) - unsigned short *dest16; /* address of the 16 bit place being modified */ -#endif -#if defined(__sparc__) - unsigned char *dest8; /* address of the 8 bit place being modified */ - unsigned long *dest64; -#endif -#if defined(__alpha__) - unsigned int *dest32h; /* address of the high 32 bit place being modified */ - unsigned long *dest64; - unsigned short *dest16; -#endif -#if defined(__amd64__) - unsigned long *dest64; - int *dest32s; -#endif -#if defined(__ia64__) - unsigned long *dest64; - unsigned long *dest128; -#endif - Elf_Addr symval = 0; /* value of the indicated symbol */ - -#ifdef ELFDEBUG - ELFDEBUG("%lx %d %d\n", (unsigned long)rel->r_offset, - ELF_R_SYM(rel->r_info), ELF_R_TYPE(rel->r_info)); -# if defined(__powerpc__) || \ - defined(__mc68000__) || \ - defined(__alpha__) || \ - defined(__sparc__) || \ - defined(__ia64__) || \ - defined(__amd64__) - ELFDEBUG("%lx", rel->r_addend); -# endif - ELFDEBUG("\n"); -#endif /*ELFDEBUG*/ -#if defined(__alpha__) - if (ELF_R_SYM(rel->r_info) - && ELF_R_TYPE(rel->r_info) != R_ALPHA_GPDISP) -#else - if (ELF_R_SYM(rel->r_info)) -#endif - { - symval = ElfGetSymbolValue(elffile, ELF_R_SYM(rel->r_info)); - if (symval == 0) { - if (force) { - symval = (Elf_Addr) & LoaderDefaultFunc; - } else { -#ifdef ELFDEBUG - ELFDEBUG("***Unable to resolve symbol %s\n", - ElfGetSymbolName(elffile, ELF_R_SYM(rel->r_info))); -#endif - return ElfDelayRelocation(elffile, secn, rel); - } - } - } - - switch (ELF_R_TYPE(rel->r_info)) { -#if defined(i386) - case R_386_32: - dest32 = (unsigned int *)(secp + rel->r_offset); -# ifdef ELFDEBUG - ELFDEBUG("R_386_32\t"); - ELFDEBUG("dest32=%p\t", (void *)dest32); - ELFDEBUG("*dest32=%8.8x\t", (unsigned int)*dest32); -# endif - *dest32 = symval + (*dest32); /* S + A */ -# ifdef ELFDEBUG - ELFDEBUG("*dest32=%8.8x\n", (unsigned int)*dest32); -# endif - break; - case R_386_PC32: - dest32 = (unsigned int *)(secp + rel->r_offset); -# ifdef ELFDEBUG - ELFDEBUG("R_386_PC32 %s\t", - ElfGetSymbolName(elffile, ELF_R_SYM(rel->r_info))); - ELFDEBUG("secp=%p\t", secp); - ELFDEBUG("symval=%lx\t", (unsigned long)symval); - ELFDEBUG("dest32=%p\t", (void *)dest32); - ELFDEBUG("*dest32=%8.8x\t", (unsigned int)*dest32); -# endif - - *dest32 = symval + (*dest32) - (Elf_Addr) dest32; /* S + A - P */ - -# ifdef ELFDEBUG - ELFDEBUG("*dest32=%8.8x\n", (unsigned int)*dest32); -# endif - - break; -#endif /* i386 */ -#if defined(__amd64__) - case R_X86_64_32: - dest32 = (unsigned int *)(secp + rel->r_offset); -# ifdef ELFDEBUG - ELFDEBUG("R_X86_32\t"); - ELFDEBUG("dest32=%x\t", dest32); - ELFDEBUG("*dest32=%8.8lx\t", *dest32); - ELFDEBUG("r_addend=%lx\t", rel->r_addend); -# endif - *dest32 = symval + rel->r_addend + (*dest32); /* S + A */ -# ifdef ELFDEBUG - ELFDEBUG("*dest32=%8.8lx\n", *dest32); -# endif - break; - case R_X86_64_32S: - dest32s = (int *)(secp + rel->r_offset); -# ifdef ELFDEBUG - ELFDEBUG("R_X86_64_32\t"); - ELFDEBUG("dest32s=%x\t", dest32s); - ELFDEBUG("*dest32s=%8.8lx\t", *dest32s); - ELFDEBUG("r_addend=%lx\t", rel->r_addend); -# endif - *dest32s = symval + rel->r_addend + (*dest32s); /* S + A */ -# ifdef ELFDEBUG - ELFDEBUG("*dest32s=%8.8lx\n", *dest32s); -# endif - break; - case R_X86_64_PC32: - dest32 = (unsigned int *)(secp + rel->r_offset); -# ifdef ELFDEBUG - ELFDEBUG("R_X86_64_PC32 %s\t", - ElfGetSymbolName(elffile, ELF_R_SYM(rel->r_info))); - ELFDEBUG("secp=%x\t", secp); - ELFDEBUG("symval=%lx\t", symval); - ELFDEBUG("dest32=%x\t", dest32); - ELFDEBUG("*dest32=%8.8lx\t", *dest32); - ELFDEBUG("r_addend=%lx\t", rel->r_addend); -# endif - *dest32 = symval + rel->r_addend + (*dest32) - (Elf_Addr) dest32; /* S + A - P */ - -# ifdef ELFDEBUG - ELFDEBUG("*dest32=%8.8lx\n", *dest32); -# endif - break; - case R_X86_64_64: - dest64 = (unsigned long *)(secp + rel->r_offset); -# ifdef ELFDEBUG - ELFDEBUG("R_AMD64_64\t"); - ELFDEBUG("dest64=%x\t", dest64); - ELFDEBUG("*dest64=%8.8lx\t", *dest64); - ELFDEBUG("r_addend=%lx\t", rel->r_addend); -# endif - *dest64 = symval + rel->r_addend + (*dest64); /* S + A */ -# ifdef ELFDEBUG - ELFDEBUG("*dest64=%8.8lx\n", *dest64); -# endif - break; -#endif /* __amd64__ */ -#if defined(__alpha__) - case R_ALPHA_NONE: - case R_ALPHA_LITUSE: - break; - - case R_ALPHA_REFQUAD: - dest64 = (unsigned long *)(secp + rel->r_offset); - symval = ElfGetSymbolValue(elffile, ELF_R_SYM(rel->r_info)); -# ifdef ELFDEBUG - ELFDEBUG("R_ALPHA_REFQUAD\t"); - ELFDEBUG("dest64=%lx\t", dest64); - ELFDEBUG("*dest64=%8.8lx\t", *dest64); -# endif - *dest64 = symval + rel->r_addend + (*dest64); /* S + A + P */ -# ifdef ELFDEBUG - ELFDEBUG("*dest64=%8.8lx\n", *dest64); -# endif - break; - - case R_ALPHA_GPREL32: - { - dest64 = (unsigned long *)(secp + rel->r_offset); - dest32 = (unsigned int *)dest64; - -# ifdef ELFDEBUG - ELFDEBUG("R_ALPHA_GPREL32 %s\t", - ElfGetSymbolName(elffile, ELF_R_SYM(rel->r_info))); - ELFDEBUG("secp=%lx\t", secp); - ELFDEBUG("symval=%lx\t", symval); - ELFDEBUG("dest32=%lx\t", dest32); - ELFDEBUG("*dest32=%8.8x\t", *dest32); -# endif - symval += rel->r_addend; - symval = ((unsigned char *)symval) - - ((unsigned char *)elffile->got); -# ifdef ELFDEBUG - ELFDEBUG("symval=%lx\t", symval); -# endif - if ((symval & 0xffffffff00000000) != 0x0000000000000000 && - (symval & 0xffffffff00000000) != 0xffffffff00000000) { - FatalError("R_ALPHA_GPREL32 symval-got is too large for %s\n", - ElfGetSymbolName(elffile, ELF_R_SYM(rel->r_info))); - } - - *dest32 = symval; -# ifdef ELFDEBUG - ELFDEBUG("*dest32=%x\n", *dest32); -# endif - break; - } - - case R_ALPHA_GPRELLOW: - { - dest64 = (unsigned long *)(secp + rel->r_offset); - dest16 = (unsigned short *)dest64; - - symval += rel->r_addend; - symval = ((unsigned char *)symval) - - ((unsigned char *)elffile->got); - - *dest16 = symval; - break; - } - - case R_ALPHA_GPRELHIGH: - { - dest64 = (unsigned long *)(secp + rel->r_offset); - dest16 = (unsigned short *)dest64; - - symval += rel->r_addend; - symval = ((unsigned char *)symval) - - ((unsigned char *)elffile->got); - symval = ((long)symval >> 16) + ((symval >> 15) & 1); - if ((long)symval > 0x7fff || (long)symval < -(long)0x8000) { - FatalError - ("R_ALPHA_GPRELHIGH symval-got is too large for %s:%lx\n", - ElfGetSymbolName(elffile, ELF_R_SYM(rel->r_info)), - symval); - } - - *dest16 = symval; - break; - } - - case R_ALPHA_LITERAL: - { - ELFGotEntryPtr gotent; - - dest32 = (unsigned int *)(secp + rel->r_offset); -# ifdef ELFDEBUG - ELFDEBUG("R_ALPHA_LITERAL %s\t", - ElfGetSymbolName(elffile, ELF_R_SYM(rel->r_info))); - ELFDEBUG("secp=%lx\t", secp); - ELFDEBUG("symval=%lx\t", symval); - ELFDEBUG("dest32=%lx\t", dest32); - ELFDEBUG("*dest32=%8.8x\t", *dest32); -# endif - - for (gotent = elffile->got_entries; gotent; gotent = gotent->next) { - if (ELF_R_SYM(gotent->rel->r_info) == ELF_R_SYM(rel->r_info) - && gotent->rel->r_addend == rel->r_addend) - break; - } - - /* Set the address in the GOT */ - if (gotent) { - *(unsigned long *)(elffile->got + gotent->offset) = - symval + rel->r_addend; -# ifdef ELFDEBUG - ELFDEBUG("Setting gotent[%x]=%lx\t", - gotent->offset, symval + rel->r_addend); -# endif - if ((gotent->offset & 0xffff0000) != 0) - FatalError("\nR_ALPHA_LITERAL offset %x too large\n", - gotent->offset); - (*dest32) |= (gotent->offset); /* The address part is always 0 */ - } else { - unsigned long val; - - /* S + A - P >> 2 */ - val = ((symval + (rel->r_addend) - (Elf_Addr) dest32)); -# ifdef ELFDEBUG - ELFDEBUG("S+A-P=%x\t", val); -# endif - if ((val & 0xffff0000) != 0xffff0000 && - (val & 0xffff0000) != 0x00000000) { - ErrorF("\nR_ALPHA_LITERAL offset %x too large\n", val); - break; - } - val &= 0x0000ffff; - (*dest32) |= (val); /* The address part is always 0 */ - } -# ifdef ELFDEBUG - ELFDEBUG("*dest32=%8.8x\n", *dest32); -# endif - - break; - } - - case R_ALPHA_GPDISP: - { - long offset; - - dest32h = (unsigned int *)(secp + rel->r_offset); - dest32 = (unsigned int *)((secp + rel->r_offset) + rel->r_addend); - -# ifdef ELFDEBUG - ELFDEBUG("R_ALPHA_GPDISP %s\t", - ElfGetSymbolName(elffile, ELF_R_SYM(rel->r_info))); - ELFDEBUG("secp=%lx\t", secp); - ELFDEBUG("got=%lx\t", elffile->got); - ELFDEBUG("dest32=%lx\t", dest32); - ELFDEBUG("*dest32=%8.8x\t", *dest32); - ELFDEBUG("dest32h=%lx\t", dest32h); - ELFDEBUG("*dest32h=%8.8x\t", *dest32h); -# endif - if ((*dest32h >> 26) != 9 || (*dest32 >> 26) != 8) { - ErrorF("***Bad instructions in relocating %s\n", - ElfGetSymbolName(elffile, ELF_R_SYM(rel->r_info))); - } - - symval = (*dest32h & 0xffff) << 16 | (*dest32 & 0xffff); - symval = (symval ^ 0x80008000) - 0x80008000; - - offset = ((unsigned char *)elffile->got - - (unsigned char *)dest32h); -# ifdef ELFDEBUG - ELFDEBUG("symval=%lx\t", symval); - ELFDEBUG("got-dest32=%lx\t", offset); -# endif - - if ((offset >= 0x7fff8000L) || (offset < -0x80000000L)) { - FatalError("Offset overflow for R_ALPHA_GPDISP\n"); - } - - symval += (unsigned long)offset; -# ifdef ELFDEBUG - ELFDEBUG("symval=%lx\t", symval); -# endif - *dest32 = (*dest32 & 0xffff0000) | (symval & 0xffff); - *dest32h = (*dest32h & 0xffff0000) | - (((symval >> 16) + ((symval >> 15) & 1)) & 0xffff); -# ifdef ELFDEBUG - ELFDEBUG("*dest32=%8.8x\t", *dest32); - ELFDEBUG("*dest32h=%8.8x\n", *dest32h); -# endif - break; - } - - case R_ALPHA_HINT: - dest32 = (unsigned int *)((secp + rel->r_offset) + rel->r_addend); -# ifdef ELFDEBUG - ELFDEBUG("R_ALPHA_HINT %s\t", - ElfGetSymbolName(elffile, ELF_R_SYM(rel->r_info))); - ELFDEBUG("secp=%lx\t", secp); - ELFDEBUG("symval=%lx\t", symval); - ELFDEBUG("dest32=%lx\t", dest32); - ELFDEBUG("*dest32=%8.8x\t", *dest32); -# endif - -# ifdef ELFDEBUG - ELFDEBUG("symval=%lx\t", symval); -# endif - symval -= (Elf_Addr) (((unsigned char *)dest32) + 4); - if (symval % 4) { - ErrorF("R_ALPHA_HINT bad alignment of offset\n"); - } - symval = symval >> 2; - -# ifdef ELFDEBUG - ELFDEBUG("symval=%lx\t", symval); -# endif - - if (symval & 0xffff8000) { -# ifdef ELFDEBUG - ELFDEBUG("R_ALPHA_HINT symval too large\n"); -# endif - } - - *dest32 = (*dest32 & ~0x3fff) | (symval & 0x3fff); - -# ifdef ELFDEBUG - ELFDEBUG("*dest32=%8.8x\n", *dest32); -# endif - break; - - case R_ALPHA_GPREL16: - { - dest64 = (unsigned long *)(secp + rel->r_offset); - dest16 = (unsigned short *)dest64; - - symval += rel->r_addend; - symval = ((unsigned char *)symval) - - ((unsigned char *)elffile->got); - if ((long)symval > 0x7fff || (long)symval < -(long)0x8000) { - FatalError - ("R_ALPHA_GPREL16 symval-got is too large for %s:%lx\n", - ElfGetSymbolName(elffile, ELF_R_SYM(rel->r_info)), - symval); - } - - *dest16 = symval; - break; - } - - case R_ALPHA_SREL32: - { - dest32 = (unsigned int *)(secp + rel->r_offset); - symval += rel->r_addend; - symval -= (unsigned long) dest32; - if ((long)symval >= 0x80000000 - || (long)symval < -(long)0x80000000) - FatalError("R_ALPHA_SREL32 overflow for %s: %lx\n", - ElfGetSymbolName(elffile, ELF_R_SYM(rel->r_info)), - symval); - *dest32 = symval; - break; - } - - case R_ALPHA_BRSGP: - { - Elf_Sym *syms; - int Delta; - - dest32 = (unsigned int *)((secp + rel->r_offset) + rel->r_addend); - -# ifdef ELFDEBUG - ELFDEBUF("R_ALPHA_BRSGP %s\t", - ElfGetSymbolName(elffile, ELF_R_SYM(rel->r_info))); - - ELFDEBUG("secp=%lx\t", secp); - ELFDEBUG("symval=%lx\t", symval); - ELFDEBUG("dest32=%lx\t", dest32); - ELFDEBUG("*dest32=%8.8x\t", *dest32); -# endif - -# ifdef ELFDEBUG - ELFDEBUG("symval=%lx\t", symval); -# endif - syms = (Elf_Sym *) elffile->saddr[elffile->symndx]; - - if (syms[ELF_R_SYM(rel->r_info)].st_other & 0x8) - Delta = -4; - else - Delta = 4; - - symval -= (Elf_Addr) (((unsigned char *)dest32) + Delta); - if (symval % 4) { - ErrorF("R_ALPHA_BRSGP bad alignment of offset\n"); - } - symval = symval >> 2; - -# ifdef ELFDEBUG - ELFDEBUG("symval=%lx\t", symval); -# endif - - if (symval & 0xffe00000) { -# ifdef ELFDEBUG - ELFDEBUG("R_ALPHA_BRSGP symval too large\n"); -# endif - } - - *dest32 = (*dest32 & ~0x1fffff) | (symval & 0x1fffff); - -# ifdef ELFDEBUG - ELFDEBUG("*dest32=%8.8x\n", *dest32); -# endif - break; - } - -#endif /* alpha */ -#if defined(__mc68000__) - case R_68K_32: - dest32 = (unsigned int *)(secp + rel->r_offset); -# ifdef ELFDEBUG - ELFDEBUG("R_68K_32\t"); - ELFDEBUG("secp=%x\t", secp); - ELFDEBUG("symval=%x\t", symval); - ELFDEBUG("r_addend=%x\t", rel->r_addend); - ELFDEBUG("dest32=%8.8x\t", dest32); - ELFDEBUG("*dest32=%8.8x\n", *dest32); -# endif - { - unsigned long val; - - /* S + A */ - val = symval + (rel->r_addend); -# ifdef ELFDEBUG - ELFDEBUG("S+A=%x\t", val); -# endif - *dest32 = val; /* S + A */ - } -# ifdef ELFDEBUG - ELFDEBUG("*dest32=%8.8x\n", *dest32); -# endif - break; - case R_68K_PC32: - dest32 = (unsigned int *)(secp + rel->r_offset); -# ifdef ELFDEBUG - ELFDEBUG("R_68K_PC32\t"); - ELFDEBUG("secp=%x\t", secp); - ELFDEBUG("symval=%x\t", symval); - ELFDEBUG("r_addend=%x\t", rel->r_addend); - ELFDEBUG("dest32=%8.8x\t", dest32); - ELFDEBUG("*dest32=%8.8x\n", *dest32); -# endif - { - unsigned long val; - - /* S + A - P */ - val = symval + (rel->r_addend); - val -= *dest32; -# ifdef ELFDEBUG - ELFDEBUG("S+A=%x\t", val); - ELFDEBUG("S+A-P=%x\t", val + (*dest32) - (Elf_Addr) dest32); -# endif - *dest32 = val + (*dest32) - (Elf_Addr) dest32; /* S + A - P */ - } -# ifdef ELFDEBUG - ELFDEBUG("*dest32=%8.8x\n", *dest32); -# endif - break; -#endif /* __mc68000__ */ -#if defined(__powerpc__) -# if defined(PowerMAX_OS) - case R_PPC_DISP24: /* 11 */ - dest32 = (unsigned long *)(secp + rel->r_offset); -# ifdef ELFDEBUG - ELFDEBUG("R_PPC_DISP24 %s\t", - ElfGetSymbolName(elffile, ELF_R_SYM(rel->r_info))); - ELFDEBUG("secp=%x\t", secp); - ELFDEBUG("symval=%x\t", symval); - ELFDEBUG("dest32=%x\t", dest32); - ELFDEBUG("*dest32=%8.8x\t", *dest32); -# endif - - { - unsigned long val; - - /* S + A - P >> 2 */ - val = ((symval + (rel->r_addend) - (Elf_Addr) dest32)); -# ifdef ELFDEBUG - ELFDEBUG("S+A-P=%x\t", val); -# endif - val = val >> 2; - if ((val & 0x3f000000) != 0x3f000000 && - (val & 0x3f000000) != 0x00000000) { -# ifdef ELFDEBUG - ELFDEBUG("R_PPC_DISP24 offset %x too large\n", val << 2); -# endif - symval = ElfGetPltAddr(elffile, ELF_R_SYM(rel->r_info)); - val = ((symval + (rel->r_addend) - (Elf_Addr) dest32)); -# ifdef ELFDEBUG - ELFDEBUG("PLT offset is %x\n", val); -# endif - val = val >> 2; - if ((val & 0x3f000000) != 0x3f000000 && - (val & 0x3f000000) != 0x00000000) - FatalError("R_PPC_DISP24 PLT offset %x too large\n", - val << 2); - } - val &= 0x00ffffff; - (*dest32) |= (val << 2); /* The address part is always 0 */ - ppc_flush_icache(dest32); - } -# ifdef ELFDEBUG - ELFDEBUG("*dest32=%8.8x\n", *dest32); -# endif - break; - case R_PPC_16HU: /* 31 */ - dest16 = (unsigned short *)(secp + rel->r_offset); -# ifdef ELFDEBUG - dest32 = (unsigned long *)(dest16 - 1); - -# endif -# ifdef ELFDEBUG - ELFDEBUG("R_PPC_16HU\t"); - ELFDEBUG("secp=%x\t", secp); - ELFDEBUG("symval=%x\t", symval); - ELFDEBUG("r_addend=%x\t", rel->r_addend); - ELFDEBUG("dest16=%x\t", dest16); - ELFDEBUG("*dest16=%8.8x\t", *dest16); - ELFDEBUG("dest32=%8.8x\t", dest32); - ELFDEBUG("*dest32=%8.8x\n", *dest32); -# endif - { - unsigned short val; - - /* S + A */ - val = ((symval + (rel->r_addend)) & 0xffff0000) >> 16; -# ifdef ELFDEBUG - ELFDEBUG("uhi16(S+A)=%x\t", val); -# endif - *dest16 = val; /* S + A */ - ppc_flush_icache(dest16); - } -# ifdef ELFDEBUG - ELFDEBUG("*dest16=%8.8x\t", *dest16); - ELFDEBUG("*dest32=%8.8x\n", *dest32); -# endif - break; - case R_PPC_32: /* 32 */ - dest32 = (unsigned long *)(secp + rel->r_offset); -# ifdef ELFDEBUG - ELFDEBUG("R_PPC_32\t"); - ELFDEBUG("secp=%x\t", secp); - ELFDEBUG("symval=%x\t", symval); - ELFDEBUG("r_addend=%x\t", rel->r_addend); - ELFDEBUG("dest32=%8.8x\t", dest32); - ELFDEBUG("*dest32=%8.8x\n", *dest32); -# endif - { - unsigned long val; - - /* S + A */ - val = symval + (rel->r_addend); -# ifdef ELFDEBUG - ELFDEBUG("S+A=%x\t", val); -# endif - *dest32 = val; /* S + A */ - ppc_flush_icache(dest32); - } -# ifdef ELFDEBUG - ELFDEBUG("*dest32=%8.8x\n", *dest32); -# endif - break; - case R_PPC_32UA: /* 33 */ - dest32 = (unsigned long *)(secp + rel->r_offset); -# ifdef ELFDEBUG - ELFDEBUG("R_PPC_32UA\t"); - ELFDEBUG("secp=%x\t", secp); - ELFDEBUG("symval=%x\t", symval); - ELFDEBUG("r_addend=%x\t", rel->r_addend); - ELFDEBUG("dest32=%8.8x\t", dest32); - ELFDEBUG("*dest32=%8.8x\n", *dest32); -# endif - { - unsigned long val; - unsigned char *dest8 = (unsigned char *)dest32; - - /* S + A */ - val = symval + (rel->r_addend); -# ifdef ELFDEBUG - ELFDEBUG("S+A=%x\t", val); -# endif - *dest8++ = (val & 0xff000000) >> 24; - *dest8++ = (val & 0x00ff0000) >> 16; - *dest8++ = (val & 0x0000ff00) >> 8; - *dest8++ = (val & 0x000000ff); - ppc_flush_icache(dest32); - } -# ifdef ELFDEBUG - ELFDEBUG("*dest32=%8.8x\n", *dest32); -# endif - break; - case R_PPC_16H: /* 34 */ - dest16 = (unsigned short *)(secp + rel->r_offset); -# ifdef ELFDEBUG - dest32 = (unsigned long *)(dest16 - 1); -# endif -# ifdef ELFDEBUG - ELFDEBUG("R_PPC_16H\t"); - ELFDEBUG("secp=%x\t", secp); - ELFDEBUG("symbol=%s\t", - ElfGetSymbolName(elffile, ELF_R_SYM(rel->r_info))); - ELFDEBUG("symval=%x\t", symval); - ELFDEBUG("r_addend=%x\t", rel->r_addend); - ELFDEBUG("dest16=%x\t", dest16); - ELFDEBUG("*dest16=%8.8x\t", *dest16); - ELFDEBUG("dest32=%8.8x\t", dest32); - ELFDEBUG("*dest32=%8.8x\n", *dest32); -# endif - { - unsigned short val; - unsigned short loval; - - /* S + A */ - val = ((symval + (rel->r_addend)) & 0xffff0000) >> 16; - loval = (symval + (rel->r_addend)) & 0xffff; - if (loval & 0x8000) { - /* - * This is hi16(), instead of uhi16(). Because of this, - * if the lo16() will produce a negative offset, then - * we have to increment this part of the address to get - * the correct final result. - */ - val++; - } -# ifdef ELFDEBUG - ELFDEBUG("hi16(S+A)=%x\t", val); -# endif - *dest16 = val; /* S + A */ - ppc_flush_icache(dest16); - } -# ifdef ELFDEBUG - ELFDEBUG("*dest16=%8.8x\t", *dest16); - ELFDEBUG("*dest32=%8.8x\n", *dest32); -# endif - break; - case R_PPC_16L: /* 35 */ - dest16 = (unsigned short *)(secp + rel->r_offset); -# ifdef ELFDEBUG - dest32 = (unsigned long *)(dest16 - 1); -# endif -# ifdef ELFDEBUG - ELFDEBUG("R_PPC_16L\t"); - ELFDEBUG("secp=%x\t", secp); - ELFDEBUG("symval=%x\t", symval); - ELFDEBUG("r_addend=%x\t", rel->r_addend); - ELFDEBUG("dest16=%x\t", dest16); - ELFDEBUG("*dest16=%8.8x\t", *dest16); - ELFDEBUG("dest32=%8.8x\t", dest32); - ELFDEBUG("*dest32=%8.8x\n", *dest32); -# endif - { - unsigned short val; - - /* S + A */ - val = (symval + (rel->r_addend)) & 0xffff; -# ifdef ELFDEBUG - ELFDEBUG("lo16(S+A)=%x\t", val); -# endif - *dest16 = val; /* S + A */ - ppc_flush_icache(dest16); - } -# ifdef ELFDEBUG - ELFDEBUG("*dest16=%8.8x\t", *dest16); - ELFDEBUG("*dest32=%8.8x\n", *dest32); -# endif - break; -# else /* PowerMAX_OS */ - /* Linux PPC */ - case R_PPC_ADDR32: /* 1 */ - dest32 = (unsigned int *)(secp + rel->r_offset); - symval = ElfGetSymbolValue(elffile, ELF_R_SYM(rel->r_info)); -# ifdef ELFDEBUG - ELFDEBUG("R_PPC_ADDR32\t"); - ELFDEBUG("secp=%x\t", secp); - ELFDEBUG("symval=%x\t", symval); - ELFDEBUG("r_addend=%x\t", rel->r_addend); - ELFDEBUG("dest32=%8.8x\t", dest32); - ELFDEBUG("*dest32=%8.8x\n", *dest32); -# endif - { - unsigned long val; - - /* S + A */ - val = symval + (rel->r_addend); -# ifdef ELFDEBUG - ELFDEBUG("S+A=%x\t", val); -# endif - *dest32 = val; /* S + A */ - ppc_flush_icache(dest32); - } -# ifdef ELFDEBUG - ELFDEBUG("*dest32=%8.8x\n", *dest32); -# endif - break; - case R_PPC_ADDR16_LO: /* 4 */ - dest16 = (unsigned short *)(secp + rel->r_offset); -# ifdef ELFDEBUG - dest32 = (unsigned long *)(dest16 - 1); -# endif -# ifdef ELFDEBUG - ELFDEBUG("R_PPC_ADDR16_LO\t"); - ELFDEBUG("secp=%x\t", secp); - ELFDEBUG("symval=%x\t", symval); - ELFDEBUG("r_addend=%x\t", rel->r_addend); - ELFDEBUG("dest16=%x\t", dest16); - ELFDEBUG("*dest16=%8.8x\t", *dest16); -# endif - { - unsigned short val; - - /* S + A */ - val = (symval + (rel->r_addend)) & 0xffff; -# ifdef ELFDEBUG - ELFDEBUG("lo16(S+A)=%x\t", val); -# endif - *dest16 = val; /* S + A */ - ppc_flush_icache(dest16); - } -# ifdef ELFDEBUG - ELFDEBUG("*dest16=%8.8x\t", *dest16); - ELFDEBUG("*dest32=%8.8x\n", *dest32); -# endif - break; - case R_PPC_ADDR16_HA: /* 6 */ - dest16 = (unsigned short *)(secp + rel->r_offset); -# ifdef ELFDEBUG - dest32 = (unsigned long *)(dest16 - 1); -# endif -# ifdef ELFDEBUG - ELFDEBUG("R_PPC_ADDR16_HA\t"); - ELFDEBUG("secp=%x\t", secp); - ELFDEBUG("symval=%x\t", symval); - ELFDEBUG("r_addend=%x\t", rel->r_addend); - ELFDEBUG("dest16=%x\t", dest16); - ELFDEBUG("*dest16=%8.8x\t", *dest16); -# endif - { - unsigned short val; - unsigned short loval; - - /* S + A */ - val = ((symval + (rel->r_addend)) & 0xffff0000) >> 16; - loval = (symval + (rel->r_addend)) & 0xffff; - if (loval & 0x8000) { - /* - * This is hi16(), instead of uhi16(). Because of this, - * if the lo16() will produce a negative offset, then - * we have to increment this part of the address to get - * the correct final result. - */ - val++; - } -# ifdef ELFDEBUG - ELFDEBUG("hi16(S+A)=%x\t", val); -# endif - *dest16 = val; /* S + A */ - ppc_flush_icache(dest16); - } -# ifdef ELFDEBUG - ELFDEBUG("*dest16=%8.8x\t", *dest16); - ELFDEBUG("*dest32=%8.8x\n", *dest32); -# endif - break; - case R_PPC_REL24: /* 10 */ - dest32 = (unsigned int *)(secp + rel->r_offset); -# ifdef ELFDEBUG - ELFDEBUG("R_PPC_REL24 %s\t", - ElfGetSymbolName(elffile, ELF_R_SYM(rel->r_info))); - ELFDEBUG("secp=%x\t", secp); - ELFDEBUG("symval=%x\t", symval); - ELFDEBUG("dest32=%x\t", dest32); - ELFDEBUG("*dest32=%8.8x\t", *dest32); -# endif - - { - unsigned long val; - - /* S + A - P >> 2 */ - val = ((symval + (rel->r_addend) - (Elf_Addr) dest32)); -# ifdef ELFDEBUG - ELFDEBUG("S+A-P=%x\t", val); -# endif - val = val >> 2; - if ((val & 0x3f000000) != 0x3f000000 && - (val & 0x3f000000) != 0x00000000) { -# ifdef ELFDEBUG - ELFDEBUG("R_PPC_REL24 offset %x too large\n", val << 2); -# endif - symval = ElfGetPltAddr(elffile, ELF_R_SYM(rel->r_info)); - val = ((symval + (rel->r_addend) - (Elf_Addr) dest32)); -# ifdef ELFDEBUG - ELFDEBUG("PLT offset is %x\n", val); -# endif - val = val >> 2; - if ((val & 0x3f000000) != 0x3f000000 && - (val & 0x3f000000) != 0x00000000) - FatalError("R_PPC_REL24 PLT offset %x too large\n", - val << 2); - } - val &= 0x00ffffff; - (*dest32) |= (val << 2); /* The address part is always 0 */ - ppc_flush_icache(dest32); - } -# ifdef ELFDEBUG - ELFDEBUG("*dest32=%8.8x\n", *dest32); -# endif - break; - case R_PPC_REL32: /* 26 */ - dest32 = (unsigned int *)(secp + rel->r_offset); -# ifdef ELFDEBUG - ELFDEBUG("R_PPC_REL32\t"); - ELFDEBUG("secp=%x\t", secp); - ELFDEBUG("symval=%x\t", symval); - ELFDEBUG("r_addend=%x\t", rel->r_addend); - ELFDEBUG("dest32=%8.8x\t", dest32); - ELFDEBUG("*dest32=%8.8x\n", *dest32); -# endif - { - unsigned long val; - - /* S + A - P */ - val = symval + (rel->r_addend); - val -= *dest32; -# ifdef ELFDEBUG - ELFDEBUG("S+A=%x\t", val); - ELFDEBUG("S+A-P=%x\t", val + (*dest32) - (Elf_Addr) dest32); -# endif - *dest32 = val + (*dest32) - (Elf_Addr) dest32; /* S + A - P */ - ppc_flush_icache(dest32); - } -# ifdef ELFDEBUG - ELFDEBUG("*dest32=%8.8x\n", *dest32); -# endif - break; -# endif /* PowerMAX_OS */ -#endif /* __powerpc__ */ -#ifdef __sparc__ - case R_SPARC_NONE: /* 0 */ - break; - - case R_SPARC_8: /* 1 */ - dest8 = (unsigned char *)(secp + rel->r_offset); - symval += rel->r_addend; - *dest8 = symval; - break; - - case R_SPARC_16: /* 2 */ - dest16 = (unsigned short *)(secp + rel->r_offset); - symval += rel->r_addend; - *dest16 = symval; - break; - - case R_SPARC_32: /* 3 */ - case R_SPARC_UA32: /* 23 */ - dest32 = (unsigned int *)(secp + rel->r_offset); - symval += rel->r_addend; - ((unsigned char *)dest32)[0] = (unsigned char)(symval >> 24); - ((unsigned char *)dest32)[1] = (unsigned char)(symval >> 16); - ((unsigned char *)dest32)[2] = (unsigned char)(symval >> 8); - ((unsigned char *)dest32)[3] = (unsigned char)(symval); - break; - - case R_SPARC_GLOB_DAT: /* 20 */ - case R_SPARC_64: /* 32 */ - dest64 = (unsigned long *)(secp + rel->r_offset); - symval += rel->r_addend; - *dest64 = symval; - break; - - case R_SPARC_DISP8: /* 4 */ - dest8 = (unsigned char *)(secp + rel->r_offset); - symval += rel->r_addend; - *dest8 = (symval - (Elf_Addr) dest8); - break; - - case R_SPARC_DISP16: /* 5 */ - dest16 = (unsigned short *)(secp + rel->r_offset); - symval += rel->r_addend; - *dest16 = (symval - (Elf_Addr) dest16); - break; - - case R_SPARC_DISP32: /* 6 */ - dest32 = (unsigned int *)(secp + rel->r_offset); - symval += rel->r_addend; - *dest32 = (symval - (Elf_Addr) dest32); - break; - - case R_SPARC_WDISP30: /* 7 */ - dest32 = (unsigned int *)(secp + rel->r_offset); - symval += rel->r_addend; - *dest32 = ((*dest32 & 0xc0000000) | - (((symval - (Elf_Addr) dest32) >> 2) & 0x3fffffff)); - break; - - case R_SPARC_HI22: /* 9 */ - dest32 = (unsigned int *)(secp + rel->r_offset); - symval += rel->r_addend; - *dest32 = (*dest32 & 0xffc00000) | (symval >> 10); - break; - - case R_SPARC_LO10: /* 12 */ - dest32 = (unsigned int *)(secp + rel->r_offset); - symval += rel->r_addend; - *dest32 = (*dest32 & ~0x3ff) | (symval & 0x3ff); - break; - - case R_SPARC_COPY: /* 19 */ - /* Fix your code... I'd rather dish out an error here - * so people will not link together PIC and non-PIC - * code into a final driver object file. - */ - ErrorF("Elf_RelocateEntry():" - " Copy relocs not supported on Sparc.\n"); - break; - - case R_SPARC_JMP_SLOT: /* 21 */ - dest32 = (unsigned int *)(secp + rel->r_offset); - /* Before we change it the PLT entry looks like: - * - * pltent: sethi %hi(rela_plt_offset), %g1 - * b,a PLT0 - * nop - * - * We change it into: - * - * pltent: sethi %hi(rela_plt_offset), %g1 - * sethi %hi(symval), %g1 - * jmp %g1 + %lo(symval), %g0 - */ - symval += rel->r_addend; - dest32[2] = 0x81c06000 | (symval & 0x3ff); - __asm __volatile("flush %0 + 0x8"::"r"(dest32)); - - dest32[1] = 0x03000000 | (symval >> 10); - __asm __volatile("flush %0 + 0x4"::"r"(dest32)); - - break; - - case R_SPARC_RELATIVE: /* 22 */ - dest64 = (unsigned long *)(secp + rel->r_offset); - *dest64 = (unsigned long)secp + rel->r_addend; - break; -#endif /*__sparc__*/ -#ifdef __ia64__ - case R_IA64_NONE: - break; - - case R_IA64_LTOFF_FPTR22: - if (rel->r_addend) - FatalError("\nAddend for R_IA64_LTOFF_FPTR22 not supported\n"); -# ifdef ELFDEBUG - ELFDEBUG("opd=%016lx.%016lx\n", - ((long *)symval)[0], ((long *)symval)[1]); -# endif - /* FALLTHROUGH */ - case R_IA64_LTOFF22: -#ifndef IA64_LDX_OPTIMIZATION - case R_IA64_LTOFF22X: /* If not implementing LDXMOV optimization treat LTOFF22X as LTOFF22 */ -#endif - { - ELFGotEntryPtr gotent; - - dest128 = (unsigned long *)(secp + (rel->r_offset & ~3)); -# ifdef ELFDEBUG - ELFDEBUG("%s %s\t", ELF_R_TYPE(rel->r_info) == R_IA64_LTOFF22 ? - "R_IA64_LTOFF22" : "R_IA64_LTOFF_FPTR22", - ElfGetSymbolName(elffile, ELF_R_SYM(rel->r_info))); - ELFDEBUG("secp=%lx\t", secp); - ELFDEBUG("symval=%lx\t", symval); - ELFDEBUG("dest128=%lx\t", dest128); - ELFDEBUG("slot=%d\n", rel->r_offset & 3); - ELFDEBUG("*dest128=[%016lx%016lx]\n", dest128[1], dest128[0]); -# endif - - for (gotent = elffile->got_entries; gotent; gotent = gotent->next) { - if (ELF_R_SYM(gotent->rel->r_info) == ELF_R_SYM(rel->r_info) - && gotent->rel->r_addend == rel->r_addend) - break; - } - - /* Set the address in the GOT */ - if (gotent) { - *(unsigned long *)(elffile->got + gotent->offset) = - symval + rel->r_addend; -# ifdef ELFDEBUG - ELFDEBUG("Setting gotent[%x]=%lx\n", - gotent->offset, symval + rel->r_addend); -# endif - if ((gotent->offset & 0xffe00000) != 0) - FatalError("\nR_IA64_LTOFF22 offset %x too large\n", - gotent->offset); - IA64InstallReloc(dest128, rel->r_offset & 3, IA64_OPND_IMM22, - gotent->offset); - } else - FatalError("\nCould not find GOT entry\n"); - } - break; - - case R_IA64_PCREL21B: - { - ELFPltEntryPtr pltent; - - dest128 = (unsigned long *)(secp + (rel->r_offset & ~3)); -# ifdef ELFDEBUG - ELFDEBUG("R_IA64_PCREL21B %s\t", - ElfGetSymbolName(elffile, ELF_R_SYM(rel->r_info))); - ELFDEBUG("secp=%lx\t", secp); - ELFDEBUG("symval=%lx\t", symval); - ELFDEBUG("opd=%lx.%lx\t", ((long *)symval)[0], - ((long *)symval)[1]); - ELFDEBUG("dest128=%lx\t", dest128); - ELFDEBUG("slot=%d\n", rel->r_offset & 3); - ELFDEBUG("*dest128=[%016lx%016lx]\n", dest128[1], dest128[0]); -# endif - if (rel->r_addend) - FatalError("\nAddend for PCREL21B not supported\n"); - if (((long *)symval)[1] == (long)elffile->got - && (((unsigned long)dest128 - ((unsigned long *)symval)[0]) + - 0x2000000 < 0x4000000)) { - /* We can save the travel through PLT */ - IA64InstallReloc(dest128, rel->r_offset & 3, IA64_OPND_TGT25C, - ((unsigned long *)symval)[0] - - (unsigned long)dest128); - break; - } - for (pltent = elffile->plt_entries; pltent; pltent = pltent->next) { - if (ELF_R_SYM(pltent->rel->r_info) == ELF_R_SYM(rel->r_info) - && pltent->rel->r_addend == rel->r_addend) - break; - } - - /* Set the address in the PLT */ - if (pltent == NULL) - FatalError("\nCould not find PLT entry\n"); - else { - unsigned long *p = - (unsigned long *)(elffile->plt + pltent->offset); - unsigned long r = - (unsigned long)symval - (unsigned long)elffile->got; - - if (r + 0x200000 >= 0x400000) { - /* Too far from gp to use the official function descriptor, - * so we have to make a local one. - */ - r = pltent->gotoffset; - memcpy(elffile->got + r, (char *)symval, 16); - } - - /* [MMI] addl r15=NNN,r1;; ld8 r16=[r15],8; mov r14=r1;; */ - p[0] = 0x410024000200780bUL; - p[1] = 0x84000801c028303cUL; - /* [MIB] ld8 r1=[r15]; mov b6=r16; br.few b6;; */ - p[2] = 0x806010181e000811UL; - p[3] = 0x0080006000038004UL; - IA64InstallReloc(p, 0, IA64_OPND_IMM22, r); - IA64InstallReloc(dest128, rel->r_offset & 3, IA64_OPND_TGT25C, - (unsigned long)p - (unsigned long)dest128); - } - } - break; - - case R_IA64_FPTR64LSB: - dest64 = (unsigned long *)(secp + rel->r_offset); -# ifdef ELFDEBUG - ELFDEBUG("R_IA64_FPTR64LSB %s\t", - ElfGetSymbolName(elffile, ELF_R_SYM(rel->r_info))); - ELFDEBUG("secp=%lx\t", secp); - ELFDEBUG("symval=%lx\t", symval); - ELFDEBUG("dest64=%lx\t", dest64); - ELFDEBUG("opd=%016lx.%016lx\n", ((long *)symval)[0], - ((long *)symval)[1]); -# endif - - if (rel->r_addend) - FatalError("\nAddend not supported for R_IA64_FPTR64LSB\n"); - *dest64 = symval; - ia64_flush_cache(dest64); - break; - - case R_IA64_DIR64LSB: - dest64 = (unsigned long *)(secp + rel->r_offset); -# ifdef ELFDEBUG - ELFDEBUG("R_IA64_DIR64LSB %s\t", - ElfGetSymbolName(elffile, ELF_R_SYM(rel->r_info))); - ELFDEBUG("secp=%lx\t", secp); - ELFDEBUG("symval=%lx\t", symval); - ELFDEBUG("dest64=%lx\n", dest64); -# endif - *dest64 = symval + rel->r_addend; - ia64_flush_cache(dest64); - break; - - case R_IA64_PCREL64LSB: - dest64 = (unsigned long *)(secp + rel->r_offset); -#ifdef ELFDEBUG - ELFDEBUG("R_IA64_PCREL64LSB %s\t", - ElfGetSymbolName(elffile, ELF_R_SYM(rel->r_info))); - ELFDEBUG("secp=%lx\t", secp); - ELFDEBUG("symval=%lx\t", symval); - ELFDEBUG("dest64=%lx\n", dest64); -#endif - *dest64 = symval + rel->r_addend - (unsigned long)dest64; - break; - - case R_IA64_GPREL22: - dest128 = (unsigned long *)(secp + (rel->r_offset & ~3)); -# ifdef ELFDEBUG - ELFDEBUG("R_IA64_GPREL22 %s\t", - ElfGetSymbolName(elffile, ELF_R_SYM(rel->r_info))); - ELFDEBUG("secp=%lx\t", secp); - ELFDEBUG("symval=%lx\t", symval); - ELFDEBUG("dest128=%lx\t", dest128); - ELFDEBUG("slot=%d\n", rel->r_offset & 3); - ELFDEBUG("*dest128=[%016lx%016lx]\n", dest128[1], dest128[0]); -# endif - IA64InstallReloc(dest128, rel->r_offset & 3, IA64_OPND_IMM22, - symval + rel->r_addend - (long)elffile->got); - break; - -#ifdef IA64_LDX_OPTIMIZATION - case R_IA64_LTOFF22X: - { - ELFGotEntryPtr gotent; - long gp_offset = symval + rel->r_addend - (long)elffile->got; - - dest128 = (unsigned long *)(secp + (rel->r_offset & ~3)); - -# ifdef ELFDEBUG - ELFDEBUG("R_IA64_LTOFF22X %s\t", - ElfGetSymbolName(elffile, ELF_R_SYM(rel->r_info))); - ELFDEBUG("secp=%lx\t", secp); - ELFDEBUG("symval=%lx\t", symval); - ELFDEBUG("dest128=%lx\t", dest128); - ELFDEBUG("slot=%d\n", rel->r_offset & 3); -# endif - - if (gp_offset << 42 >> 42 != gp_offset) { - /* Offset is too large for LTOFF22X, - * fallback to using GOT lookup, e.g. LTOFF22. - * Note: LDXMOV will fail the same test and will be ignored. */ - -# ifdef ELFDEBUG - ELFDEBUG("gp_offset=%ld too large, using GOT instead (LTOFF22)\n", gp_offset); -# endif - - for (gotent = elffile->got_entries; gotent; - gotent = gotent->next) { - if (ELF_R_SYM(gotent->rel->r_info) == - ELF_R_SYM(rel->r_info) - && gotent->rel->r_addend == rel->r_addend) - break; - } - - /* Set the address in the GOT */ - if (gotent) { - *(unsigned long *)(elffile->got + gotent->offset) = - symval + rel->r_addend; -# ifdef ELFDEBUG - ELFDEBUG("Setting gotent[%x]=%lx\n", gotent->offset, - symval + rel->r_addend); -# endif - if ((gotent->offset & 0xffe00000) != 0) - FatalError("\nR_IA64_LTOFF22 offset %x too large\n", - gotent->offset); - } else { - FatalError("\nCould not find GOT entry\n"); - } - gp_offset = gotent->offset; /* Use GOT lookup */ - } else { -# ifdef ELFDEBUG - ELFDEBUG("using gp_offset=%ld (LTOFF22X)", gp_offset); -# endif - } - IA64InstallReloc(dest128, rel->r_offset & 3, IA64_OPND_IMM22, - gp_offset); - } - break; -#endif - - case R_IA64_LDXMOV: -# ifdef ELFDEBUG - ELFDEBUG("R_IA64_LDXMOV %s\t", - ElfGetSymbolName(elffile, ELF_R_SYM(rel->r_info))); -# endif - -#ifdef IA64_LDX_OPTIMIZATION - { - long gp_offset = symval + rel->r_addend - (long)elffile->got; - - dest128 = (unsigned long *)(secp + (rel->r_offset & ~3)); - - if (gp_offset << 42 >> 42 != gp_offset) { - /* Offset is too large for LTOFF22X, ignore this relocation */ -# ifdef ELFDEBUG - ELFDEBUG("offset = %ld too large, ignoring\n", gp_offset); -# endif - } else { - -# ifdef ELFDEBUG - ELFDEBUG("secp=%lx\t", secp); - ELFDEBUG("symval=%lx\t", symval); - ELFDEBUG("dest128=%lx\t", dest128); - ELFDEBUG("slot=%d\n", rel->r_offset & 3); - ELFDEBUG("offset=%ld\n", gp_offset); - ELFDEBUG("*dest128=[%016lx%016lx]\n", dest128[1], dest128[0]); -# endif - - IA64InstallReloc(dest128, rel->r_offset & 3, IA64_OPND_LDXMOV, - 0); - } - } -#endif - break; - -#endif /*__ia64__*/ - -#if defined(__arm__) - case R_ARM_ABS32: - dest32 = (unsigned int *)(secp + rel->r_offset); -# ifdef ELFDEBUG - ELFDEBUG("R_ARM_ABS32\t"); - ELFDEBUG("dest32=%x\t", dest32); - ELFDEBUG("*dest32=%8.8lx\t", *dest32); -# endif - *dest32 = symval + (*dest32); /* S + A */ -# ifdef ELFDEBUG - ELFDEBUG("*dest32=%8.8lx\n", *dest32); -# endif - break; - - case R_ARM_REL32: - dest32 = (unsigned int *)(secp + rel->r_offset); -# ifdef ELFDEBUG - { - char *namestr; - - ELFDEBUG("R_ARM_REL32 %s\t", - namestr = - ElfGetSymbolName(elffile, ELF_R_SYM(rel->r_info))); - xf86loaderfree(namestr); - ELFDEBUG("secp=%x\t", secp); - ELFDEBUG("symval=%lx\t", symval); - ELFDEBUG("dest32=%x\t", dest32); - ELFDEBUG("*dest32=%8.8lx\t", *dest32); - } -# endif - - *dest32 = symval + (*dest32) - (Elf_Addr) dest32; /* S + A - P */ - -# ifdef ELFDEBUG - ELFDEBUG("*dest32=%8.8lx\n", *dest32); -# endif - - break; - - case R_ARM_PC24: - { - unsigned long val; - - dest32 = (unsigned int *)(secp + rel->r_offset); - val = (*dest32 & 0x00ffffff) << 2; - val = symval - (unsigned long)dest32 + val; - val >>= 2; - *dest32 = (*dest32 & 0xff000000) | (val & 0x00ffffff); -#ifdef NOTYET - arm_flush_cache(dest32); -#endif - } - break; - -#endif /* (__arm__) */ - - default: - ErrorF("Elf_RelocateEntry() Unsupported relocation type %d\n", - (int)ELF_R_TYPE(rel->r_info)); - break; - } - return 0; -} - -static ELFRelocPtr -ELFCollectRelocations(elffile, index) - ELFModulePtr elffile; - int index; /* The section to use as relocation data */ -{ - int i, numrel; - Elf_Shdr *sect = &(elffile->sections[index]); - Elf_Rel_t *rel = (Elf_Rel_t *) elffile->saddr[index]; - ELFRelocPtr reloc_head = NULL; - ELFRelocPtr tmp; - - numrel = sect->sh_size / sect->sh_entsize; - - for (i = 0; i < numrel; i++) { -#if defined(__alpha__) - if (ELF_R_TYPE(rel[i].r_info) == R_ALPHA_LITERAL) { - ElfAddGOT(elffile, &rel[i]); - } -#endif -#if defined(__ia64__) - if (ELF_R_TYPE(rel[i].r_info) == R_IA64_LTOFF22 - || ELF_R_TYPE(rel[i].r_info) == R_IA64_LTOFF22X - || ELF_R_TYPE(rel[i].r_info) == R_IA64_LTOFF_FPTR22) { - ElfAddGOT(elffile, &rel[i]); - } - if (ELF_R_TYPE(rel[i].r_info) == R_IA64_PCREL21B) { - ElfAddPLT(elffile, &rel[i]); - } - if (ELF_R_TYPE(rel[i].r_info) == R_IA64_LTOFF_FPTR22 - || ELF_R_TYPE(rel[i].r_info) == R_IA64_FPTR64LSB) { - Elf_Sym *syms = (Elf_Sym *) elffile->saddr[elffile->symndx]; - - if (ELF_ST_BIND(syms[ELF_R_SYM(rel[i].r_info)].st_info) == - STB_LOCAL) { - ElfAddOPD(elffile, ELF_R_SYM(rel[i].r_info), NULL); - } - } -#endif - tmp = ElfDelayRelocation(elffile, sect->sh_info, &(rel[i])); - tmp->next = reloc_head; - reloc_head = tmp; - } - - return reloc_head; -} - -/* - * ELF_GetSymbols() - * - * add the symbols to the symbol table maintained by the loader. - */ - -static LOOKUP * -ELF_GetSymbols(ELFModulePtr elffile, unsigned short **psecttable) -{ - Elf_Sym *syms; - Elf_Shdr *sect; - int i, l, numsyms; - LOOKUP *lookup, *p; - ELFCommonPtr tmp; - unsigned short *secttable; - - syms = elffile->symtab; - sect = &(elffile->sections[elffile->symndx]); - numsyms = sect->sh_size / sect->sh_entsize; - - if ((lookup = xf86loadermalloc((numsyms + 1) * sizeof(LOOKUP))) == NULL) - return 0; - - if ((secttable = - xf86loadercalloc(sizeof(unsigned short), (numsyms + 1))) == NULL) { - xf86loaderfree(lookup); - return 0; - } - *psecttable = secttable; - - for (i = 0, l = 0; i < numsyms; i++) { -#ifdef ELFDEBUG - ELFDEBUG("value=%lx\tsize=%lx\tBIND=%x\tTYPE=%x\tndx=%x\t%s\n", - (unsigned long)syms[i].st_value, - (unsigned long)syms[i].st_size, - ELF_ST_BIND(syms[i].st_info), ELF_ST_TYPE(syms[i].st_info), - syms[i].st_shndx, ElfGetString(elffile, syms[i].st_name)); -#endif - - if (ELF_ST_BIND(syms[i].st_info) == STB_LOCAL) - /* Don't add static symbols to the symbol table */ - continue; - - switch (ELF_ST_TYPE(syms[i].st_info)) { - case STT_OBJECT: - case STT_FUNC: - case STT_SECTION: - case STT_NOTYPE: - switch (syms[i].st_shndx) { - case SHN_ABS: - ErrorF("ELF_GetSymbols() Don't know how to handle SHN_ABS\n"); - break; - case SHN_COMMON: -#ifdef ELFDEBUG - ELFDEBUG("Adding COMMON space for %s\n", - ElfGetString(elffile, syms[i].st_name)); -#endif - if (!LoaderHashFind(ElfGetString(elffile, syms[i].st_name))) { - tmp = ElfAddCOMMON(&(syms[i])); - if (tmp) { - tmp->next = listCOMMON; - listCOMMON = tmp; - } - } - break; - case SHN_UNDEF: - /* - * UNDEF will get resolved later, so the value - * doesn't really matter here. - */ - /* since we don't know the value don't advertise the symbol */ - break; - default: - lookup[l].symName = - xf86loaderstrdup(ElfGetString - (elffile, syms[i].st_name)); - lookup[l].offset = (funcptr) syms[i].st_value; - secttable[l] = syms[i].st_shndx; -#ifdef ELFDEBUG - ELFDEBUG("Adding symbol %lx(%d) %s\n", - (unsigned long)lookup[l].offset, secttable[l], - lookup[l].symName); -#endif -#ifdef __ia64__ - if (ELF_ST_TYPE(syms[i].st_info) == STT_FUNC) { - ElfAddOPD(elffile, -1, &lookup[l]); - } -#endif - l++; - break; - } - break; - case STT_FILE: - case STT_LOPROC: - case STT_HIPROC: - /* Skip this type */ -#ifdef ELFDEBUG - ELFDEBUG("Skipping TYPE %d %s\n", - ELF_ST_TYPE(syms[i].st_info), - ElfGetString(elffile, syms[i].st_name)); -#endif - break; - default: - ErrorF("ELF_GetSymbols(): Unepected symbol type %d\n", - ELF_ST_TYPE(syms[i].st_info)); - break; - } - } - - lookup[l].symName = NULL; /* Terminate the list */ - -/* - * Remove the ELF symbols that will show up in every object module. - */ - for (i = 0, p = lookup; p->symName; i++, p++) { - while (!strcmp(lookup[i].symName, ".text") - || !strcmp(lookup[i].symName, ".data") - || !strcmp(lookup[i].symName, ".bss") - || !strcmp(lookup[i].symName, ".comment") - || !strcmp(lookup[i].symName, ".note") - ) { - memmove(&(lookup[i]), &(lookup[i + 1]), (l - i) * sizeof(LOOKUP)); - memmove(&(secttable[i]), &(secttable[i + 1]), - (l-- - i) * sizeof(unsigned short)); - } - } - return lookup; -} - -#define SecOffset(index) elffile->sections[index].sh_offset -#define SecSize(index) elffile->sections[index].sh_size -#define SecAlign(index) elffile->sections[index].sh_addralign -#define SecType(index) elffile->sections[index].sh_type -#define SecFlags(index) elffile->sections[index].sh_flags -#define SecInfo(index) elffile->sections[index].sh_info - -#define AdjustSize(i) \ - if (!pass) { \ - if (SecAlign(i) > *maxalign) \ - *maxalign = SecAlign(i); \ - *totalsize += (SecAlign(i) - 1); \ - *totalsize &= ~(SecAlign(i) - 1); \ - *totalsize += SecSize(i); \ - continue; \ - } do { } while (0) - -/* - * ELFCollectSections - * - * Do the work required to load each section into memory. - */ -static void -ELFCollectSections(ELFModulePtr elffile, int pass, int *totalsize, - int *maxalign) -{ - int i; - int j; - -/* - * Find and identify all of the Sections - */ - j = elffile->lsectidx; - for (i = 1; i < elffile->numsh; i++) { - int flags = 0; - char *name = ElfGetSectionName(elffile, elffile->sections[i].sh_name); - -#if defined(__alpha__) || defined(__ia64__) - if (!strcmp(name, ".got") /*Isn't there a more generic way to do this? */ -# if defined(__ia64__) - || !strcmp(name, ".plt") || !strcmp(name, ".IA_64.unwind_info") -# endif - ) - continue; -#endif - switch (SecType(i)) { - case SHT_STRTAB: - if (!strcmp(name, ".shstrtab")) /* already loaded */ - continue; - if (!strcmp(name, ".stabstr")) /* ignore debug info */ - continue; - if (!strcmp(name, ".stab.indexstr")) /* ignore more debug info */ - continue; - case SHT_SYMTAB: - if (pass) - continue; - flags = LOADED_SECTION; - flags |= RELOC_SECTION; - break; - case SHT_REL: - case SHT_RELA: - if (pass) - continue; - if (!(SecFlags(SecInfo(i)) & SHF_ALLOC)) - continue; -#ifdef __ia64__ - if (SecType(SecInfo(i)) == SHT_IA_64_UNWIND) - continue; -#endif - flags = LOADED_SECTION; - flags |= RELOC_SECTION; - break; - case SHT_PROGBITS: - flags |= LOADED_SECTION; - case SHT_NOBITS: - if (!(elffile->sections[i].sh_flags & SHF_ALLOC)) - continue; - AdjustSize(i); - break; - default: -#ifdef ELFDEBUG - if (pass) - ELFDEBUG("ELF: Not loading %s\n", name); -#endif - continue; - } - - elffile->lsection = xf86loaderrealloc(elffile->lsection, - (j + 1) * sizeof(LoadSection)); - if (!(flags & RELOC_SECTION)) { - if (flags & LOADED_SECTION) { - elffile->lsection[j].saddr /* sect. contains data */ - = ELFLoaderSectToMem(elffile, SecAlign(i), - SecOffset(i), SecSize(i), name); - } else { - if (SecSize(i)) - elffile->lsection[j].saddr - = ELFLoaderSectCalloc(elffile, SecAlign(i), - SecSize(i)); - else - elffile->lsection[j].saddr = NULL; - } - } else { - elffile->lsection[j].saddr = - (Elf_Sym *) _LoaderFileToMem(elffile->fd, SecOffset(i), - SecSize(i), name); - } - elffile->saddr[i] = elffile->lsection[j].saddr; -#ifdef ELFDEBUG - ELFDEBUG("%s starts at %p size: %lx\n", - name, elffile->saddr[i], (unsigned long)SecSize(i)); -#endif - elffile->lsection[j].name = name; - elffile->lsection[j].ndx = i; - elffile->lsection[j].size = SecSize(i); - elffile->lsection[j].flags = flags; - switch (SecType(i)) { -#if defined(linux) || defined(__OpenBSD__) || defined(sun) - case SHT_PROGBITS: - { - unsigned long page_size = getpagesize(); - unsigned long round; - - round = (unsigned long)elffile->lsection[j].saddr & (page_size -1); - mprotect( (char *)elffile->lsection[j].saddr - round, - SecSize(i) + round, PROT_READ | PROT_WRITE | PROT_EXEC); - } -#ifdef __ia64__ - { - int k; - for (k = 0; k < SecSize(i); k += 32) - ia64_flush_cache(elffile->lsection[j].saddr+k); - ia64_flush_cache(elffile->lsection[j].saddr+SecSize(i)-1); - } -#endif - break; -#endif - case SHT_SYMTAB: - elffile->symtab = (Elf_Sym *) elffile->saddr[i]; - elffile->symndx = i; - break; - case SHT_STRTAB: - elffile->straddr = elffile->saddr[i]; - elffile->strsize = elffile->lsection[j].size; - elffile->strndx = i; - break; - default: - break; - } - elffile->lsectidx = ++j; - } -} - -/* - * Public API for the ELF implementation of the loader. - */ -void * -ELFLoadModule(loaderPtr modrec, int elffd, LOOKUP **ppLookup, int flags) -{ - ELFModulePtr elffile; - Elf_Ehdr *header; - ELFRelocPtr elf_reloc, tail; - void *v; - LDRModulePtr elfmod; - int totalsize, maxalign, i; - unsigned short *secttable; - LOOKUP *pLookup; - - ldrCommons = 0; - nCommons = 0; - -#ifdef ELFDEBUG - ELFDEBUG("Loading %s %s\n", modrec->name, modrec->cname); -#endif - if ((elffile = xf86loadercalloc(1, sizeof(ELFModuleRec))) == NULL) { - ErrorF("Unable to allocate ELFModuleRec\n"); - return NULL; - } - - elffile->handle = modrec->handle; - elffile->module = modrec->module; - elffile->fd = elffd; - v = elffile->funcs = modrec->funcs; - -/* - * Get the ELF header - */ - elffile->header = - (Elf_Ehdr *) _LoaderFileToMem(elffd, 0, sizeof(Elf_Ehdr), - "header"); - header = (Elf_Ehdr *) elffile->header; - -/* - * Get the section table - */ - elffile->numsh = header->e_shnum; - elffile->secsize = (header->e_shentsize * header->e_shnum); - elffile->sections = - (Elf_Shdr *) _LoaderFileToMem(elffd, header->e_shoff, - elffile->secsize, "sections"); -#if defined(__alpha__) || defined(__ia64__) - /* - * Need to allocate space for the .got section which will be - * fabricated later - */ - elffile->gotndx = header->e_shnum; - header->e_shnum++; -# if defined(__ia64__) - elffile->pltndx = header->e_shnum; - header->e_shnum++; -# endif - elffile->numsh = header->e_shnum; - elffile->secsize = (header->e_shentsize * header->e_shnum); - elffile->sections = - xf86loaderrealloc(elffile->sections, elffile->secsize); -#endif /*defined(__alpha__) || defined(__ia64__) */ - elffile->saddr = - xf86loadercalloc(elffile->numsh, sizeof(unsigned char *)); - -#if defined(__alpha__) || defined(__ia64__) - /* - * Manually fill in the entry for the .got section so ELFCollectSections() - * will be able to find it. - */ - elffile->sections[elffile->gotndx].sh_name = - SecSize(header->e_shstrndx) + 1; - elffile->sections[elffile->gotndx].sh_type = SHT_PROGBITS; - elffile->sections[elffile->gotndx].sh_flags = SHF_WRITE | SHF_ALLOC; - elffile->sections[elffile->gotndx].sh_size = 0; - elffile->sections[elffile->gotndx].sh_addralign = 8; - /* Add room to copy ".got", and maintain alignment */ - SecSize(header->e_shstrndx) += 8; -#endif -#if defined(__ia64__) - /* - * Manually fill in the entry for the .plt section so ELFCollectSections() - * will be able to find it. - */ - elffile->sections[elffile->pltndx].sh_name = - SecSize(header->e_shstrndx) + 1; - elffile->sections[elffile->pltndx].sh_type = SHT_PROGBITS; - elffile->sections[elffile->pltndx].sh_flags = SHF_EXECINSTR | SHF_ALLOC; - elffile->sections[elffile->pltndx].sh_size = 0; - elffile->sections[elffile->pltndx].sh_addralign = 32; - /* Add room to copy ".plt", and maintain alignment */ - SecSize(header->e_shstrndx) += 32; -#endif - -/* - * Get the section header string table - */ - elffile->shstrsize = SecSize(header->e_shstrndx); - elffile->shstraddr = - _LoaderFileToMem(elffd, SecOffset(header->e_shstrndx), - SecSize(header->e_shstrndx), ".shstrtab"); - elffile->shstrndx = header->e_shstrndx; -#if defined(__alpha__) || defined(__ia64__) - /* - * Add the string for the .got section - */ - strcpy((char *)(elffile->shstraddr + - elffile->sections[elffile->gotndx].sh_name), ".got"); -#endif -#if defined(__ia64__) - /* - * Add the string for the .plt section - */ - strcpy((char *)(elffile->shstraddr + - elffile->sections[elffile->pltndx].sh_name), ".plt"); -#endif - -/* - * Load some desired sections, compute size of the remaining ones - */ - totalsize = 0; - maxalign = 0; - ELFCollectSections(elffile, 0, &totalsize, &maxalign); - if (elffile->straddr == NULL || elffile->strsize == 0) { -#if 0 - ErrorF("No symbols found in this module\n"); -#endif - ELFUnloadModule(elffile); - return (void *)-1L; - } -/* - * add symbols - */ - *ppLookup = pLookup = ELF_GetSymbols(elffile, §table); - -/* - * Do relocations - */ - for (i = 0; i < elffile->lsectidx; i++) { - switch (SecType(elffile->lsection[i].ndx)) { - case SHT_REL: - case SHT_RELA: - break; - default: - continue; - } - elf_reloc = ELFCollectRelocations(elffile, elffile->lsection[i].ndx); - if (elf_reloc) { - for (tail = elf_reloc; tail->next; tail = tail->next) ; - tail->next = _LoaderGetRelocations(v)->elf_reloc; - _LoaderGetRelocations(v)->elf_reloc = elf_reloc; - } - } - -#if defined(__ia64__) - totalsize += (elffile->sections[elffile->pltndx].sh_addralign - 1); - totalsize &= ~(elffile->sections[elffile->pltndx].sh_addralign - 1); - totalsize += elffile->pltsize; - if (maxalign < elffile->sections[elffile->pltndx].sh_addralign) - maxalign = elffile->sections[elffile->pltndx].sh_addralign; -#endif - - /* Space for COMMON */ - totalsize = (totalsize + 7) & ~7; - totalsize += ElfCOMMONSize(); - -#ifdef MergeSectionAlloc - elffile->basesize = totalsize + maxalign; - -# if !defined(DoMMAPedMerge) - elffile->base = xf86loadermalloc(elffile->basesize); - if (elffile->base == NULL) { - ErrorF("Unable to allocate ELF sections\n"); - return NULL; - } -# if defined(linux) || defined(__OpenBSD__) || defined(sun) - { - unsigned long page_size = getpagesize(); - unsigned long round; - - round = (unsigned long)elffile->base & (page_size - 1); - mprotect(elffile->base - round, - (elffile->basesize + round + page_size - 1) & ~(page_size - - 1), - PROT_READ | PROT_WRITE | PROT_EXEC); - } -# endif -# else - MMAP_ALIGN(elffile->basesize); - elffile->base = mmap(0, elffile->basesize, MMAP_PROT, MMAP_FLAGS, -1, - (off_t) 0); - if (elffile->base == NULL) { - ErrorF("Unable to mmap ELF sections\n"); - return NULL; - } -# endif - elffile->baseptr = - ((long)elffile->base + (maxalign - 1)) & ~(maxalign - 1); -#endif - -#if defined(__alpha__) || defined(__ia64__) - if (!ELFCreateGOT(elffile, maxalign)) - return NULL; -#endif -#if defined(__ia64__) - ELFCreatePLT(elffile); -#endif - - ELFCollectSections(elffile, 1, NULL, NULL); - - for (i = 0; pLookup[i].symName; i++) - if (secttable[i]) { - pLookup[i].offset = - (funcptr) ((long)pLookup[i].offset + - (long)elffile->saddr[secttable[i]]); -#ifdef ELFDEBUG - ELFDEBUG("Finalizing symbol %p %s\n", - (void *)pLookup[i].offset, pLookup[i].symName); -#endif - } - xf86loaderfree(secttable); - -#if defined(__ia64__) - ELFCreateOPD(elffile); -#endif - - if (!ElfCreateCOMMON(elffile, *ppLookup)) - return NULL; - - /* Record info for gdb - if we can't allocate the loader record fail - * silently (the user will find out soon enough that there's no VM left */ - if ((elfmod = xf86loadercalloc(1, sizeof(LDRModuleRec))) != NULL) { - elfmod->name = strdup(modrec->name); - elfmod->namelen = strlen(modrec->name); - elfmod->version = 1; - for (i = 0; i < elffile->lsectidx; i++) { - char *name = elffile->lsection[i].name; - - if (!strcmp(name, ".text")) - elfmod->text = elffile->lsection[i].saddr; - else if (!strcmp(name, ".data")) - elfmod->data = elffile->lsection[i].saddr; - else if (!strcmp(name, ".rodata")) - elfmod->rodata = elffile->lsection[i].saddr; - else if (!strcmp(name, ".bss")) - elfmod->bss = elffile->lsection[i].saddr; - } - elfmod->next = ModList; - elfmod->commons = ldrCommons; - elfmod->commonslen = nCommons; - - ModList = elfmod; - - /* Tell GDB something interesting happened */ - _loader_debug_state(); - } - return (void *)elffile; -} - -void -ELFResolveSymbols(void *mod) -{ - ELFRelocPtr 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)->elf_reloc; p;) { -#ifdef ELFDEBUG - ELFDEBUG("ResolveSymbols: " - "file %p, sec %d, r_offset 0x%x, r_info 0x%p\n", - (void *)p->file, p->secn, p->rel->r_offset, - (void *)p->rel->r_info); -#endif - tmp = Elf_RelocateEntry(p->file, p->secn, p->rel, FALSE); - if (tmp) { - /* Failed to relocate. Keep it in the list. */ - tmp->next = newlist; - newlist = tmp; - } - tmp = p; - p = p->next; - xf86loaderfree(tmp); - } - _LoaderGetRelocations(mod)->elf_reloc = newlist; -} - -int -ELFCheckForUnresolved(void *mod) -{ - ELFRelocPtr erel; - char *name; - int flag, fatalsym = 0; - - if ((erel = _LoaderGetRelocations(mod)->elf_reloc) == NULL) - return 0; - - while (erel) { - Elf_RelocateEntry(erel->file, erel->secn, erel->rel, TRUE); - name = ElfGetSymbolName(erel->file, ELF_R_SYM(erel->rel->r_info)); - flag = _LoaderHandleUnresolved(name, - _LoaderHandleToName(erel->file-> - handle)); - if (flag) - fatalsym = 1; - erel = erel->next; - } - return fatalsym; -} - -void -ELFUnloadModule(void *modptr) -{ - ELFModulePtr elffile = (ELFModulePtr) modptr; - ELFRelocPtr relptr, reltptr, *brelptr; - int i; - -/* - * Delete any unresolved relocations - */ - - relptr = _LoaderGetRelocations(elffile->funcs)->elf_reloc; - brelptr = &(_LoaderGetRelocations(elffile->funcs)->elf_reloc); - - while (relptr) { - if (relptr->file == elffile) { - *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 *)elffile, ELFhashCleanOut); - -/* - * Free the sections that were allocated. - */ -#if !defined (DoMMAPedMerge) -# define CheckandFree(ptr,size) if(ptr) xf86loaderfree(ptr) -#else -# define CheckandFree(ptr,size) if (ptr) munmap(ptr,size) -#endif -#define CheckandFreeFile(ptr,size) if(ptr) _LoaderFreeFileMem((ptr),(size)) - -#ifdef MergeSectionAlloc - CheckandFree(elffile->base, elffile->basesize); -# if defined(__alpha__) || defined(__ia64__) - if (elffile->shared_got) { - elffile->shared_got->nuses--; - if (!elffile->shared_got->nuses) { - ELFGotPtr *pgot = &ELFSharedGOTs; - - while (*pgot && *pgot != elffile->shared_got) - pgot = &(*pgot)->next; - if (*pgot) - *pgot = elffile->shared_got->next; - xf86loaderfree(elffile->shared_got); - } - } -# endif -#else /*MergeSectionAlloc */ - CheckandFree(elffile->common, elffile->comsize); -# if defined(__alpha__) || defined(__ia64__) - CheckandFree(elffile->got, elffile->gotsize); -# endif -# if defined(__ia64__) - CheckandFree(elffile->plt, elffile->pltsize); -# endif -#endif -#if defined(__alpha__) || defined(__ia64__) - { - ELFGotEntryPtr gotent; - - while ((gotent = elffile->got_entries)) { - elffile->got_entries = gotent->next; - xf86loaderfree(gotent); - } - } -#endif -#if defined(__ia64__) - { - ELFPltEntryPtr pltent; - - while ((pltent = elffile->plt_entries)) { - elffile->plt_entries = pltent->next; - xf86loaderfree(pltent); - } - } - { - ELFOpdPtr opdent; - - while ((opdent = elffile->opd_entries)) { - elffile->opd_entries = opdent->next; - xf86loaderfree(opdent); - } - } -#endif - - for (i = 0; i < elffile->lsectidx; i++) { -#ifdef MergeSectionAlloc - if (!(elffile->lsection[i].flags & RELOC_SECTION)) - continue; -#endif - if (elffile->lsection[i].flags & LOADED_SECTION) { - CheckandFreeFile(elffile->lsection[i].saddr, - elffile->lsection[i].size); - } else { - CheckandFree(elffile->lsection[i].saddr, - elffile->lsection[i].size); - } - } - xf86loaderfree(elffile->lsection); - -/* - * Free the section table, section pointer array, and section names - */ - _LoaderFreeFileMem(elffile->sections, elffile->secsize); - xf86loaderfree(elffile->saddr); - _LoaderFreeFileMem(elffile->header, sizeof(Elf_Ehdr)); - _LoaderFreeFileMem(elffile->shstraddr, elffile->shstrsize); - -/* - * Free the ELFModuleRec - */ - xf86loaderfree(elffile); - - return; -} - -char * -ELFAddressToSection(void *modptr, unsigned long address) -{ - ELFModulePtr elffile = (ELFModulePtr) modptr; - int i; - - for (i = 1; i < elffile->numsh; i++) { - if (address >= (unsigned long)elffile->saddr[i] && - address <= (unsigned long)elffile->saddr[i] + SecSize(i)) { - return ElfGetSectionName(elffile, elffile->sections[i].sh_name); - } - } - return NULL; -} |