From: sewardj Date: Wed, 23 Jan 2002 11:29:12 +0000 (+0000) Subject: [project @ 2002-01-23 11:29:12 by sewardj] X-Git-Tag: Approximately_9120_patches~270 X-Git-Url: http://git.megacz.com/?a=commitdiff_plain;h=830c1108833bbdfb9eb1309bd136aedf0b7d141f;p=ghc-hetmet.git [project @ 2002-01-23 11:29:12 by sewardj] Fix two problems with the ELF linker: 1. Determine section attributes by examining various bits in the section header tables, rather than from the section names. This makes it robust against future changes / additions to the set of section names. 2. Handle local symbols differently. Do not add them to our own local symbol table for this object, since that's (a) wrong -- multiple local symbols can have the same name so long as each is in a different section, so if we just dump them into the local symbol table we'll wind up with apparently duplicate symbols (b) totally unnecessary, since the relocations against local symbols simply specify an index into the ELF symbol table for the object, from whence the address can be calculated without reference to the name. TODO: Test on sparc-solaris Investigate whether PEi386 linker needs fixing similarly and then MERGE TO STABLE --- diff --git a/ghc/rts/Linker.c b/ghc/rts/Linker.c index f693a5e..31a21db 100644 --- a/ghc/rts/Linker.c +++ b/ghc/rts/Linker.c @@ -1,5 +1,5 @@ /* ----------------------------------------------------------------------------- - * $Id: Linker.c,v 1.77 2001/12/29 09:24:42 sof Exp $ + * $Id: Linker.c,v 1.78 2002/01/23 11:29:12 sewardj Exp $ * * (c) The GHC Team, 2000, 2001 * @@ -582,6 +582,7 @@ lookupSymbol( char *lbl ) } static +__attribute((unused)) void * lookupLocalSymbol( ObjectCode* oc, char *lbl ) { @@ -1609,6 +1610,7 @@ ocResolve_PEi386 ( ObjectCode* oc ) */ #include +#include static char * findElfSection ( void* objImage, Elf32_Word sh_type ) @@ -1625,7 +1627,7 @@ findElfSection ( void* objImage, Elf32_Word sh_type ) && i != ehdr->e_shstrndx /* Ignore string tables named .stabstr, as they contain debugging info. */ - && 0 != strcmp(".stabstr", sh_strtab + shdr[i].sh_name) + && 0 != strncmp(".stabstr", sh_strtab + shdr[i].sh_name, 8) ) { ptr = ehdrC + shdr[i].sh_offset; break; @@ -1735,7 +1737,7 @@ ocVerifyImage_ELF ( ObjectCode* oc ) && i != ehdr->e_shstrndx /* Ignore string tables named .stabstr, as they contain debugging info. */ - && 0 != strcmp(".stabstr", sh_strtab + shdr[i].sh_name) + && 0 != strncmp(".stabstr", sh_strtab + shdr[i].sh_name, 8) ) { IF_DEBUG(linker,belch(" section %d is a normal string table", i )); strtab = ehdrC + shdr[i].sh_offset; @@ -1813,7 +1815,6 @@ ocGetNames_ELF ( ObjectCode* oc ) Elf32_Ehdr* ehdr = (Elf32_Ehdr*)ehdrC; char* strtab = findElfSection ( ehdrC, SHT_STRTAB ); Elf32_Shdr* shdr = (Elf32_Shdr*) (ehdrC + ehdr->e_shoff); - char* sh_strtab = ehdrC + shdr[ehdr->e_shstrndx].sh_offset; ASSERT(symhash != NULL); @@ -1824,19 +1825,39 @@ ocGetNames_ELF ( ObjectCode* oc ) k = 0; for (i = 0; i < ehdr->e_shnum; i++) { + /* 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]; + SectionKind kind = SECTIONKIND_OTHER; + int is_bss = FALSE; + + if (hdr.sh_type == SHT_PROGBITS + && (hdr.sh_flags & SHF_ALLOC) && (hdr.sh_flags & SHF_EXECINSTR)) { + /* .text-style section */ + kind = SECTIONKIND_CODE_OR_RODATA; + } + else + if (hdr.sh_type == SHT_PROGBITS + && (hdr.sh_flags & SHF_ALLOC) && (hdr.sh_flags & SHF_WRITE)) { + /* .data-style section */ + kind = SECTIONKIND_RWDATA; + } + else + if (hdr.sh_type == SHT_PROGBITS + && (hdr.sh_flags & SHF_ALLOC) && !(hdr.sh_flags & SHF_WRITE)) { + /* .rodata-style section */ + kind = SECTIONKIND_CODE_OR_RODATA; + } + else + if (hdr.sh_type == SHT_NOBITS + && (hdr.sh_flags & SHF_ALLOC) && (hdr.sh_flags & SHF_WRITE)) { + /* .bss-style section */ + kind = SECTIONKIND_RWDATA; + is_bss = TRUE; + } - /* 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(".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) { + if (is_bss && 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. */ @@ -1910,8 +1931,6 @@ 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_DEBUG(linker,belch( "addOTabName(LOCL): %10p %s %s", - ad, oc->fileName, nm )); isLocal = TRUE; } else { IF_DEBUG(linker,belch( "addOTabName(GLOB): %10p %s %s", @@ -1927,7 +1946,7 @@ ocGetNames_ELF ( ObjectCode* oc ) oc->symbols[j] = nm; /* Acquire! */ if (isLocal) { - ghciInsertStrHashTable(oc->fileName, oc->lochash, nm, ad); + /* Ignore entirely. */ } else { ghciInsertStrHashTable(oc->fileName, symhash, nm, ad); } @@ -1987,20 +2006,21 @@ do_Elf32_Rel_relocations ( ObjectCode* oc, char* ehdrC, IF_DEBUG(linker,belch( " ZERO" )); S = 0; } else { - /* First see if it is a nameless local symbol. */ - if (stab[ ELF32_R_SYM(info)].st_name == 0) { - symbol = "(noname)"; + Elf32_Sym sym = stab[ELF32_R_SYM(info)]; + /* First see if it is a local symbol. */ + if (ELF32_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) - (ehdrC + shdr[stab[ELF32_R_SYM(info)].st_shndx ].sh_offset + (ehdrC + shdr[ sym.st_shndx ].sh_offset + stab[ELF32_R_SYM(info)].st_value); - } else { - /* No? Should be in a symbol table then; first try the - local one. */ - symbol = strtab+stab[ ELF32_R_SYM(info)].st_name; - (void*)S = lookupLocalSymbol( oc, symbol ); - if ((void*)S == NULL) - (void*)S = lookupSymbol( symbol ); - } + + } else { + /* No, so look up the name in our global table. */ + symbol = strtab + sym.st_name; + (void*)S = lookupSymbol( symbol ); + } if (!S) { belch("%s: unknown symbol `%s'", oc->fileName, symbol); return 0; @@ -2049,7 +2069,7 @@ do_Elf32_Rela_relocations ( ObjectCode* oc, char* ehdrC, 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 A = addend; /* Do not delete this; it is used on sparc. */ Elf32_Addr S; # if defined(sparc_TARGET_ARCH) /* This #ifdef only serves to avoid unused-var warnings. */ @@ -2064,20 +2084,21 @@ do_Elf32_Rela_relocations ( ObjectCode* oc, char* ehdrC, IF_DEBUG(linker,belch( " ZERO" )); S = 0; } else { - /* First see if it is a nameless local symbol. */ - if (stab[ ELF32_R_SYM(info)].st_name == 0) { - symbol = "(noname)"; + Elf32_Sym sym = stab[ELF32_R_SYM(info)]; + /* First see if it is a local symbol. */ + if (ELF32_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) - (ehdrC + shdr[stab[ELF32_R_SYM(info)].st_shndx ].sh_offset + (ehdrC + shdr[ sym.st_shndx ].sh_offset + stab[ELF32_R_SYM(info)].st_value); - } else { - /* No? Should be in a symbol table then; first try the - local one. */ - symbol = strtab+stab[ ELF32_R_SYM(info)].st_name; - (void*)S = lookupLocalSymbol( oc, symbol ); - if ((void*)S == NULL) - (void*)S = lookupSymbol( symbol ); - } + + } else { + /* No, so look up the name in our global table. */ + symbol = strtab + sym.st_name; + (void*)S = lookupSymbol( symbol ); + } if (!S) { belch("%s: unknown symbol `%s'", oc->fileName, symbol); return 0; @@ -2170,7 +2191,7 @@ ocResolve_ELF ( ObjectCode* oc ) relocation entries that, when done, make the stabs debugging info point at the right places. We ain't interested in all dat jazz, mun. */ - if (0 == strcmp(".rel.stab", sh_strtab + shdr[shnum].sh_name)) + if (0 == strncmp(".rel.stab", sh_strtab + shdr[shnum].sh_name, 9)) continue; if (shdr[shnum].sh_type == SHT_REL ) {