From 52f5a164e64fe5c443445cfc59345920506b4f2a Mon Sep 17 00:00:00 2001 From: matthewc Date: Sun, 9 Jun 2002 13:37:44 +0000 Subject: [PATCH 1/1] [project @ 2002-06-09 13:37:41 by matthewc] Initial GHCI support on IA64. --- ghc/compiler/ghci/ByteCodeItbls.lhs | 11 +- ghc/rts/Linker.c | 639 ++++++++++++++++++++++++++++------- ghc/rts/LinkerInternals.h | 10 +- 3 files changed, 530 insertions(+), 130 deletions(-) diff --git a/ghc/compiler/ghci/ByteCodeItbls.lhs b/ghc/compiler/ghci/ByteCodeItbls.lhs index 519e50c..605ddae 100644 --- a/ghc/compiler/ghci/ByteCodeItbls.lhs +++ b/ghc/compiler/ghci/ByteCodeItbls.lhs @@ -147,9 +147,8 @@ mkJumpToAddr a 0x8610E000 .|. (lo10 w32), 0x81C0C000, 0x01000000 ] -#endif -#if i386_TARGET_ARCH +#elif i386_TARGET_ARCH -- Let the address to jump to be 0xWWXXYYZZ. -- Generate movl $0xWWXXYYZZ,%eax ; jmp *%eax -- which is @@ -165,9 +164,8 @@ mkJumpToAddr a 0xFF, 0xE0] in insnBytes -#endif -#if alpha_TARGET_ARCH +#elif alpha_TARGET_ARCH type ItblCode = Word32 mkJumpToAddr a = [ 0xc3800000 -- br at, .+4 @@ -177,6 +175,11 @@ mkJumpToAddr a , fromIntegral (w64 .&. 0x0000FFFF) , fromIntegral ((w64 `shiftR` 32) .&. 0x0000FFFF) ] where w64 = fromIntegral (ptrToInt a) :: Word64 + +#else +type ItblCode = Word32 +mkJumpToAddr a + = undefined #endif diff --git a/ghc/rts/Linker.c b/ghc/rts/Linker.c index e287d98..1c6575c 100644 --- a/ghc/rts/Linker.c +++ b/ghc/rts/Linker.c @@ -1,5 +1,5 @@ /* ----------------------------------------------------------------------------- - * $Id: Linker.c,v 1.90 2002/06/04 19:21:28 sof Exp $ + * $Id: Linker.c,v 1.91 2002/06/09 13:37:41 matthewc Exp $ * * (c) The GHC Team, 2000, 2001 * @@ -48,6 +48,12 @@ #include #endif +#if defined(ia64_TARGET_ARCH) +#define USE_MMAP +#include +#include +#endif + #if defined(linux_TARGET_OS) || defined(solaris2_TARGET_OS) || defined(freebsd_TARGET_OS) # define OBJFORMAT_ELF #elif defined(cygwin32_TARGET_OS) || defined (mingw32_TARGET_OS) @@ -275,10 +281,24 @@ typedef struct _RtsSymbolVal { Sym(init_stack) \ SymX(__stg_chk_0) \ SymX(__stg_chk_1) \ + SymX(stg_chk_2) \ + SymX(stg_chk_3) \ + SymX(stg_chk_4) \ + SymX(stg_chk_5) \ + SymX(stg_chk_6) \ + SymX(stg_chk_7) \ + SymX(stg_chk_8) \ Sym(stg_enterStackTop) \ SymX(stg_gc_d1) \ SymX(stg_gc_l1) \ SymX(__stg_gc_enter_1) \ + SymX(stg_gc_enter_2) \ + SymX(stg_gc_enter_3) \ + SymX(stg_gc_enter_4) \ + SymX(stg_gc_enter_5) \ + SymX(stg_gc_enter_6) \ + SymX(stg_gc_enter_7) \ + SymX(stg_gc_enter_8) \ SymX(stg_gc_f1) \ SymX(stg_gc_noregs) \ SymX(stg_gc_seq_1) \ @@ -459,19 +479,28 @@ typedef struct _RtsSymbolVal { SymX(xorIntegerzh_fast) \ SymX(yieldzh_fast) -#ifndef SUPPORT_LONG_LONGS -#define RTS_LONG_LONG_SYMS /* nothing */ -#else +#ifdef SUPPORT_LONG_LONGS #define RTS_LONG_LONG_SYMS \ SymX(int64ToIntegerzh_fast) \ SymX(word64ToIntegerzh_fast) -#endif /* SUPPORT_LONG_LONGS */ +#else +#define RTS_LONG_LONG_SYMS /* nothing */ +#endif + +#ifdef ia64_TARGET_ARCH +/* force these symbols to be present */ +#define RTS_EXTRA_SYMBOLS \ + Sym(__divsf3) +#else +#define RTS_EXTRA_SYMBOLS /* nothing */ +#endif /* entirely bogus claims about types of these symbols */ #define Sym(vvv) extern void (vvv); #define SymX(vvv) /**/ RTS_SYMBOLS RTS_LONG_LONG_SYMS +RTS_EXTRA_SYMBOLS RTS_POSIX_ONLY_SYMBOLS RTS_MINGW_ONLY_SYMBOLS RTS_CYGWIN_ONLY_SYMBOLS @@ -491,6 +520,7 @@ RTS_CYGWIN_ONLY_SYMBOLS static RtsSymbolVal rtsSyms[] = { RTS_SYMBOLS RTS_LONG_LONG_SYMS + RTS_EXTRA_SYMBOLS RTS_POSIX_ONLY_SYMBOLS RTS_MINGW_ONLY_SYMBOLS RTS_CYGWIN_ONLY_SYMBOLS @@ -743,6 +773,9 @@ void ghci_enquire ( char* addr ) } #endif +#ifdef ia64_TARGET_ARCH +static unsigned int PLTSize(void); +#endif /* ----------------------------------------------------------------------------- * Load an obj (populate the global symbol table, but don't resolve yet) @@ -755,7 +788,12 @@ loadObj( char *path ) ObjectCode* oc; struct stat st; int r, n; +#ifdef USE_MMAP + int fd, pagesize; + void *map_addr; +#else FILE *f; +#endif /* fprintf(stderr, "loadObj %s\n", path ); */ @@ -799,7 +837,6 @@ loadObj( char *path ) strcpy(oc->fileName, path); oc->fileSize = st.st_size; - oc->image = stgMallocBytes( st.st_size, "loadObj(image)" ); oc->symbols = NULL; oc->sections = NULL; oc->lochash = allocStrHashTable(); @@ -809,16 +846,55 @@ loadObj( char *path ) oc->next = objects; objects = oc; + fd = open(path, O_RDONLY); + if (fd == -1) + barf("loadObj: can't open `%s'", path); + +#ifdef USE_MMAP +#define ROUND_UP(x,size) ((x + size - 1) & ~(size - 1)) + + /* On many architectures malloc'd memory isn't executable, so we need to use mmap. */ + + fd = open(path, O_RDONLY); + if (fd == -1) + barf("loadObj: can't open `%s'", path); + + pagesize = getpagesize(); + +#ifdef ia64_TARGET_ARCH + /* The PLT needs to be right before the object */ + n = ROUND_UP(PLTSize(), pagesize); + oc->plt = mmap(NULL, n, PROT_EXEC|PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); + if (oc->plt == MAP_FAILED) + barf("loadObj: can't allocate PLT"); + + oc->pltIndex = 0; + map_addr = oc->plt + n; +#endif + + n = ROUND_UP(oc->fileSize, pagesize); + oc->image = mmap(map_addr, n, PROT_EXEC|PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0); + if (oc->image == MAP_FAILED) + barf("loadObj: can't map `%s'", path); + + close(fd); + +#else /* !USE_MMAP */ + + oc->image = stgMallocBytes(oc->fileSize, "loadObj(image)"); + /* load the image into memory */ f = fopen(path, "rb"); - if (!f) { + if (!f) barf("loadObj: can't read `%s'", path); - } + n = fread ( oc->image, 1, oc->fileSize, f ); - if (n != oc->fileSize) { - fclose(f); + if (n != oc->fileSize) barf("loadObj: error whilst reading `%s'", path); - } + + fclose(f); + +#endif /* USE_MMAP */ /* verify the in-memory image */ # if defined(OBJFORMAT_ELF) @@ -1784,23 +1860,186 @@ ocResolve_PEi386 ( ObjectCode* oc ) # define ELF_TARGET_SPARC /* Used inside */ #elif defined(i386_TARGET_ARCH) # define ELF_TARGET_386 /* Used inside */ +#elif defined (ia64_TARGET_ARCH) +# define ELF_TARGET_IA64 /* Used inside */ +# define ELF_64BIT +# define ELF_FUNCTION_DESC /* calling convention uses function descriptors */ +# define ELF_NEED_GOT /* needs Global Offset Table */ +# define ELF_NEED_PLT /* needs Procedure Linkage Tables */ #endif -/* There is a similar case for IA64 in the Solaris2 headers if this - * ever becomes relevant. - */ #include -#include + +/* + * Define a set of types which can be used for both ELF32 and ELF64 + */ + +#ifdef ELF_64BIT +#define ELFCLASS ELFCLASS64 +#define Elf_Addr Elf64_Addr +#define Elf_Word Elf64_Word +#define Elf_Sword Elf64_Sword +#define Elf_Ehdr Elf64_Ehdr +#define Elf_Phdr Elf64_Phdr +#define Elf_Shdr Elf64_Shdr +#define Elf_Sym Elf64_Sym +#define Elf_Rel Elf64_Rel +#define Elf_Rela Elf64_Rela +#define ELF_ST_TYPE ELF64_ST_TYPE +#define ELF_ST_BIND ELF64_ST_BIND +#define ELF_R_TYPE ELF64_R_TYPE +#define ELF_R_SYM ELF64_R_SYM +#else +#define ELFCLASS ELFCLASS32 +#define Elf_Addr Elf32_Addr +#define Elf_Word Elf32_Word +#define Elf_Sword Elf32_Sword +#define Elf_Ehdr Elf32_Ehdr +#define Elf_Phdr Elf32_Phdr +#define Elf_Shdr Elf32_Shdr +#define Elf_Sym Elf32_Sym +#define Elf_Rel Elf32_Rel +#define Elf_Rela Elf32_Rela +#define ELF_ST_TYPE ELF32_ST_TYPE +#define ELF_ST_BIND ELF32_ST_BIND +#define ELF_R_TYPE ELF32_R_TYPE +#define ELF_R_SYM ELF32_R_SYM +#endif + + +/* + * Functions to allocate entries in dynamic sections. Currently we simply + * preallocate a large number, and we don't check if a entry for the given + * target already exists (a linear search is too slow). Ideally these + * entries would be associated with symbols. + */ + +/* These sizes sufficient to load HSbase + HShaskell98 + a few modules */ +#define GOT_SIZE 0x20000 +#define FUNCTION_TABLE_SIZE 0x10000 +#define PLT_SIZE 0x08000 + +#ifdef ELF_NEED_GOT +static Elf_Addr got[GOT_SIZE]; +static unsigned int gotIndex; +static Elf_Addr gp_val = (Elf_Addr)got; + +static Elf_Addr +allocateGOTEntry(Elf_Addr target) +{ + Elf_Addr *entry; + + if (gotIndex >= GOT_SIZE) + barf("Global offset table overflow"); + + entry = &got[gotIndex++]; + *entry = target; + return (Elf_Addr)entry; +} +#endif + +#ifdef ELF_FUNCTION_DESC +typedef struct { + Elf_Addr ip; + Elf_Addr gp; +} FunctionDesc; + +static FunctionDesc functionTable[FUNCTION_TABLE_SIZE]; +static unsigned int functionTableIndex; + +static Elf_Addr +allocateFunctionDesc(Elf_Addr target) +{ + FunctionDesc *entry; + + if (functionTableIndex >= FUNCTION_TABLE_SIZE) + barf("Function table overflow"); + + entry = &functionTable[functionTableIndex++]; + entry->ip = target; + entry->gp = (Elf_Addr)gp_val; + return (Elf_Addr)entry; +} + +static Elf_Addr +copyFunctionDesc(Elf_Addr target) +{ + FunctionDesc *olddesc = (FunctionDesc *)target; + FunctionDesc *newdesc; + + newdesc = (FunctionDesc *)allocateFunctionDesc(olddesc->ip); + newdesc->gp = olddesc->gp; + return (Elf_Addr)newdesc; +} +#endif + +#ifdef ELF_NEED_PLT +#ifdef ia64_TARGET_ARCH +static void ia64_reloc_gprel22(Elf_Addr target, Elf_Addr value); +static void ia64_reloc_pcrel21(Elf_Addr target, Elf_Addr value, ObjectCode *oc); + +static unsigned char plt_code[] = +{ + /* taken from binutils bfd/elfxx-ia64.c */ + 0x0b, 0x78, 0x00, 0x02, 0x00, 0x24, /* [MMI] addl r15=0,r1;; */ + 0x00, 0x41, 0x3c, 0x30, 0x28, 0xc0, /* ld8 r16=[r15],8 */ + 0x01, 0x08, 0x00, 0x84, /* mov r14=r1;; */ + 0x11, 0x08, 0x00, 0x1e, 0x18, 0x10, /* [MIB] ld8 r1=[r15] */ + 0x60, 0x80, 0x04, 0x80, 0x03, 0x00, /* mov b6=r16 */ + 0x60, 0x00, 0x80, 0x00 /* br.few b6;; */ +}; + +/* If we can't get to the function descriptor via gp, take a local copy of it */ +#define PLT_RELOC(code, target) { \ + Elf64_Sxword rel_value = target - gp_val; \ + if ((rel_value > 0x1fffff) || (rel_value < -0x1fffff)) \ + ia64_reloc_gprel22((Elf_Addr)code, copyFunctionDesc(target)); \ + else \ + ia64_reloc_gprel22((Elf_Addr)code, target); \ + } +#endif + +typedef struct { + unsigned char code[sizeof(plt_code)]; +} PLTEntry; + +static Elf_Addr +allocatePLTEntry(Elf_Addr target, ObjectCode *oc) +{ + PLTEntry *plt = (PLTEntry *)oc->plt; + PLTEntry *entry; + + if (oc->pltIndex >= PLT_SIZE) + barf("Procedure table overflow"); + + entry = &plt[oc->pltIndex++]; + memcpy(entry->code, plt_code, sizeof(entry->code)); + PLT_RELOC(entry->code, target); + return (Elf_Addr)entry; +} + +static unsigned int +PLTSize(void) +{ + return (PLT_SIZE * sizeof(PLTEntry)); +} +#endif + + +/* + * Generic ELF functions + */ static char * -findElfSection ( void* objImage, Elf32_Word sh_type ) +findElfSection ( void* objImage, Elf_Word sh_type ) { - int i; char* ehdrC = (char*)objImage; - Elf32_Ehdr* ehdr = (Elf32_Ehdr*)ehdrC; - Elf32_Shdr* shdr = (Elf32_Shdr*)(ehdrC + ehdr->e_shoff); + Elf_Ehdr* ehdr = (Elf_Ehdr*)ehdrC; + Elf_Shdr* shdr = (Elf_Shdr*)(ehdrC + ehdr->e_shoff); char* sh_strtab = ehdrC + shdr[ehdr->e_shstrndx].sh_offset; char* ptr = NULL; + int i; + for (i = 0; i < ehdr->e_shnum; i++) { if (shdr[i].sh_type == sh_type /* Ignore the section header's string table. */ @@ -1816,35 +2055,48 @@ findElfSection ( void* objImage, Elf32_Word sh_type ) return ptr; } +static Elf_Addr +findElfSegment ( void* objImage, Elf_Addr vaddr ) +{ + char* ehdrC = (char*)objImage; + Elf_Ehdr* ehdr = (Elf_Ehdr*)ehdrC; + Elf_Phdr* phdr = (Elf_Phdr*)(ehdrC + ehdr->e_phoff); + Elf_Addr segaddr = 0; + int i; + + for (i = 0; i < ehdr->e_phnum; i++) { + segaddr = phdr[i].p_vaddr; + if ((vaddr >= segaddr) && (vaddr < segaddr + phdr[i].p_memsz)) + break; + } + return segaddr; +} static int ocVerifyImage_ELF ( ObjectCode* oc ) { - Elf32_Shdr* shdr; - Elf32_Sym* stab; + Elf_Shdr* shdr; + Elf_Sym* stab; int i, j, nent, nstrtab, nsymtabs; char* sh_strtab; char* strtab; - char* ehdrC = (char*)(oc->image); - Elf32_Ehdr* ehdr = ( Elf32_Ehdr*)ehdrC; + char* ehdrC = (char*)(oc->image); + Elf_Ehdr* ehdr = (Elf_Ehdr*)ehdrC; if (ehdr->e_ident[EI_MAG0] != ELFMAG0 || ehdr->e_ident[EI_MAG1] != ELFMAG1 || ehdr->e_ident[EI_MAG2] != ELFMAG2 || ehdr->e_ident[EI_MAG3] != ELFMAG3) { - belch("%s: not an ELF header", oc->fileName); + belch("%s: not an ELF object", oc->fileName); return 0; } - IF_DEBUG(linker,belch( "Is an ELF header" )); - if (ehdr->e_ident[EI_CLASS] != ELFCLASS32) { - belch("%s: not 32 bit ELF", oc->fileName); + if (ehdr->e_ident[EI_CLASS] != ELFCLASS) { + belch("%s: unsupported ELF format", oc->fileName); return 0; } - IF_DEBUG(linker,belch( "Is 32 bit ELF" )); - if (ehdr->e_ident[EI_DATA] == ELFDATA2LSB) { IF_DEBUG(linker,belch( "Is little-endian" )); } else @@ -1865,6 +2117,7 @@ ocVerifyImage_ELF ( ObjectCode* oc ) switch (ehdr->e_machine) { case EM_386: IF_DEBUG(linker,belch( "x86" )); break; case EM_SPARC: IF_DEBUG(linker,belch( "sparc" )); break; + case EM_IA_64: IF_DEBUG(linker,belch( "ia64" )); break; default: IF_DEBUG(linker,belch( "unknown" )); belch("%s: unknown architecture", oc->fileName); return 0; @@ -1874,9 +2127,9 @@ ocVerifyImage_ELF ( ObjectCode* oc ) "\nSection header table: start %d, n_entries %d, ent_size %d", ehdr->e_shoff, ehdr->e_shnum, ehdr->e_shentsize )); - ASSERT (ehdr->e_shentsize == sizeof(Elf32_Shdr)); + ASSERT (ehdr->e_shentsize == sizeof(Elf_Shdr)); - shdr = (Elf32_Shdr*) (ehdrC + ehdr->e_shoff); + shdr = (Elf_Shdr*) (ehdrC + ehdr->e_shoff); if (ehdr->e_shstrndx == SHN_UNDEF) { belch("%s: no section header string table", oc->fileName); @@ -1935,13 +2188,13 @@ ocVerifyImage_ELF ( ObjectCode* oc ) if (shdr[i].sh_type != SHT_SYMTAB) continue; IF_DEBUG(linker,belch( "section %d is a symbol table", i )); nsymtabs++; - stab = (Elf32_Sym*) (ehdrC + shdr[i].sh_offset); - nent = shdr[i].sh_size / sizeof(Elf32_Sym); + stab = (Elf_Sym*) (ehdrC + shdr[i].sh_offset); + nent = shdr[i].sh_size / sizeof(Elf_Sym); IF_DEBUG(linker,belch( " number of entries is apparently %d (%d rem)", nent, - shdr[i].sh_size % sizeof(Elf32_Sym) + shdr[i].sh_size % sizeof(Elf_Sym) )); - if (0 != shdr[i].sh_size % sizeof(Elf32_Sym)) { + if (0 != shdr[i].sh_size % sizeof(Elf_Sym)) { belch("%s: non-integral number of symbol table entries", oc->fileName); return 0; } @@ -1953,7 +2206,7 @@ ocVerifyImage_ELF ( ObjectCode* oc ) (char*)stab[j].st_value )); IF_DEBUG(linker,fprintf(stderr, "type=" )); - switch (ELF32_ST_TYPE(stab[j].st_info)) { + switch (ELF_ST_TYPE(stab[j].st_info)) { case STT_NOTYPE: IF_DEBUG(linker,fprintf(stderr, "notype " )); break; case STT_OBJECT: IF_DEBUG(linker,fprintf(stderr, "object " )); break; case STT_FUNC : IF_DEBUG(linker,fprintf(stderr, "func " )); break; @@ -1964,7 +2217,7 @@ ocVerifyImage_ELF ( ObjectCode* oc ) IF_DEBUG(linker,fprintf(stderr, " " )); IF_DEBUG(linker,fprintf(stderr, "bind=" )); - switch (ELF32_ST_BIND(stab[j].st_info)) { + switch (ELF_ST_BIND(stab[j].st_info)) { case STB_LOCAL : IF_DEBUG(linker,fprintf(stderr, "local " )); break; case STB_GLOBAL: IF_DEBUG(linker,fprintf(stderr, "global" )); break; case STB_WEAK : IF_DEBUG(linker,fprintf(stderr, "weak " )); break; @@ -1989,12 +2242,12 @@ static int ocGetNames_ELF ( ObjectCode* oc ) { int i, j, k, nent; - Elf32_Sym* stab; + Elf_Sym* stab; - char* ehdrC = (char*)(oc->image); - Elf32_Ehdr* ehdr = (Elf32_Ehdr*)ehdrC; - char* strtab = findElfSection ( ehdrC, SHT_STRTAB ); - Elf32_Shdr* shdr = (Elf32_Shdr*) (ehdrC + ehdr->e_shoff); + char* ehdrC = (char*)(oc->image); + Elf_Ehdr* ehdr = (Elf_Ehdr*)ehdrC; + char* strtab = findElfSection ( ehdrC, SHT_STRTAB ); + Elf_Shdr* shdr = (Elf_Shdr*) (ehdrC + ehdr->e_shoff); ASSERT(symhash != NULL); @@ -2008,7 +2261,7 @@ ocGetNames_ELF ( ObjectCode* oc ) /* Figure out what kind of section it is. Logic derived from Figure 1.14 ("Special Sections") of the ELF document ("Portable Formats Specification, Version 1.1"). */ - Elf32_Shdr hdr = shdr[i]; + Elf_Shdr hdr = shdr[i]; SectionKind kind = SECTIONKIND_OTHER; int is_bss = FALSE; @@ -2060,8 +2313,8 @@ ocGetNames_ELF ( ObjectCode* oc ) if (shdr[i].sh_type != SHT_SYMTAB) continue; /* copy stuff into this module's object symbol table */ - stab = (Elf32_Sym*) (ehdrC + shdr[i].sh_offset); - nent = shdr[i].sh_size / sizeof(Elf32_Sym); + stab = (Elf_Sym*) (ehdrC + shdr[i].sh_offset); + nent = shdr[i].sh_size / sizeof(Elf_Sym); oc->n_symbols = nent; oc->symbols = stgMallocBytes(oc->n_symbols * sizeof(char*), @@ -2088,8 +2341,8 @@ ocGetNames_ELF ( ObjectCode* oc ) since the linker should never poke around in it. */ } else - if ( ( ELF32_ST_BIND(stab[j].st_info)==STB_GLOBAL - || ELF32_ST_BIND(stab[j].st_info)==STB_LOCAL + if ( ( ELF_ST_BIND(stab[j].st_info)==STB_GLOBAL + || ELF_ST_BIND(stab[j].st_info)==STB_LOCAL ) /* and not an undefined symbol */ && stab[j].st_shndx != SHN_UNDEF @@ -2097,9 +2350,9 @@ ocGetNames_ELF ( ObjectCode* oc ) && stab[j].st_shndx < SHN_LORESERVE && /* and it's a not a section or string table or anything silly */ - ( ELF32_ST_TYPE(stab[j].st_info)==STT_FUNC || - ELF32_ST_TYPE(stab[j].st_info)==STT_OBJECT || - ELF32_ST_TYPE(stab[j].st_info)==STT_NOTYPE + ( ELF_ST_TYPE(stab[j].st_info)==STT_FUNC || + ELF_ST_TYPE(stab[j].st_info)==STT_OBJECT || + ELF_ST_TYPE(stab[j].st_info)==STT_NOTYPE ) ) { /* Section 0 is the undefined section, hence > and not >=. */ @@ -2111,9 +2364,16 @@ ocGetNames_ELF ( ObjectCode* oc ) } */ ad = ehdrC + shdr[ secno ].sh_offset + stab[j].st_value; - if (ELF32_ST_BIND(stab[j].st_info)==STB_LOCAL) { + if (ELF_ST_BIND(stab[j].st_info)==STB_LOCAL) { isLocal = TRUE; } else { +#ifdef ELF_FUNCTION_DESC + /* dlsym() and the initialisation table both give us function + * descriptors, so to be consistent we store function descriptors + * in the symbol table */ + if (ELF_ST_TYPE(stab[j].st_info) == STT_FUNC) + ad = (char *)allocateFunctionDesc((Elf_Addr)ad); +#endif IF_DEBUG(linker,belch( "addOTabName(GLOB): %10p %s %s", ad, oc->fileName, nm )); isLocal = FALSE; @@ -2138,8 +2398,8 @@ ocGetNames_ELF ( ObjectCode* oc ) /* fprintf(stderr, "skipping bind = %d, type = %d, shndx = %d `%s'\n", - (int)ELF32_ST_BIND(stab[j].st_info), - (int)ELF32_ST_TYPE(stab[j].st_info), + (int)ELF_ST_BIND(stab[j].st_info), + (int)ELF_ST_TYPE(stab[j].st_info), (int)stab[j].st_shndx, strtab + stab[j].st_name ); @@ -2153,33 +2413,35 @@ ocGetNames_ELF ( ObjectCode* oc ) return 1; } - /* Do ELF relocations which lack an explicit addend. All x86-linux relocations appear to be of this form. */ static int -do_Elf32_Rel_relocations ( ObjectCode* oc, char* ehdrC, - Elf32_Shdr* shdr, int shnum, - Elf32_Sym* stab, char* strtab ) +do_Elf_Rel_relocations ( ObjectCode* oc, char* ehdrC, + Elf_Shdr* shdr, int shnum, + Elf_Sym* stab, char* strtab ) { int j; char *symbol; - Elf32_Word* targ; - Elf32_Rel* rtab = (Elf32_Rel*) (ehdrC + shdr[shnum].sh_offset); - int nent = shdr[shnum].sh_size / sizeof(Elf32_Rel); + Elf_Word* targ; + Elf_Rel* rtab = (Elf_Rel*) (ehdrC + shdr[shnum].sh_offset); + int nent = shdr[shnum].sh_size / sizeof(Elf_Rel); int target_shndx = shdr[shnum].sh_info; int symtab_shndx = shdr[shnum].sh_link; - stab = (Elf32_Sym*) (ehdrC + shdr[ symtab_shndx ].sh_offset); - targ = (Elf32_Word*)(ehdrC + shdr[ target_shndx ].sh_offset); + + stab = (Elf_Sym*) (ehdrC + shdr[ symtab_shndx ].sh_offset); + targ = (Elf_Word*)(ehdrC + shdr[ target_shndx ].sh_offset); IF_DEBUG(linker,belch( "relocations for section %d using symtab %d", target_shndx, symtab_shndx )); + for (j = 0; j < nent; j++) { - Elf32_Addr offset = rtab[j].r_offset; - Elf32_Word info = rtab[j].r_info; + Elf_Addr offset = rtab[j].r_offset; + Elf_Word info = rtab[j].r_info; - Elf32_Addr P = ((Elf32_Addr)targ) + offset; - Elf32_Word* pP = (Elf32_Word*)P; - Elf32_Addr A = *pP; - Elf32_Addr S; + Elf_Addr P = ((Elf_Addr)targ) + offset; + Elf_Word* pP = (Elf_Word*)P; + Elf_Addr A = *pP; + Elf_Addr S; + Elf_Addr value; IF_DEBUG(linker,belch( "Rel entry %3d is raw(%6p %6p)", j, (void*)offset, (void*)info )); @@ -2187,15 +2449,15 @@ do_Elf32_Rel_relocations ( ObjectCode* oc, char* ehdrC, IF_DEBUG(linker,belch( " ZERO" )); S = 0; } else { - Elf32_Sym sym = stab[ELF32_R_SYM(info)]; + Elf_Sym sym = stab[ELF_R_SYM(info)]; /* First see if it is a local symbol. */ - if (ELF32_ST_BIND(sym.st_info) == STB_LOCAL) { + if (ELF_ST_BIND(sym.st_info) == STB_LOCAL) { /* Yes, so we can get the address directly from the ELF symbol table. */ symbol = sym.st_name==0 ? "(noname)" : strtab+sym.st_name; - S = (Elf32_Addr) + S = (Elf_Addr) (ehdrC + shdr[ sym.st_shndx ].sh_offset - + stab[ELF32_R_SYM(info)].st_value); + + stab[ELF_R_SYM(info)].st_value); } else { /* No, so look up the name in our global table. */ @@ -2208,17 +2470,21 @@ do_Elf32_Rel_relocations ( ObjectCode* oc, char* ehdrC, } IF_DEBUG(linker,belch( "`%s' resolves to %p", symbol, (void*)S )); } + IF_DEBUG(linker,belch( "Reloc: P = %p S = %p A = %p", (void*)P, (void*)S, (void*)A )); checkProddableBlock ( oc, pP ); - switch (ELF32_R_TYPE(info)) { + + value = S + A; + + switch (ELF_R_TYPE(info)) { # ifdef i386_TARGET_ARCH - case R_386_32: *pP = S + A; break; - case R_386_PC32: *pP = S + A - P; break; + case R_386_32: *pP = value; break; + case R_386_PC32: *pP = value - P; break; # endif default: belch("%s: unhandled ELF relocation(Rel) type %d\n", - oc->fileName, ELF32_R_TYPE(info)); + oc->fileName, ELF_R_TYPE(info)); return 0; } @@ -2226,94 +2492,109 @@ do_Elf32_Rel_relocations ( ObjectCode* oc, char* ehdrC, return 1; } - /* Do ELF relocations for which explicit addends are supplied. sparc-solaris relocations appear to be of this form. */ static int -do_Elf32_Rela_relocations ( ObjectCode* oc, char* ehdrC, - Elf32_Shdr* shdr, int shnum, - Elf32_Sym* stab, char* strtab ) +do_Elf_Rela_relocations ( ObjectCode* oc, char* ehdrC, + Elf_Shdr* shdr, int shnum, + Elf_Sym* stab, char* strtab ) { int j; char *symbol; - Elf32_Word* targ; - Elf32_Rela* rtab = (Elf32_Rela*) (ehdrC + shdr[shnum].sh_offset); - int nent = shdr[shnum].sh_size / sizeof(Elf32_Rela); + Elf_Addr* targ; + Elf_Rela* rtab = (Elf_Rela*) (ehdrC + shdr[shnum].sh_offset); + int nent = shdr[shnum].sh_size / sizeof(Elf_Rela); int target_shndx = shdr[shnum].sh_info; int symtab_shndx = shdr[shnum].sh_link; - stab = (Elf32_Sym*) (ehdrC + shdr[ symtab_shndx ].sh_offset); - targ = (Elf32_Word*)(ehdrC + shdr[ target_shndx ].sh_offset); + + stab = (Elf_Sym*) (ehdrC + shdr[ symtab_shndx ].sh_offset); + targ = (Elf_Addr*)(ehdrC + shdr[ target_shndx ].sh_offset); IF_DEBUG(linker,belch( "relocations for section %d using symtab %d", target_shndx, symtab_shndx )); + for (j = 0; j < nent; j++) { - Elf32_Addr offset = rtab[j].r_offset; - Elf32_Word info = rtab[j].r_info; -# if defined(sparc_TARGET_ARCH) || defined(DEBUG) - Elf32_Sword addend = rtab[j].r_addend; - Elf32_Addr A = addend; -# endif - Elf32_Addr P = ((Elf32_Addr)targ) + offset; - Elf32_Addr S; + Elf_Addr offset = rtab[j].r_offset; + Elf_Addr info = rtab[j].r_info; + Elf_Addr A = rtab[j].r_addend; + Elf_Addr P = (Elf_Addr)targ + offset; + Elf_Addr S; + Elf_Addr value; # if defined(sparc_TARGET_ARCH) /* This #ifdef only serves to avoid unused-var warnings. */ - Elf32_Word* pP = (Elf32_Word*)P; - Elf32_Word w1, w2; + Elf_Word* pP = (Elf_Word*)P; + Elf_Word w1, w2; +# elif defined(ia64_TARGET_ARCH) + Elf64_Xword *pP = (Elf64_Xword *)P; + Elf_Addr addr; # endif IF_DEBUG(linker,belch( "Rel entry %3d is raw(%6p %6p %6p) ", j, (void*)offset, (void*)info, - (void*)addend )); + (void*)A )); if (!info) { IF_DEBUG(linker,belch( " ZERO" )); S = 0; } else { - Elf32_Sym sym = stab[ELF32_R_SYM(info)]; + Elf_Sym sym = stab[ELF_R_SYM(info)]; /* First see if it is a local symbol. */ - if (ELF32_ST_BIND(sym.st_info) == STB_LOCAL) { + if (ELF_ST_BIND(sym.st_info) == STB_LOCAL) { /* Yes, so we can get the address directly from the ELF symbol table. */ symbol = sym.st_name==0 ? "(noname)" : strtab+sym.st_name; - S = (Elf32_Addr) + S = (Elf_Addr) (ehdrC + shdr[ sym.st_shndx ].sh_offset - + stab[ELF32_R_SYM(info)].st_value); - + + stab[ELF_R_SYM(info)].st_value); +#ifdef ELF_FUNCTION_DESC + /* Make a function descriptor for this function */ + if (S && ELF_ST_TYPE(sym.st_info) == STT_FUNC) { + S = allocateFunctionDesc(S + A); + A = 0; + } +#endif } else { /* No, so look up the name in our global table. */ symbol = strtab + sym.st_name; (void*)S = lookupSymbol( symbol ); + +#ifdef ELF_FUNCTION_DESC + /* If a function, already a function descriptor - we would + have to copy it to add an offset. */ + if (S && ELF_ST_TYPE(sym.st_info) == STT_FUNC) + assert(A == 0); +#endif } if (!S) { belch("%s: unknown symbol `%s'", oc->fileName, symbol); return 0; - /* - S = 0x11223344; - fprintf ( stderr, "S %p A %p S+A %p S+A-P %p\n",S,A,S+A,S+A-P); - */ } IF_DEBUG(linker,belch( "`%s' resolves to %p", symbol, (void*)S )); } + IF_DEBUG(linker,fprintf ( stderr, "Reloc: P = %p S = %p A = %p\n", (void*)P, (void*)S, (void*)A )); - checkProddableBlock ( oc, (void*)P ); - switch (ELF32_R_TYPE(info)) { + /* checkProddableBlock ( oc, (void*)P ); */ + + value = S + A; + + switch (ELF_R_TYPE(info)) { # if defined(sparc_TARGET_ARCH) case R_SPARC_WDISP30: w1 = *pP & 0xC0000000; - w2 = (Elf32_Word)((S + A - P) >> 2); + w2 = (Elf_Word)((value - P) >> 2); ASSERT((w2 & 0xC0000000) == 0); w1 |= w2; *pP = w1; break; case R_SPARC_HI22: w1 = *pP & 0xFFC00000; - w2 = (Elf32_Word)((S + A) >> 10); + w2 = (Elf_Word)(value >> 10); ASSERT((w2 & 0xFFC00000) == 0); w1 |= w2; *pP = w1; break; case R_SPARC_LO10: w1 = *pP & ~0x3FF; - w2 = (Elf32_Word)((S + A) & 0x3FF); + w2 = (Elf_Word)(value & 0x3FF); ASSERT((w2 & ~0x3FF) == 0); w1 |= w2; *pP = w1; @@ -2330,13 +2611,33 @@ do_Elf32_Rela_relocations ( ObjectCode* oc, char* ehdrC, */ case R_SPARC_UA32: case R_SPARC_32: - w2 = (Elf32_Word)(S + A); + w2 = (Elf_Word)value; *pP = w2; break; +# elif defined(ia64_TARGET_ARCH) + case R_IA64_DIR64LSB: + case R_IA64_FPTR64LSB: + *pP = value; + break; + case R_IA64_SEGREL64LSB: + addr = findElfSegment(ehdrC, value); + *pP = value - addr; + break; + case R_IA64_GPREL22: + ia64_reloc_gprel22(P, value); + break; + case R_IA64_LTOFF22: + case R_IA64_LTOFF_FPTR22: + addr = allocateGOTEntry(value); + ia64_reloc_gprel22(P, addr); + break; + case R_IA64_PCREL21B: + ia64_reloc_pcrel21(P, S, oc); + break; # endif default: belch("%s: unhandled ELF relocation(RelA) type %d\n", - oc->fileName, ELF32_R_TYPE(info)); + oc->fileName, ELF_R_TYPE(info)); return 0; } @@ -2344,20 +2645,19 @@ do_Elf32_Rela_relocations ( ObjectCode* oc, char* ehdrC, return 1; } - static int ocResolve_ELF ( ObjectCode* oc ) { char *strtab; int shnum, ok; - Elf32_Sym* stab = NULL; - char* ehdrC = (char*)(oc->image); - Elf32_Ehdr* ehdr = (Elf32_Ehdr*) ehdrC; - Elf32_Shdr* shdr = (Elf32_Shdr*) (ehdrC + ehdr->e_shoff); - char* sh_strtab = ehdrC + shdr[ehdr->e_shstrndx].sh_offset; + Elf_Sym* stab = NULL; + char* ehdrC = (char*)(oc->image); + Elf_Ehdr* ehdr = (Elf_Ehdr*) ehdrC; + Elf_Shdr* shdr = (Elf_Shdr*) (ehdrC + ehdr->e_shoff); + char* sh_strtab = ehdrC + shdr[ehdr->e_shstrndx].sh_offset; /* first find "the" symbol table */ - stab = (Elf32_Sym*) findElfSection ( ehdrC, SHT_SYMTAB ); + stab = (Elf_Sym*) findElfSection ( ehdrC, SHT_SYMTAB ); /* also go find the string table */ strtab = findElfSection ( ehdrC, SHT_STRTAB ); @@ -2378,17 +2678,16 @@ ocResolve_ELF ( ObjectCode* oc ) continue; if (shdr[shnum].sh_type == SHT_REL ) { - ok = do_Elf32_Rel_relocations ( oc, ehdrC, shdr, - shnum, stab, strtab ); + ok = do_Elf_Rel_relocations ( oc, ehdrC, shdr, + shnum, stab, strtab ); if (!ok) return ok; } else if (shdr[shnum].sh_type == SHT_RELA) { - ok = do_Elf32_Rela_relocations ( oc, ehdrC, shdr, - shnum, stab, strtab ); + ok = do_Elf_Rela_relocations ( oc, ehdrC, shdr, + shnum, stab, strtab ); if (!ok) return ok; } - } /* Free the local symbol table; we won't need it again. */ @@ -2399,4 +2698,96 @@ ocResolve_ELF ( ObjectCode* oc ) } +/* + * IA64 specifics + * Instructions are 41 bits long, packed into 128 bit bundles with a 5-bit template + * at the front. The following utility functions pack and unpack instructions, and + * take care of the most common relocations. + */ + +#ifdef ia64_TARGET_ARCH + +static Elf64_Xword +ia64_extract_instruction(Elf64_Xword *target) +{ + Elf64_Xword w1, w2; + int slot = (Elf_Addr)target & 3; + (Elf_Addr)target &= ~3; + + w1 = *target; + w2 = *(target+1); + + switch (slot) + { + case 0: + return ((w1 >> 5) & 0x1ffffffffff); + case 1: + return (w1 >> 46) | ((w2 & 0x7fffff) << 18); + case 2: + return (w2 >> 23); + default: + barf("ia64_extract_instruction: invalid slot %p", target); + } +} + +static void +ia64_deposit_instruction(Elf64_Xword *target, Elf64_Xword value) +{ + int slot = (Elf_Addr)target & 3; + (Elf_Addr)target &= ~3; + + switch (slot) + { + case 0: + *target |= value << 5; + break; + case 1: + *target |= value << 46; + *(target+1) |= value >> 18; + break; + case 2: + *(target+1) |= value << 23; + break; + } +} + +static void +ia64_reloc_gprel22(Elf_Addr target, Elf_Addr value) +{ + Elf64_Xword instruction; + Elf64_Sxword rel_value; + + rel_value = value - gp_val; + if ((rel_value > 0x1fffff) || (rel_value < -0x1fffff)) + barf("GP-relative data out of range (address = 0x%lx, gp = 0x%lx)", value, gp_val); + + instruction = ia64_extract_instruction((Elf64_Xword *)target); + instruction |= (((rel_value >> 0) & 0x07f) << 13) /* imm7b */ + | (((rel_value >> 7) & 0x1ff) << 27) /* imm9d */ + | (((rel_value >> 16) & 0x01f) << 22) /* imm5c */ + | ((Elf64_Xword)(rel_value < 0) << 36); /* s */ + ia64_deposit_instruction((Elf64_Xword *)target, instruction); +} + +static void +ia64_reloc_pcrel21(Elf_Addr target, Elf_Addr value, ObjectCode *oc) +{ + Elf64_Xword instruction; + Elf64_Sxword rel_value; + Elf_Addr entry; + + entry = allocatePLTEntry(value, oc); + + rel_value = (entry >> 4) - (target >> 4); + if ((rel_value > 0xfffff) || (rel_value < -0xfffff)) + barf("PLT entry too far away (entry = 0x%lx, target = 0x%lx)", entry, target); + + instruction = ia64_extract_instruction((Elf64_Xword *)target); + instruction |= ((rel_value & 0xfffff) << 13) /* imm20b */ + | ((Elf64_Xword)(rel_value < 0) << 36); /* s */ + ia64_deposit_instruction((Elf64_Xword *)target, instruction); +} + +#endif /* ia64 */ + #endif /* ELF */ diff --git a/ghc/rts/LinkerInternals.h b/ghc/rts/LinkerInternals.h index 2f5fa17..0763703 100644 --- a/ghc/rts/LinkerInternals.h +++ b/ghc/rts/LinkerInternals.h @@ -1,5 +1,5 @@ /* ----------------------------------------------------------------------------- - * $Id: LinkerInternals.h,v 1.5 2001/09/04 16:33:04 sewardj Exp $ + * $Id: LinkerInternals.h,v 1.6 2002/06/09 13:37:44 matthewc Exp $ * * (c) The GHC Team, 2000 * @@ -70,7 +70,13 @@ typedef struct _ObjectCode { safely be prodded during relocation. Any attempt to prod outside one of these is an error in the linker. */ ProddableBlock* proddables; - + +#ifdef ia64_TARGET_ARCH + /* Procedure Linkage Table for this object */ + void *plt; + unsigned int pltIndex; +#endif + } ObjectCode; extern ObjectCode *objects; -- 1.7.10.4