]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/ld, cmd/6l, cmd/8l, cmd/5l: fix hidden/local symbol import for ELF systems
authorShenghou Ma <minux.ma@gmail.com>
Tue, 22 May 2012 18:32:27 +0000 (02:32 +0800)
committerShenghou Ma <minux.ma@gmail.com>
Tue, 22 May 2012 18:32:27 +0000 (02:32 +0800)
   Introduce a newsym() to cmd/lib.c to add a symbol but don't add
them to hash table.
   Introduce a new bit flag SHIDDEN and bit mask SMASK to handle hidden
and/or local symbols in ELF symbol tables. Though we still need to order
the symbol table entries correctly.
   Fix for issue 3261 comment #9.
   For CL 5822049.

R=iant, rsc
CC=golang-dev
https://golang.org/cl/5823055

src/cmd/5l/asm.c
src/cmd/5l/pass.c
src/cmd/6l/asm.c
src/cmd/6l/pass.c
src/cmd/8l/asm.c
src/cmd/8l/pass.c
src/cmd/ld/data.c
src/cmd/ld/ldelf.c
src/cmd/ld/lib.c
src/cmd/ld/lib.h
src/cmd/ld/symtab.c

index b4798b94677c2da0203dc77869c48e8cfcee5703..c8e50305c6153281dd727fc569f29d34a5e52674 100644 (file)
@@ -2203,7 +2203,7 @@ genasmsym(void (*put)(Sym*, char*, int, vlong, vlong, int, Sym*))
                for(s=hash[h]; s!=S; s=s->hash) {
                        if(s->hide)
                                continue;
-                       switch(s->type&~SSUB) {
+                       switch(s->type&SMASK) {
                        case SCONST:
                        case SRODATA:
                        case SDATA:
index cf6db8f0209a2ac75ddcea8fe23025ca9785dab9..34932fd4a0ad3d05789aa696fd65249b231b0b2a 100644 (file)
@@ -215,7 +215,7 @@ patch(void)
                                s = p->to.sym;
                                if(s->text == nil)
                                        continue;
-                               switch(s->type&~SSUB) {
+                               switch(s->type&SMASK) {
                                default:
                                        diag("undefined: %s", s->name);
                                        s->type = STEXT;
index ee31a05cdc2df796cf8271ba9fc39b955e784090..7939b10e30f248a9cab59cf0335efd6cc852fe29 100644 (file)
@@ -1167,7 +1167,7 @@ genasmsym(void (*put)(Sym*, char*, int, vlong, vlong, int, Sym*))
        for(s=allsym; s!=S; s=s->allsym) {
                if(s->hide)
                        continue;
-               switch(s->type&~SSUB) {
+               switch(s->type&SMASK) {
                case SCONST:
                case SRODATA:
                case SSYMTAB:
index c9b4776276bee30cf52583a8afb2aaf89fce4e95..9bc7d178b8029e277609d6d6d803a82662a9b092 100644 (file)
@@ -307,7 +307,7 @@ patch(void)
                        if(s) {
                                if(debug['c'])
                                        Bprint(&bso, "%s calls %s\n", TNAME, s->name);
-                               if((s->type&~SSUB) != STEXT) {
+                               if((s->type&SMASK) != STEXT) {
                                        /* diag prints TNAME first */
                                        diag("undefined: %s", s->name);
                                        s->type = STEXT;
index 25ffc786fc97e1fb12d9a15ccdbaf9cf2d8501ba..6c3a76e4d4e6122e6c684e578f5741c6e846b036 100644 (file)
@@ -1247,7 +1247,7 @@ genasmsym(void (*put)(Sym*, char*, int, vlong, vlong, int, Sym*))
                for(s=hash[h]; s!=S; s=s->hash) {
                        if(s->hide)
                                continue;
-                       switch(s->type&~SSUB) {
+                       switch(s->type&SMASK) {
                        case SCONST:
                        case SRODATA:
                        case SDATA:
index 9034fdf3a4bde08bbabe77245663d442d325ce69..c34a5568280672d83212e3a1e2a7a73cd2750242 100644 (file)
@@ -315,7 +315,7 @@ patch(void)
                                } else if(s) {
                                        if(debug['c'])
                                                Bprint(&bso, "%s calls %s\n", TNAME, s->name);
-                                       if((s->type&~SSUB) != STEXT) {
+                                       if((s->type&SMASK) != STEXT) {
                                                /* diag prints TNAME first */
                                                diag("undefined: %s", s->name);
                                                s->type = STEXT;
index ea7129781ef364029e3f34f8ce05e77b28f508f1..4eff24024e62a63f23a0b3c0eb5c4aaf9fe8b1f0 100644 (file)
@@ -159,7 +159,7 @@ relocsym(Sym *s)
                        diag("%s: invalid relocation %d+%d not in [%d,%d)", s->name, off, siz&~Rbig, 0, s->np);
                        continue;
                }
-               if(r->sym != S && (r->sym->type == 0 || r->sym->type == SXREF)) {
+               if(r->sym != S && (r->sym->type & SMASK == 0 || r->sym->type & SMASK == SXREF)) {
                        diag("%s: not defined", r->sym->name);
                        continue;
                }
index b64b5e5653d668cb3eeb70be625474225135ecb9..5100b3f4e3fa53b3f9a634aedca187fe027439c1 100644 (file)
@@ -308,7 +308,7 @@ uchar ElfMagic[4] = { 0x7F, 'E', 'L', 'F' };
 
 static ElfSect*        section(ElfObj*, char*);
 static int     map(ElfObj*, ElfSect*);
-static int     readsym(ElfObj*, int i, ElfSym*);
+static int     readsym(ElfObj*, int i, ElfSym*, int);
 static int     reltype(char*, int, uchar*);
 
 void
@@ -327,6 +327,9 @@ ldelf(Biobuf *f, char *pkg, int64 len, char *pn)
        Endian *e;
        Reloc *r, *rp;
        Sym *s;
+       Sym **symbols;
+
+       symbols = nil;
 
        USED(pkg);
        if(debug['v'])
@@ -547,7 +550,71 @@ ldelf(Biobuf *f, char *pkg, int64 len, char *pn)
                        etextp = s;
                }
                sect->sym = s;
-       }               
+       }
+
+       // enter sub-symbols into symbol table.
+       // symbol 0 is the null symbol.
+       symbols = malloc(obj->nsymtab * sizeof(symbols[0]));
+       if(symbols == nil) {
+               diag("out of memory");
+               errorexit();
+       }
+       for(i=1; i<obj->nsymtab; i++) {
+               if(readsym(obj, i, &sym, 1) < 0)
+                       goto bad;
+               symbols[i] = sym.sym;
+               if(sym.type != ElfSymTypeFunc && sym.type != ElfSymTypeObject && sym.type != ElfSymTypeNone)
+                       continue;
+               if(sym.shndx == ElfSymShnCommon) {
+                       s = sym.sym;
+                       if(s->size < sym.size)
+                               s->size = sym.size;
+                       if(s->type == 0 || s->type == SXREF)
+                               s->type = SBSS;
+                       continue;
+               }
+               if(sym.shndx >= obj->nsect || sym.shndx == 0)
+                       continue;
+               sect = obj->sect+sym.shndx;
+               if(sect->sym == nil) {
+                       diag("%s: sym#%d: ignoring %s in section %d (type %d)", pn, i, sym.name, sym.shndx, sym.type);
+                       continue;
+               }
+               s = sym.sym;
+               s->sub = sect->sym->sub;
+               sect->sym->sub = s;
+               s->type = sect->sym->type | (s->type&~SMASK) | SSUB;
+               if(!s->dynexport) {
+                       s->dynimplib = nil;  // satisfy dynimport
+                       s->dynimpname = nil;  // satisfy dynimport
+               }
+               s->value = sym.value;
+               s->size = sym.size;
+               s->outer = sect->sym;
+               if(sect->sym->type == STEXT) {
+                       Prog *p;
+
+                       if(s->text != P) {
+                               if(!s->dupok)
+                                       diag("%s: duplicate definition of %s", pn, s->name);
+                       } else {
+                               // build a TEXT instruction with a unique pc
+                               // just to make the rest of the linker happy.
+                               p = prg();
+                               p->as = ATEXT;
+                               p->from.type = D_EXTERN;
+                               p->from.sym = s;
+                               p->textflag = 7;
+                               p->to.type = D_CONST;
+                               p->link = nil;
+                               p->pc = pc++;
+                               s->text = p;
+
+                               etextp->next = s;
+                               etextp = s;
+                       }
+               }
+       }
 
        // load relocations
        for(i=0; i<obj->nsect; i++) {
@@ -591,8 +658,9 @@ ldelf(Biobuf *f, char *pkg, int64 len, char *pn)
                        if((info >> 32) == 0) { // absolute relocation, don't bother reading the null symbol
                                rp->sym = S;
                        } else {
-                               if(readsym(obj, info>>32, &sym) < 0)
+                               if(readsym(obj, info>>32, &sym, 0) < 0)
                                        goto bad;
+                               sym.sym = symbols[info>>32];
                                if(sym.sym == nil) {
                                        werrstr("%s#%d: reloc of invalid sym #%d %s shndx=%d type=%d",
                                                sect->sym->name, j, (int)(info>>32), sym.name, sym.shndx, sym.type);
@@ -619,67 +687,13 @@ ldelf(Biobuf *f, char *pkg, int64 len, char *pn)
                s->r = r;
                s->nr = n;
        }
+       free(symbols);
 
-       // enter sub-symbols into symbol table.
-       // symbol 0 is the null symbol.
-       for(i=1; i<obj->nsymtab; i++) {
-               if(readsym(obj, i, &sym) < 0)
-                       goto bad;
-               if(sym.type != ElfSymTypeFunc && sym.type != ElfSymTypeObject && sym.type != ElfSymTypeNone)
-                       continue;
-               if(sym.shndx == ElfSymShnCommon) {
-                       s = sym.sym;
-                       if(s->size < sym.size)
-                               s->size = sym.size;
-                       if(s->type == 0 || s->type == SXREF)
-                               s->type = SBSS;
-                       continue;
-               }
-               if(sym.shndx >= obj->nsect || sym.shndx == 0)
-                       continue;
-               if(thechar == '5' && (strcmp(sym.name, "$a") == 0 || strcmp(sym.name, "$d") == 0)) // binutils for arm generate these mapping symbols, skip these
-                       continue;
-               sect = obj->sect+sym.shndx;
-               if(sect->sym == nil) {
-                       diag("%s: sym#%d: ignoring %s in section %d (type %d)", pn, i, sym.name, sym.shndx, sym.type);
-                       continue;
-               }
-               s = sym.sym;
-               s->sub = sect->sym->sub;
-               sect->sym->sub = s;
-               s->type = sect->sym->type | SSUB;
-               if(!s->dynexport) {
-                       s->dynimplib = nil;  // satisfy dynimport
-                       s->dynimpname = nil;  // satisfy dynimport
-               }
-               s->value = sym.value;
-               s->size = sym.size;
-               s->outer = sect->sym;
-               if(sect->sym->type == STEXT) {
-                       Prog *p;
-
-                       if(s->text != P)
-                               diag("%s: duplicate definition of %s", pn, s->name);
-                       // build a TEXT instruction with a unique pc
-                       // just to make the rest of the linker happy.
-                       p = prg();
-                       p->as = ATEXT;
-                       p->from.type = D_EXTERN;
-                       p->from.sym = s;
-                       p->textflag = 7;
-                       p->to.type = D_CONST;
-                       p->link = nil;
-                       p->pc = pc++;
-                       s->text = p;
-
-                       etextp->next = s;
-                       etextp = s;
-               }
-       }
        return;
 
 bad:
        diag("%s: malformed elf file: %r", pn);
+       free(symbols);
 }
 
 static ElfSect*
@@ -713,7 +727,7 @@ map(ElfObj *obj, ElfSect *sect)
 }
 
 static int
-readsym(ElfObj *obj, int i, ElfSym *sym)
+readsym(ElfObj *obj, int i, ElfSym *sym, int needSym)
 {
        Sym *s;
 
@@ -752,8 +766,6 @@ readsym(ElfObj *obj, int i, ElfSym *sym)
        s = nil;
        if(strcmp(sym->name, "_GLOBAL_OFFSET_TABLE_") == 0)
                sym->name = ".got";
-       if(strcmp(sym->name, "__stack_chk_fail_local") == 0)
-               sym->other = 0;  // rewrite hidden -> default visibility
        switch(sym->type) {
        case ElfSymTypeSection:
                s = obj->sect[sym->shndx].sym;
@@ -763,14 +775,30 @@ readsym(ElfObj *obj, int i, ElfSym *sym)
        case ElfSymTypeNone:
                switch(sym->bind) {
                case ElfSymBindGlobal:
-                       if(sym->other != 2) {
+                       if(needSym) {
                                s = lookup(sym->name, 0);
-                               break;
+                               // for global scoped hidden symbols we should insert it into
+                               // symbol hash table, but mark them as hidden.
+                               // __i686.get_pc_thunk.bx is allowed to be duplicated, to
+                               // workaround that we set dupok.
+                               // TODO(minux): correctly handle __i686.get_pc_thunk.bx without
+                               // set dupok generally. See http://codereview.appspot.com/5823055/
+                               // comment #5 for details.
+                               if(s && sym->other == 2) {
+                                       s->type = SHIDDEN;
+                                       s->dupok = 1;
+                               }
                        }
-                       // fall through
+                       break;
                case ElfSymBindLocal:
                        if(!(thechar == '5' && (strcmp(sym->name, "$a") == 0 || strcmp(sym->name, "$d") == 0))) // binutils for arm generate these mapping symbols, ignore these
-                               s = lookup(sym->name, version);
+                               if(needSym) {
+                                       // local names and hidden visiblity global names are unique
+                                       // and should only reference by its index, not name, so we
+                                       // don't bother to add them into hash table
+                                       s = newsym(sym->name, version);
+                                       s->type = SHIDDEN;
+                               }
                        break;
                default:
                        werrstr("%s: invalid symbol binding %d", sym->name, sym->bind);
index 4a100cac3a1e48a514347a00e662572c8990b24b..2385809dbf0dcf7a54a90e431e38e2fc8bc37e8f 100644 (file)
@@ -548,6 +548,36 @@ eof:
        free(pn);
 }
 
+Sym*
+newsym(char *symb, int v)
+{
+       Sym *s;
+       int l;
+
+       l = strlen(symb) + 1;
+       s = mal(sizeof(*s));
+       if(debug['v'] > 1)
+               Bprint(&bso, "newsym %s\n", symb);
+
+       s->dynid = -1;
+       s->plt = -1;
+       s->got = -1;
+       s->name = mal(l + 1);
+       memmove(s->name, symb, l);
+
+       s->type = 0;
+       s->version = v;
+       s->value = 0;
+       s->sig = 0;
+       s->size = 0;
+       nsymbol++;
+
+       s->allsym = allsym;
+       allsym = s;
+
+       return s;
+}
+
 static Sym*
 _lookup(char *symb, int v, int creat)
 {
@@ -569,27 +599,10 @@ _lookup(char *symb, int v, int creat)
        if(!creat)
                return nil;
 
-       s = mal(sizeof(*s));
-       if(debug['v'] > 1)
-               Bprint(&bso, "lookup %s\n", symb);
-
-       s->dynid = -1;
-       s->plt = -1;
-       s->got = -1;
-       s->name = mal(l + 1);
-       memmove(s->name, symb, l);
-
+       s = newsym(symb, v);
        s->hash = hash[h];
-       s->type = 0;
-       s->version = v;
-       s->value = 0;
-       s->sig = 0;
-       s->size = 0;
        hash[h] = s;
-       nsymbol++;
 
-       s->allsym = allsym;
-       allsym = s;
        return s;
 }
 
index 02dac6e1c89b3914aca5e05a5139b45e4a6706c1..25c0b3709d7c2871732dee1e827158dfe2461da0 100644 (file)
@@ -61,7 +61,9 @@ enum
        SDYNIMPORT,
 
        SSUB = 1<<8,    /* sub-symbol, linked from parent via ->sub list */
-       
+       SMASK = SSUB - 1,
+       SHIDDEN = 1<<9, // hidden or local symbol
+
        NHASH = 100003,
 };
 
@@ -142,6 +144,7 @@ void        addhist(int32 line, int type);
 void   asmlc(void);
 void   histtoauto(void);
 void   collapsefrog(Sym *s);
+Sym*   newsym(char *symb, int v);
 Sym*   lookup(char *symb, int v);
 Sym*   rlookup(char *symb, int v);
 void   nuxiinit(void);
index 129b13ea088a56e283c99e9fdfc1857fd1241bf3..359a658e74e719368999cd9ff1a9adbca27e590a 100644 (file)
@@ -36,7 +36,7 @@
 
 static int maxelfstr;
 
-int
+static int
 putelfstr(char *s)
 {
        int off, n;
@@ -57,14 +57,14 @@ putelfstr(char *s)
        return off;
 }
 
-void
-putelfsyment(int off, vlong addr, vlong size, int info, int shndx)
+static void
+putelfsyment(int off, vlong addr, vlong size, int info, int shndx, int other)
 {
        switch(thechar) {
        case '6':
                LPUT(off);
                cput(info);
-               cput(0);
+               cput(other);
                WPUT(shndx);
                VPUT(addr);
                VPUT(size);
@@ -75,14 +75,14 @@ putelfsyment(int off, vlong addr, vlong size, int info, int shndx)
                LPUT(addr);
                LPUT(size);
                cput(info);
-               cput(0);
+               cput(other);
                WPUT(shndx);
                symsize += ELF32SYMSIZE;
                break;
        }
 }
 
-void
+static void
 putelfsym(Sym *x, char *s, int t, vlong addr, vlong size, int ver, Sym *go)
 {
        int bind, type, shndx, off;
@@ -97,7 +97,7 @@ putelfsym(Sym *x, char *s, int t, vlong addr, vlong size, int ver, Sym *go)
                break;
        case 'D':
                type = STT_OBJECT;
-               if((x->type&~SSUB) == SRODATA)
+               if((x->type&SMASK) == SRODATA)
                        shndx = elftextsh + 1;
                else
                        shndx = elftextsh + 2;
@@ -107,20 +107,22 @@ putelfsym(Sym *x, char *s, int t, vlong addr, vlong size, int ver, Sym *go)
                shndx = elftextsh + 3;
                break;
        }
-       bind = ver ? STB_LOCAL : STB_GLOBAL;
+       // TODO(minux): we need to place all STB_LOCAL precede all STB_GLOBAL and
+       // STB_WEAK symbols in the symbol table
+       bind = (ver || (x->type & SHIDDEN)) ? STB_LOCAL : STB_GLOBAL;
        off = putelfstr(s);
-       putelfsyment(off, addr, size, (bind<<4)|(type&0xf), shndx);
+       putelfsyment(off, addr, size, (bind<<4)|(type&0xf), shndx, (x->type & SHIDDEN) ? 2 : 0);
 }
 
 void
 asmelfsym(void)
 {
        // the first symbol entry is reserved
-       putelfsyment(0, 0, 0, (STB_LOCAL<<4)|STT_NOTYPE, 0);
+       putelfsyment(0, 0, 0, (STB_LOCAL<<4)|STT_NOTYPE, 0, 0);
        genasmsym(putelfsym);
 }
 
-void
+static void
 putplan9sym(Sym *x, char *s, int t, vlong addr, vlong size, int ver, Sym *go)
 {
        int i;