X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=ghc%2Frts%2FLinker.c;h=d733257d1fce2de46e2ae6187f51a17a8677f341;hb=2db150e82af6cb9802006227cffb8414d99261f3;hp=e4d2d07400979e7180049e2645cec6aa921e8568;hpb=f87914660f07f6915eaa7e31c195b77c71b95391;p=ghc-hetmet.git diff --git a/ghc/rts/Linker.c b/ghc/rts/Linker.c index e4d2d07..d733257 100644 --- a/ghc/rts/Linker.c +++ b/ghc/rts/Linker.c @@ -1,7 +1,7 @@ /* ----------------------------------------------------------------------------- - * $Id: Linker.c,v 1.59 2001/08/21 15:22:09 sewardj Exp $ + * $Id: Linker.c,v 1.67 2001/09/12 14:53:39 sewardj Exp $ * - * (c) The GHC Team, 2000 + * (c) The GHC Team, 2000, 2001 * * RTS Object Linker * @@ -138,6 +138,7 @@ typedef struct _RtsSymbolVal { Sym(mktime) \ Sym(_imp___timezone) \ Sym(_imp___tzname) \ + Sym(_imp___iob) \ Sym(localtime) \ Sym(gmtime) \ SymX(getenv) \ @@ -286,7 +287,7 @@ typedef struct _RtsSymbolVal { Sym(StgReturn) \ Sym(init_stack) \ SymX(cmp_thread) \ - Sym(__init_PrelGHC) \ + Sym(__stginit_PrelGHC) \ SymX(freeHaskellFunctionPtr) \ SymX(OnExitHook) \ SymX(ErrorHdrHook) \ @@ -424,7 +425,7 @@ static OpenedDLL* opened_dlls = NULL; char* -addDLL ( char* path, char* dll_name ) +addDLL ( __attribute((unused)) char* path, char* dll_name ) { # if defined(OBJFORMAT_ELF) void *hdl; @@ -506,15 +507,15 @@ lookupSymbol( char *lbl ) void* sym; for (o_dll = opened_dlls; o_dll != NULL; o_dll = o_dll->next) { /* fprintf(stderr, "look in %s for %s\n", o_dll->name, lbl); */ - if (lbl[0] == '_') { - /* HACK: if the name has an initial underscore, try stripping - it off & look that up first. I've yet to verify whether there's - a Rule that governs whether an initial '_' *should always* be - stripped off when mapping from import lib name to the DLL name. - */ - sym = GetProcAddress(o_dll->instance, (lbl+1)); - if (sym != NULL) return sym; - } + if (lbl[0] == '_') { + /* HACK: if the name has an initial underscore, try stripping + it off & look that up first. I've yet to verify whether there's + a Rule that governs whether an initial '_' *should always* be + stripped off when mapping from import lib name to the DLL name. + */ + sym = GetProcAddress(o_dll->instance, (lbl+1)); + if (sym != NULL) return sym; + } sym = GetProcAddress(o_dll->instance, lbl); if (sym != NULL) return sym; } @@ -589,6 +590,7 @@ loadObj( char *path ) oc->symbols = NULL; oc->sections = NULL; oc->lochash = allocStrHashTable(); + oc->proddables = NULL; /* chain it onto the list of objects */ oc->next = objects; @@ -709,6 +711,54 @@ unloadObj( char *path ) return 0; } +/* ----------------------------------------------------------------------------- + * Sanity checking. For each ObjectCode, maintain a list of address ranges + * which may be prodded during relocation, and abort if we try and write + * outside any of these. + */ +static void addProddableBlock ( ObjectCode* oc, void* start, int size ) +{ + ProddableBlock* pb + = stgMallocBytes(sizeof(ProddableBlock), "addProddableBlock"); + /* fprintf(stderr, "aPB %p %p %d\n", oc, start, size); */ + ASSERT(size > 0); + pb->start = start; + pb->size = size; + pb->next = oc->proddables; + oc->proddables = pb; +} + +static void checkProddableBlock ( ObjectCode* oc, void* addr ) +{ + ProddableBlock* pb; + for (pb = oc->proddables; pb != NULL; pb = pb->next) { + char* s = (char*)(pb->start); + char* e = s + pb->size - 1; + char* a = (char*)addr; + /* Assumes that the biggest fixup involves a 4-byte write. This + probably needs to be changed to 8 (ie, +7) on 64-bit + plats. */ + if (a >= s && (a+3) <= e) return; + } + barf("checkProddableBlock: invalid fixup in runtime linker"); +} + +/* ----------------------------------------------------------------------------- + * Section management. + */ +static void addSection ( ObjectCode* oc, SectionKind kind, + void* start, void* end ) +{ + Section* s = stgMallocBytes(sizeof(Section), "addSection"); + s->start = start; + s->end = end; + s->kind = kind; + s->next = oc->sections; + oc->sections = s; +} + + + /* -------------------------------------------------------------------------- * PEi386 specifics (Win32 targets) * ------------------------------------------------------------------------*/ @@ -981,8 +1031,14 @@ ocVerifyImage_PEi386 ( ObjectCode* oc ) (int)(hdr->Characteristics)); return 0; } + /* If the string table size is way crazy, this might indicate that + there are more than 64k relocations, despite claims to the + contrary. Hence this test. */ /* fprintf(stderr, "strtab size %d\n", * (UInt32*)strtab); */ - if (* (UInt32*)strtab > 510000) { + if (* (UInt32*)strtab > 600000) { + /* Note that 600k has no special significance other than being + big enough to handle the almost-2MB-sized lumps that + constitute HSwin32*.o. */ belch("PEi386 object has suspiciously large string table; > 64k relocs?"); return 0; } @@ -1036,13 +1092,15 @@ ocVerifyImage_PEi386 ( ObjectCode* oc ) " data sz %d\n" " data off %d\n" " num rel %d\n" - " off rel %d\n", + " off rel %d\n" + " ptr raw 0x%x\n", sectab_i->VirtualSize, sectab_i->VirtualAddress, sectab_i->SizeOfRawData, sectab_i->PointerToRawData, sectab_i->NumberOfRelocations, - sectab_i->PointerToRelocations + sectab_i->PointerToRelocations, + sectab_i->PointerToRawData ); reltab = (COFF_reloc*) ( ((UChar*)(oc->image)) + sectab_i->PointerToRelocations @@ -1061,9 +1119,9 @@ ocVerifyImage_PEi386 ( ObjectCode* oc ) printName ( sym->Name, strtab -10 ); fprintf ( stderr, "'\n" ); } + fprintf ( stderr, "\n" ); } - fprintf ( stderr, "\n" ); fprintf ( stderr, "string table has size 0x%x\n", * (UInt32*)strtab ); fprintf ( stderr, "---START of string table---\n"); @@ -1090,12 +1148,12 @@ ocVerifyImage_PEi386 ( ObjectCode* oc ) fprintf ( stderr, "'\n" " value 0x%x\n" - " sec# %d\n" + " 1+sec# %d\n" " type 0x%x\n" " sclass 0x%x\n" " nAux %d\n", symtab_i->Value, - (Int32)(symtab_i->SectionNumber) - 1, + (Int32)(symtab_i->SectionNumber), (UInt32)symtab_i->Type, (UInt32)symtab_i->StorageClass, (UInt32)symtab_i->NumberOfAuxSymbols @@ -1134,62 +1192,31 @@ ocGetNames_PEi386 ( ObjectCode* oc ) + hdr->PointerToSymbolTable + hdr->NumberOfSymbols * sizeof_COFF_symbol; - /* Copy exported symbols into the ObjectCode. */ - - oc->n_symbols = hdr->NumberOfSymbols; - oc->symbols = stgMallocBytes(oc->n_symbols * sizeof(char*), - "ocGetNames_PEi386(oc->symbols)"); - /* Call me paranoid; I don't care. */ - for (i = 0; i < oc->n_symbols; i++) - oc->symbols[i] = NULL; - - i = 0; - while (1) { - COFF_symbol* symtab_i; - if (i >= (Int32)(hdr->NumberOfSymbols)) break; - symtab_i = (COFF_symbol*) - myindex ( sizeof_COFF_symbol, symtab, i ); - - if (symtab_i->StorageClass == MYIMAGE_SYM_CLASS_EXTERNAL && - symtab_i->SectionNumber != MYIMAGE_SYM_UNDEFINED) { - - /* This symbol is global and defined, viz, exported */ - COFF_section* sectabent; + /* Allocate space for any (local, anonymous) .bss sections. */ - /* cstring_from_COFF_symbol_name always succeeds. */ - sname = cstring_from_COFF_symbol_name ( symtab_i->Name, strtab ); - - /* for MYIMAGE_SYMCLASS_EXTERNAL - && !MYIMAGE_SYM_UNDEFINED, - the address of the symbol is: - address of relevant section + offset in section - */ - sectabent = (COFF_section*) - myindex ( sizeof_COFF_section, - sectab, - symtab_i->SectionNumber-1 ); - addr = ((UChar*)(oc->image)) - + (sectabent->PointerToRawData - + symtab_i->Value); - /* fprintf(stderr,"addSymbol %p `%s'\n", addr,sname); */ - IF_DEBUG(linker, belch("addSymbol %p `%s'\n", addr,sname);) - ASSERT(i >= 0 && i < oc->n_symbols); - oc->symbols[i] = sname; - insertStrHashTable(symhash, sname, addr); - } - i += symtab_i->NumberOfAuxSymbols; - i++; + for (i = 0; i < hdr->NumberOfSections; i++) { + UChar* zspace; + COFF_section* sectab_i + = (COFF_section*) + myindex ( sizeof_COFF_section, sectab, i ); + if (0 != strcmp(sectab_i->Name, ".bss")) continue; + if (sectab_i->VirtualSize == 0) continue; + /* This is a non-empty .bss section. Allocate zeroed space for + it, and set its PointerToRawData field such that oc->image + + PointerToRawData == addr_of_zeroed_space. */ + zspace = stgCallocBytes(1, sectab_i->VirtualSize, + "ocGetNames_PEi386(anonymous bss)"); + sectab_i->PointerToRawData = ((UChar*)zspace) - ((UChar*)(oc->image)); + addProddableBlock(oc, zspace, sectab_i->VirtualSize); + /* fprintf(stderr, "BSS anon section at 0x%x\n", zspace); */ } /* Copy section information into the ObjectCode. */ - oc->n_sections = hdr->NumberOfSections; - oc->sections = stgMallocBytes( oc->n_sections * sizeof(Section), - "ocGetNamesPEi386" ); - - for (i = 0; i < oc->n_sections; i++) { + for (i = 0; i < hdr->NumberOfSections; i++) { UChar* start; UChar* end; + UInt32 sz; SectionKind kind = SECTIONKIND_OTHER; @@ -1198,7 +1225,7 @@ ocGetNames_PEi386 ( ObjectCode* oc ) myindex ( sizeof_COFF_section, sectab, i ); IF_DEBUG(linker, belch("section name = %s\n", sectab_i->Name )); -#if 0 +# if 0 /* I'm sure this is the Right Way to do it. However, the alternative of testing the sectab_i->Name field seems to work ok with Cygwin. @@ -1206,7 +1233,7 @@ ocGetNames_PEi386 ( ObjectCode* oc ) if (sectab_i->Characteristics & MYIMAGE_SCN_CNT_CODE || sectab_i->Characteristics & MYIMAGE_SCN_CNT_INITIALIZED_DATA) kind = SECTIONKIND_CODE_OR_RODATA; -#endif +# endif if (0==strcmp(".text",sectab_i->Name) || 0==strcmp(".rodata",sectab_i->Name)) @@ -1215,19 +1242,105 @@ ocGetNames_PEi386 ( ObjectCode* oc ) 0==strcmp(".bss",sectab_i->Name)) kind = SECTIONKIND_RWDATA; - start = ((UChar*)(oc->image)) - + sectab_i->PointerToRawData; - end = start - + sectab_i->SizeOfRawData - 1; + ASSERT(sectab_i->SizeOfRawData == 0 || sectab_i->VirtualSize == 0); + sz = sectab_i->SizeOfRawData; + if (sz < sectab_i->VirtualSize) sz = sectab_i->VirtualSize; + + start = ((UChar*)(oc->image)) + sectab_i->PointerToRawData; + end = start + sz - 1; if (kind == SECTIONKIND_OTHER) { belch("Unknown PEi386 section name `%s'", sectab_i->Name); return 0; } - oc->sections[i].start = start; - oc->sections[i].end = end; - oc->sections[i].kind = kind; + if (end >= start) { + addSection(oc, kind, start, end); + addProddableBlock(oc, start, end - start + 1); + } + } + + /* Copy exported symbols into the ObjectCode. */ + + oc->n_symbols = hdr->NumberOfSymbols; + oc->symbols = stgMallocBytes(oc->n_symbols * sizeof(char*), + "ocGetNames_PEi386(oc->symbols)"); + /* Call me paranoid; I don't care. */ + for (i = 0; i < oc->n_symbols; i++) + oc->symbols[i] = NULL; + + i = 0; + while (1) { + COFF_symbol* symtab_i; + if (i >= (Int32)(hdr->NumberOfSymbols)) break; + symtab_i = (COFF_symbol*) + myindex ( sizeof_COFF_symbol, symtab, i ); + + addr = NULL; + + if (symtab_i->StorageClass == MYIMAGE_SYM_CLASS_EXTERNAL + && symtab_i->SectionNumber != MYIMAGE_SYM_UNDEFINED) { + /* This symbol is global and defined, viz, exported */ + /* for MYIMAGE_SYMCLASS_EXTERNAL + && !MYIMAGE_SYM_UNDEFINED, + the address of the symbol is: + address of relevant section + offset in section + */ + COFF_section* sectabent + = (COFF_section*) myindex ( sizeof_COFF_section, + sectab, + symtab_i->SectionNumber-1 ); + addr = ((UChar*)(oc->image)) + + (sectabent->PointerToRawData + + symtab_i->Value); + } + else + if (symtab_i->SectionNumber == MYIMAGE_SYM_UNDEFINED + && symtab_i->Value > 0) { + /* This symbol isn't in any section at all, ie, global bss. + Allocate zeroed space for it. */ + addr = stgCallocBytes(1, symtab_i->Value, + "ocGetNames_PEi386(non-anonymous bss)"); + addSection(oc, SECTIONKIND_RWDATA, addr, + ((UChar*)addr) + symtab_i->Value - 1); + addProddableBlock(oc, addr, symtab_i->Value); + /* fprintf(stderr, "BSS section at 0x%x\n", addr); */ + } + + if (addr != NULL) { + sname = cstring_from_COFF_symbol_name ( symtab_i->Name, strtab ); + /* fprintf(stderr,"addSymbol %p `%s'\n", addr,sname); */ + IF_DEBUG(linker, belch("addSymbol %p `%s'\n", addr,sname);) + ASSERT(i >= 0 && i < oc->n_symbols); + /* cstring_from_COFF_symbol_name always succeeds. */ + oc->symbols[i] = sname; + insertStrHashTable(symhash, sname, addr); + } else { +# if 0 + fprintf ( stderr, + "IGNORING symbol %d\n" + " name `", + i + ); + printName ( symtab_i->Name, strtab ); + fprintf ( stderr, + "'\n" + " value 0x%x\n" + " 1+sec# %d\n" + " type 0x%x\n" + " sclass 0x%x\n" + " nAux %d\n", + symtab_i->Value, + (Int32)(symtab_i->SectionNumber), + (UInt32)symtab_i->Type, + (UInt32)symtab_i->StorageClass, + (UInt32)symtab_i->NumberOfAuxSymbols + ); +# endif + } + + i += symtab_i->NumberOfAuxSymbols; + i++; } return 1; @@ -1315,16 +1428,20 @@ ocResolve_PEi386 ( ObjectCode* oc ) + sym->Value); } else { copyName ( sym->Name, strtab, symbol, 1000-1 ); + (void*)S = lookupLocalSymbol( oc, symbol ); + if ((void*)S != NULL) goto foundit; + (void*)S = lookupSymbol( symbol ); + if ((void*)S != NULL) goto foundit; zapTrailingAtSign ( symbol ); (void*)S = lookupLocalSymbol( oc, symbol ); - if ((void*)S == NULL) - (void*)S = lookupSymbol( symbol ); - if (S == 0) { - belch("%s: unknown symbol `%s'", oc->fileName, symbol); - return 0; - } + if ((void*)S != NULL) goto foundit; + (void*)S = lookupSymbol( symbol ); + if ((void*)S != NULL) goto foundit; + belch("%s: unknown symbol `%s'", oc->fileName, symbol); + return 0; + foundit: } - + checkProddableBlock(oc, pP); switch (reltab_j->Type) { case MYIMAGE_REL_I386_DIR32: *pP = A + S; @@ -1582,27 +1699,38 @@ ocGetNames_ELF ( ObjectCode* oc ) } k = 0; - oc->n_sections = ehdr->e_shnum; - oc->sections = stgMallocBytes( oc->n_sections * sizeof(Section), - "ocGetNames_ELF(oc->sections)" ); - - for (i = 0; i < oc->n_sections; i++) { + for (i = 0; i < ehdr->e_shnum; i++) { /* make a section entry for relevant sections */ SectionKind kind = SECTIONKIND_OTHER; if (!strcmp(".data",sh_strtab+shdr[i].sh_name) || - !strcmp(".data1",sh_strtab+shdr[i].sh_name)) + !strcmp(".data1",sh_strtab+shdr[i].sh_name) || + !strcmp(".bss",sh_strtab+shdr[i].sh_name)) kind = SECTIONKIND_RWDATA; if (!strcmp(".text",sh_strtab+shdr[i].sh_name) || !strcmp(".rodata",sh_strtab+shdr[i].sh_name) || !strcmp(".rodata1",sh_strtab+shdr[i].sh_name)) kind = SECTIONKIND_CODE_OR_RODATA; + if (!strcmp(".bss",sh_strtab+shdr[i].sh_name) && shdr[i].sh_size > 0) { + /* This is a non-empty .bss section. Allocate zeroed space for + it, and set its .sh_offset field such that + ehdrC + .sh_offset == addr_of_zeroed_space. */ + char* zspace = stgCallocBytes(1, shdr[i].sh_size, + "ocGetNames_ELF(BSS)"); + shdr[i].sh_offset = ((char*)zspace) - ((char*)ehdrC); + /* + fprintf(stderr, "BSS section at 0x%x, size %d\n", + zspace, shdr[i].sh_size); + */ + } + /* fill in the section info */ - oc->sections[i].start = ehdrC + shdr[i].sh_offset; - oc->sections[i].end = ehdrC + shdr[i].sh_offset + shdr[i].sh_size - 1; - oc->sections[i].kind = kind; - + addSection(oc, kind, ehdrC + shdr[i].sh_offset, + ehdrC + shdr[i].sh_offset + shdr[i].sh_size - 1); + if (kind != SECTIONKIND_OTHER && shdr[i].sh_size > 0) + addProddableBlock(oc, ehdrC + shdr[i].sh_offset, shdr[i].sh_size); + if (shdr[i].sh_type != SHT_SYMTAB) continue; /* copy stuff into this module's object symbol table */ @@ -1614,6 +1742,26 @@ ocGetNames_ELF ( ObjectCode* oc ) "ocGetNames_ELF(oc->symbols)"); for (j = 0; j < nent; j++) { + + char isLocal = FALSE; /* avoids uninit-var warning */ + char* ad = NULL; + char* nm = strtab + stab[j].st_name; + int secno = stab[j].st_shndx; + + /* Figure out if we want to add it; if so, set ad to its + address. Otherwise leave ad == NULL. */ + + if (secno == SHN_COMMON) { + isLocal = FALSE; + ad = stgCallocBytes(1, stab[j].st_size, "ocGetNames_ELF(COMMON)"); + /* + fprintf(stderr, "COMMON symbol, size %d name %s\n", + stab[j].st_size, nm); + */ + /* Pointless to do addProddableBlock() for this area, + 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 ) @@ -1627,25 +1775,40 @@ ocGetNames_ELF ( ObjectCode* oc ) ELF32_ST_TYPE(stab[j].st_info)==STT_OBJECT || ELF32_ST_TYPE(stab[j].st_info)==STT_NOTYPE ) - ) { - char* nm = strtab + stab[j].st_name; - char* ad = ehdrC - + shdr[ stab[j].st_shndx ].sh_offset - + stab[j].st_value; - ASSERT(nm != NULL); - ASSERT(ad != NULL); - oc->symbols[j] = nm; + ) { + /* Section 0 is the undefined section, hence > and not >=. */ + ASSERT(secno > 0 && secno < ehdr->e_shnum); + /* + if (shdr[secno].sh_type == SHT_NOBITS) { + fprintf(stderr, " BSS symbol, size %d off %d name %s\n", + stab[j].st_size, stab[j].st_value, nm); + } + */ + ad = ehdrC + shdr[ secno ].sh_offset + stab[j].st_value; if (ELF32_ST_BIND(stab[j].st_info)==STB_LOCAL) { IF_DEBUG(linker,belch( "addOTabName(LOCL): %10p %s %s", ad, oc->fileName, nm )); - insertStrHashTable(oc->lochash, nm, ad); + isLocal = TRUE; } else { IF_DEBUG(linker,belch( "addOTabName(GLOB): %10p %s %s", ad, oc->fileName, nm )); - insertStrHashTable(symhash, nm, ad); + isLocal = FALSE; } } - else { + + /* And the decision is ... */ + + if (ad != NULL) { + ASSERT(nm != NULL); + oc->symbols[j] = nm; + /* Acquire! */ + if (isLocal) { + insertStrHashTable(oc->lochash, nm, ad); + } else { + insertStrHashTable(symhash, nm, ad); + } + } else { + /* Skip. */ IF_DEBUG(linker,belch( "skipping `%s'", strtab + stab[j].st_name )); /* @@ -1659,6 +1822,7 @@ ocGetNames_ELF ( ObjectCode* oc ) */ oc->symbols[j] = NULL; } + } } @@ -1721,6 +1885,7 @@ do_Elf32_Rel_relocations ( ObjectCode* oc, char* ehdrC, } 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)) { # ifdef i386_TARGET_ARCH case R_386_32: *pP = S + A; break; @@ -1759,7 +1924,6 @@ do_Elf32_Rela_relocations ( ObjectCode* oc, char* ehdrC, Elf32_Addr offset = rtab[j].r_offset; Elf32_Word info = rtab[j].r_info; Elf32_Sword addend = rtab[j].r_addend; - Elf32_Addr P = ((Elf32_Addr)targ) + offset; Elf32_Addr A = addend; Elf32_Addr S; @@ -1802,6 +1966,7 @@ do_Elf32_Rela_relocations ( ObjectCode* oc, char* ehdrC, } 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)) { # if defined(sparc_TARGET_ARCH) case R_SPARC_WDISP30: