diff options
Diffstat (limited to 'src/cmd/ld')
-rw-r--r-- | src/cmd/ld/data.c | 970 | ||||
-rw-r--r-- | src/cmd/ld/doc.go | 11 | ||||
-rw-r--r-- | src/cmd/ld/dwarf.c | 2598 | ||||
-rw-r--r-- | src/cmd/ld/dwarf.h | 30 | ||||
-rw-r--r-- | src/cmd/ld/dwarf_defs.h | 503 | ||||
-rw-r--r-- | src/cmd/ld/elf.c | 558 | ||||
-rw-r--r-- | src/cmd/ld/elf.h | 989 | ||||
-rw-r--r-- | src/cmd/ld/go.c | 710 | ||||
-rw-r--r-- | src/cmd/ld/ldelf.c | 816 | ||||
-rw-r--r-- | src/cmd/ld/ldmacho.c | 821 | ||||
-rw-r--r-- | src/cmd/ld/ldpe.c | 415 | ||||
-rw-r--r-- | src/cmd/ld/lib.c | 1361 | ||||
-rw-r--r-- | src/cmd/ld/lib.h | 281 | ||||
-rw-r--r-- | src/cmd/ld/macho.c | 518 | ||||
-rw-r--r-- | src/cmd/ld/macho.h | 94 | ||||
-rw-r--r-- | src/cmd/ld/pe.c | 583 | ||||
-rw-r--r-- | src/cmd/ld/pe.h | 179 | ||||
-rw-r--r-- | src/cmd/ld/symtab.c | 378 |
18 files changed, 0 insertions, 11815 deletions
diff --git a/src/cmd/ld/data.c b/src/cmd/ld/data.c deleted file mode 100644 index f1132fc8b..000000000 --- a/src/cmd/ld/data.c +++ /dev/null @@ -1,970 +0,0 @@ -// Inferno utils/8l/asm.c -// http://code.google.com/p/inferno-os/source/browse/utils/8l/asm.c -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -// Data layout and relocation. - -#include "l.h" -#include "../ld/lib.h" -#include "../ld/elf.h" -#include "../ld/pe.h" - -void dynreloc(void); - -/* - * divide-and-conquer list-link - * sort of Sym* structures. - * Used for the data block. - */ -int -datcmp(Sym *s1, Sym *s2) -{ - if(s1->type != s2->type) - return (int)s1->type - (int)s2->type; - if(s1->size != s2->size) { - if(s1->size < s2->size) - return -1; - return +1; - } - return strcmp(s1->name, s2->name); -} - -Sym* -datsort(Sym *l) -{ - Sym *l1, *l2, *le; - - if(l == 0 || l->next == 0) - return l; - - l1 = l; - l2 = l; - for(;;) { - l2 = l2->next; - if(l2 == 0) - break; - l2 = l2->next; - if(l2 == 0) - break; - l1 = l1->next; - } - - l2 = l1->next; - l1->next = 0; - l1 = datsort(l); - l2 = datsort(l2); - - /* set up lead element */ - if(datcmp(l1, l2) < 0) { - l = l1; - l1 = l1->next; - } else { - l = l2; - l2 = l2->next; - } - le = l; - - for(;;) { - if(l1 == 0) { - while(l2) { - le->next = l2; - le = l2; - l2 = l2->next; - } - le->next = 0; - break; - } - if(l2 == 0) { - while(l1) { - le->next = l1; - le = l1; - l1 = l1->next; - } - break; - } - if(datcmp(l1, l2) < 0) { - le->next = l1; - le = l1; - l1 = l1->next; - } else { - le->next = l2; - le = l2; - l2 = l2->next; - } - } - le->next = 0; - return l; -} - -Reloc* -addrel(Sym *s) -{ - if(s->nr >= s->maxr) { - if(s->maxr == 0) - s->maxr = 4; - else - s->maxr <<= 1; - s->r = realloc(s->r, s->maxr*sizeof s->r[0]); - if(s->r == 0) { - diag("out of memory"); - errorexit(); - } - memset(s->r+s->nr, 0, (s->maxr-s->nr)*sizeof s->r[0]); - } - return &s->r[s->nr++]; -} - -void -relocsym(Sym *s) -{ - Reloc *r; - Prog p; - int32 i, off, siz, fl; - vlong o; - uchar *cast; - - cursym = s; - memset(&p, 0, sizeof p); - for(r=s->r; r<s->r+s->nr; r++) { - off = r->off; - siz = r->siz; - if(off < 0 || off+(siz&~Rbig) > s->np) { - 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)) { - diag("%s: not defined", r->sym->name); - continue; - } - if(r->type >= 256) - continue; - - if(r->sym != S && r->sym->type == SDYNIMPORT) - diag("unhandled relocation for %s (type %d rtype %d)", r->sym->name, r->sym->type, r->type); - - if(r->sym != S && !r->sym->reachable) - diag("unreachable sym in relocation: %s %s", s->name, r->sym->name); - - switch(r->type) { - default: - o = 0; - if(archreloc(r, s, &o) < 0) - diag("unknown reloc %d", r->type); - break; - case D_ADDR: - o = symaddr(r->sym) + r->add; - break; - case D_PCREL: - o = symaddr(r->sym) + r->add - (s->value + r->off + r->siz); - break; - case D_SIZE: - o = r->sym->size + r->add; - break; - } -//print("relocate %s %p %s => %p %p %p %p [%p]\n", s->name, s->value+off, r->sym ? r->sym->name : "<nil>", (void*)symaddr(r->sym), (void*)s->value, (void*)r->off, (void*)r->siz, (void*)o); - switch(siz) { - default: - cursym = s; - diag("bad reloc size %#ux for %s", siz, r->sym->name); - case 4 + Rbig: - fl = o; - s->p[off] = fl>>24; - s->p[off+1] = fl>>16; - s->p[off+2] = fl>>8; - s->p[off+3] = fl; - break; - case 4 + Rlittle: - fl = o; - s->p[off] = fl; - s->p[off+1] = fl>>8; - s->p[off+2] = fl>>16; - s->p[off+3] = fl>>24; - break; - case 4: - fl = o; - cast = (uchar*)&fl; - for(i=0; i<4; i++) - s->p[off+i] = cast[inuxi4[i]]; - break; - case 8: - cast = (uchar*)&o; - for(i=0; i<8; i++) - s->p[off+i] = cast[inuxi8[i]]; - break; - } - } -} - -void -reloc(void) -{ - Sym *s; - - if(debug['v']) - Bprint(&bso, "%5.2f reloc\n", cputime()); - Bflush(&bso); - - for(s=textp; s!=S; s=s->next) - relocsym(s); - for(s=datap; s!=S; s=s->next) - relocsym(s); -} - -void -dynrelocsym(Sym *s) -{ - Reloc *r; - - if(HEADTYPE == Hwindows) { - Sym *rel, *targ; - - rel = lookup(".rel", 0); - if(s == rel) - return; - for(r=s->r; r<s->r+s->nr; r++) { - targ = r->sym; - if(r->sym->plt == -2 && r->sym->got != -2) { // make dynimport JMP table for PE object files. - targ->plt = rel->size; - r->sym = rel; - r->add = targ->plt; - - // jmp *addr - adduint8(rel, 0xff); - adduint8(rel, 0x25); - addaddr(rel, targ); - adduint8(rel, 0x90); - adduint8(rel, 0x90); - } else if(r->sym->plt >= 0) { - r->sym = rel; - r->add = targ->plt; - } - } - return; - } - - for(r=s->r; r<s->r+s->nr; r++) - if(r->sym->type == SDYNIMPORT || r->type >= 256) - adddynrel(s, r); -} - -void -dynreloc(void) -{ - Sym *s; - - // -d supresses dynamic loader format, so we may as well not - // compute these sections or mark their symbols as reachable. - if(debug['d'] && HEADTYPE != Hwindows) - return; - if(debug['v']) - Bprint(&bso, "%5.2f reloc\n", cputime()); - Bflush(&bso); - - for(s=textp; s!=S; s=s->next) - dynrelocsym(s); - for(s=datap; s!=S; s=s->next) - dynrelocsym(s); - if(iself) - elfdynhash(); -} - -void -symgrow(Sym *s, int32 siz) -{ - if(s->np >= siz) - return; - - if(s->maxp < siz) { - if(s->maxp == 0) - s->maxp = 8; - while(s->maxp < siz) - s->maxp <<= 1; - s->p = realloc(s->p, s->maxp); - if(s->p == nil) { - diag("out of memory"); - errorexit(); - } - memset(s->p+s->np, 0, s->maxp-s->np); - } - s->np = siz; -} - -void -savedata(Sym *s, Prog *p, char *pn) -{ - int32 off, siz, i, fl; - uchar *cast; - vlong o; - Reloc *r; - - off = p->from.offset; - siz = p->datasize; - if(off < 0 || siz < 0 || off >= 1<<30 || siz >= 100) - mangle(pn); - symgrow(s, off+siz); - - switch(p->to.type) { - default: - diag("bad data: %P", p); - break; - - case D_FCONST: - switch(siz) { - default: - case 4: - fl = ieeedtof(&p->to.ieee); - cast = (uchar*)&fl; - for(i=0; i<4; i++) - s->p[off+i] = cast[fnuxi4[i]]; - break; - case 8: - cast = (uchar*)&p->to.ieee; - for(i=0; i<8; i++) - s->p[off+i] = cast[fnuxi8[i]]; - break; - } - break; - - case D_SCONST: - for(i=0; i<siz; i++) - s->p[off+i] = p->to.scon[i]; - break; - - case D_CONST: - if(p->to.sym) - goto Addr; - o = p->to.offset; - fl = o; - cast = (uchar*)&fl; - switch(siz) { - default: - diag("bad nuxi %d\n%P", siz, p); - break; - case 1: - s->p[off] = cast[inuxi1[0]]; - break; - case 2: - for(i=0; i<2; i++) - s->p[off+i] = cast[inuxi2[i]]; - break; - case 4: - for(i=0; i<4; i++) - s->p[off+i] = cast[inuxi4[i]]; - break; - case 8: - cast = (uchar*)&o; - for(i=0; i<8; i++) - s->p[off+i] = cast[inuxi8[i]]; - break; - } - break; - - case D_ADDR: - case D_SIZE: - Addr: - r = addrel(s); - r->off = off; - r->siz = siz; - r->sym = p->to.sym; - r->type = p->to.type; - if(r->type != D_SIZE) - r->type = D_ADDR; - r->add = p->to.offset; - break; - } -} - -static void -blk(Sym *allsym, int32 addr, int32 size) -{ - Sym *sym; - int32 eaddr; - uchar *p, *ep; - - for(sym = allsym; sym != nil; sym = sym->next) - if(!(sym->type&SSUB) && sym->value >= addr) - break; - - eaddr = addr+size; - for(; sym != nil; sym = sym->next) { - if(sym->type&SSUB) - continue; - if(sym->value >= eaddr) - break; - if(sym->value < addr) { - diag("phase error: addr=%#llx but sym=%#llx type=%d", (vlong)addr, (vlong)sym->value, sym->type); - errorexit(); - } - cursym = sym; - for(; addr < sym->value; addr++) - cput(0); - p = sym->p; - ep = p + sym->np; - while(p < ep) - cput(*p++); - addr += sym->np; - for(; addr < sym->value+sym->size; addr++) - cput(0); - if(addr != sym->value+sym->size) { - diag("phase error: addr=%#llx value+size=%#llx", (vlong)addr, (vlong)sym->value+sym->size); - errorexit(); - } - } - - for(; addr < eaddr; addr++) - cput(0); - cflush(); -} - -void -codeblk(int32 addr, int32 size) -{ - Sym *sym; - int32 eaddr, n, epc; - Prog *p; - uchar *q; - - if(debug['a']) - Bprint(&bso, "codeblk [%#x,%#x) at offset %#llx\n", addr, addr+size, seek(cout, 0, 1)); - - blk(textp, addr, size); - - /* again for printing */ - if(!debug['a']) - return; - - for(sym = textp; sym != nil; sym = sym->next) { - if(!sym->reachable) - continue; - if(sym->value >= addr) - break; - } - - eaddr = addr + size; - for(; sym != nil; sym = sym->next) { - if(!sym->reachable) - continue; - if(sym->value >= eaddr) - break; - - if(addr < sym->value) { - Bprint(&bso, "%-20s %.8llux|", "_", (vlong)addr); - for(; addr < sym->value; addr++) - Bprint(&bso, " %.2ux", 0); - Bprint(&bso, "\n"); - } - p = sym->text; - if(p == nil) { - Bprint(&bso, "%.6llux\t%-20s | foreign text\n", (vlong)addr, sym->name); - n = sym->size; - q = sym->p; - - while(n >= 16) { - Bprint(&bso, "%.6ux\t%-20.16I\n", addr, q); - addr += 16; - q += 16; - n -= 16; - } - if(n > 0) - Bprint(&bso, "%.6ux\t%-20.*I\n", addr, (int)n, q); - addr += n; - continue; - } - - Bprint(&bso, "%.6llux\t%-20s | %P\n", (vlong)sym->value, sym->name, p); - for(p = p->link; p != P; p = p->link) { - if(p->link != P) - epc = p->link->pc; - else - epc = sym->value + sym->size; - Bprint(&bso, "%.6ux\t", p->pc); - q = sym->p + p->pc - sym->value; - n = epc - p->pc; - Bprint(&bso, "%-20.*I | %P\n", (int)n, q, p); - addr += n; - } - } - - if(addr < eaddr) { - Bprint(&bso, "%-20s %.8llux|", "_", (vlong)addr); - for(; addr < eaddr; addr++) - Bprint(&bso, " %.2ux", 0); - } - Bflush(&bso); -} - -void -datblk(int32 addr, int32 size) -{ - Sym *sym; - int32 eaddr; - uchar *p, *ep; - - if(debug['a']) - Bprint(&bso, "datblk [%#x,%#x) at offset %#llx\n", addr, addr+size, seek(cout, 0, 1)); - - blk(datap, addr, size); - - /* again for printing */ - if(!debug['a']) - return; - - for(sym = datap; sym != nil; sym = sym->next) - if(sym->value >= addr) - break; - - eaddr = addr + size; - for(; sym != nil; sym = sym->next) { - if(sym->value >= eaddr) - break; - if(addr < sym->value) { - Bprint(&bso, "%-20s %.8ux| 00 ...\n", "(pre-pad)", addr); - addr = sym->value; - } - Bprint(&bso, "%-20s %.8ux|", sym->name, (uint)addr); - p = sym->p; - ep = p + sym->np; - while(p < ep) - Bprint(&bso, " %.2ux", *p++); - addr += sym->np; - for(; addr < sym->value+sym->size; addr++) - Bprint(&bso, " %.2ux", 0); - Bprint(&bso, "\n"); - } - - if(addr < eaddr) - Bprint(&bso, "%-20s %.8ux| 00 ...\n", "(post-pad)", (uint)addr); - Bprint(&bso, "%-20s %.8ux|\n", "", (uint)eaddr); -} - -void -strnput(char *s, int n) -{ - for(; *s && n > 0; s++) { - cput(*s); - n--; - } - while(n > 0) { - cput(0); - n--; - } -} - -vlong -addstring(Sym *s, char *str) -{ - int n; - int32 r; - - if(s->type == 0) - s->type = SDATA; - s->reachable = 1; - r = s->size; - n = strlen(str)+1; - if(strcmp(s->name, ".shstrtab") == 0) - elfsetstring(str, r); - symgrow(s, r+n); - memmove(s->p+r, str, n); - s->size += n; - return r; -} - -vlong -adduintxx(Sym *s, uint64 v, int wid) -{ - int32 i, r, fl; - vlong o; - uchar *cast; - - if(s->type == 0) - s->type = SDATA; - s->reachable = 1; - r = s->size; - s->size += wid; - symgrow(s, s->size); - assert(r+wid <= s->size); - fl = v; - cast = (uchar*)&fl; - switch(wid) { - case 1: - s->p[r] = cast[inuxi1[0]]; - break; - case 2: - for(i=0; i<2; i++) - s->p[r+i] = cast[inuxi2[i]]; - break; - case 4: - for(i=0; i<4; i++) - s->p[r+i] = cast[inuxi4[i]]; - break; - case 8: - o = v; - cast = (uchar*)&o; - for(i=0; i<8; i++) - s->p[r+i] = cast[inuxi8[i]]; - break; - } - return r; -} - -vlong -adduint8(Sym *s, uint8 v) -{ - return adduintxx(s, v, 1); -} - -vlong -adduint16(Sym *s, uint16 v) -{ - return adduintxx(s, v, 2); -} - -vlong -adduint32(Sym *s, uint32 v) -{ - return adduintxx(s, v, 4); -} - -vlong -adduint64(Sym *s, uint64 v) -{ - return adduintxx(s, v, 8); -} - -vlong -addaddrplus(Sym *s, Sym *t, int32 add) -{ - vlong i; - Reloc *r; - - if(s->type == 0) - s->type = SDATA; - s->reachable = 1; - i = s->size; - s->size += PtrSize; - symgrow(s, s->size); - r = addrel(s); - r->sym = t; - r->off = i; - r->siz = PtrSize; - r->type = D_ADDR; - r->add = add; - return i; -} - -vlong -addpcrelplus(Sym *s, Sym *t, int32 add) -{ - vlong i; - Reloc *r; - - if(s->type == 0) - s->type = SDATA; - s->reachable = 1; - i = s->size; - s->size += 4; - symgrow(s, s->size); - r = addrel(s); - r->sym = t; - r->off = i; - r->add = add; - r->type = D_PCREL; - r->siz = 4; - return i; -} - -vlong -addaddr(Sym *s, Sym *t) -{ - return addaddrplus(s, t, 0); -} - -vlong -addsize(Sym *s, Sym *t) -{ - vlong i; - Reloc *r; - - if(s->type == 0) - s->type = SDATA; - s->reachable = 1; - i = s->size; - s->size += PtrSize; - symgrow(s, s->size); - r = addrel(s); - r->sym = t; - r->off = i; - r->siz = PtrSize; - r->type = D_SIZE; - return i; -} - -void -dodata(void) -{ - int32 t, datsize; - Section *sect; - Sym *s, *last, **l; - - if(debug['v']) - Bprint(&bso, "%5.2f dodata\n", cputime()); - Bflush(&bso); - - last = nil; - datap = nil; - - for(s=allsym; s!=S; s=s->allsym) { - if(!s->reachable || s->special) - continue; - if(STEXT < s->type && s->type < SXREF) { - if(last == nil) - datap = s; - else - last->next = s; - s->next = nil; - last = s; - } - } - - for(s = datap; s != nil; s = s->next) { - if(s->np > 0 && s->type == SBSS) - s->type = SDATA; - if(s->np > s->size) - diag("%s: initialize bounds (%lld < %d)", - s->name, (vlong)s->size, s->np); - } - - /* - * now that we have the datap list, but before we start - * to assign addresses, record all the necessary - * dynamic relocations. these will grow the relocation - * symbol, which is itself data. - */ - dynreloc(); - - /* some symbols may no longer belong in datap (Mach-O) */ - for(l=&datap; (s=*l) != nil; ) { - if(s->type <= STEXT || SXREF <= s->type) - *l = s->next; - else - l = &s->next; - } - *l = nil; - - datap = datsort(datap); - - /* - * allocate data sections. list is sorted by type, - * so we can just walk it for each piece we want to emit. - */ - - /* read-only data */ - sect = addsection(&segtext, ".rodata", 04); - sect->vaddr = 0; - datsize = 0; - s = datap; - for(; s != nil && s->type < SSYMTAB; s = s->next) { - s->type = SRODATA; - t = rnd(s->size, PtrSize); - s->value = datsize; - datsize += t; - } - sect->len = datsize - sect->vaddr; - - /* gosymtab */ - sect = addsection(&segtext, ".gosymtab", 04); - sect->vaddr = datsize; - for(; s != nil && s->type < SPCLNTAB; s = s->next) { - s->type = SRODATA; - s->value = datsize; - datsize += s->size; - } - sect->len = datsize - sect->vaddr; - - /* gopclntab */ - sect = addsection(&segtext, ".gopclntab", 04); - sect->vaddr = datsize; - for(; s != nil && s->type < SDATA; s = s->next) { - s->type = SRODATA; - s->value = datsize; - datsize += s->size; - } - sect->len = datsize - sect->vaddr; - - /* data */ - datsize = 0; - sect = addsection(&segdata, ".data", 06); - sect->vaddr = 0; - for(; s != nil && s->type < SBSS; s = s->next) { - s->type = SDATA; - t = s->size; - if(t == 0 && s->name[0] != '.') { - diag("%s: no size", s->name); - t = 1; - } - if(t >= PtrSize) - t = rnd(t, PtrSize); - else if(t > 2) - t = rnd(t, 4); - if(t & 1) { - ; - } else if(t & 2) - datsize = rnd(datsize, 2); - else if(t & 4) - datsize = rnd(datsize, 4); - else - datsize = rnd(datsize, 8); - s->value = datsize; - datsize += t; - } - sect->len = datsize - sect->vaddr; - - /* bss */ - sect = addsection(&segdata, ".bss", 06); - sect->vaddr = datsize; - for(; s != nil; s = s->next) { - if(s->type != SBSS) { - cursym = s; - diag("unexpected symbol type %d", s->type); - } - t = s->size; - if(t >= PtrSize) - t = rnd(t, PtrSize); - else if(t > 2) - t = rnd(t, 4); - if(t & 1) { - ; - } else if(t & 2) - datsize = rnd(datsize, 2); - else if(t & 4) - datsize = rnd(datsize, 4); - else - datsize = rnd(datsize, 8); - s->value = datsize; - datsize += t; - } - sect->len = datsize - sect->vaddr; -} - -// assign addresses to text -void -textaddress(void) -{ - uvlong va; - Prog *p; - Section *sect; - Sym *sym, *sub; - - addsection(&segtext, ".text", 05); - - // Assign PCs in text segment. - // Could parallelize, by assigning to text - // and then letting threads copy down, but probably not worth it. - sect = segtext.sect; - va = INITTEXT; - sect->vaddr = va; - for(sym = textp; sym != nil; sym = sym->next) { - if(sym->type & SSUB) - continue; - sym->value = 0; - for(sub = sym; sub != S; sub = sub->sub) { - sub->value += va; - for(p = sub->text; p != P; p = p->link) - p->pc += sub->value; - } - if(sym->size == 0 && sym->sub != S) { - cursym = sym; - } - va += sym->size; - } - sect->len = va - sect->vaddr; -} - -// assign addresses -void -address(void) -{ - Section *s, *text, *data, *rodata, *symtab, *pclntab; - Sym *sym, *sub; - uvlong va; - - va = INITTEXT; - segtext.rwx = 05; - segtext.vaddr = va; - segtext.fileoff = HEADR; - for(s=segtext.sect; s != nil; s=s->next) { - s->vaddr = va; - va += s->len; - segtext.len = va - INITTEXT; - va = rnd(va, INITRND); - } - segtext.filelen = segtext.len; - - segdata.rwx = 06; - segdata.vaddr = va; - segdata.fileoff = va - segtext.vaddr + segtext.fileoff; - if(HEADTYPE == Hwindows) - segdata.fileoff = segtext.fileoff + rnd(segtext.len, PEFILEALIGN); - if(HEADTYPE == Hplan9x32) - segdata.fileoff = segtext.fileoff + segtext.filelen; - for(s=segdata.sect; s != nil; s=s->next) { - s->vaddr = va; - va += s->len; - segdata.len = va - segdata.vaddr; - } - segdata.filelen = segdata.sect->len; // assume .data is first - - text = segtext.sect; - rodata = text->next; - symtab = rodata->next; - pclntab = symtab->next; - data = segdata.sect; - - for(sym = datap; sym != nil; sym = sym->next) { - cursym = sym; - if(sym->type < SDATA) - sym->value += rodata->vaddr; - else - sym->value += data->vaddr; - for(sub = sym->sub; sub != nil; sub = sub->sub) - sub->value += sym->value; - } - - xdefine("text", STEXT, text->vaddr); - xdefine("etext", STEXT, text->vaddr + text->len); - xdefine("rodata", SRODATA, rodata->vaddr); - xdefine("erodata", SRODATA, rodata->vaddr + rodata->len); - xdefine("symtab", SRODATA, symtab->vaddr); - xdefine("esymtab", SRODATA, symtab->vaddr + symtab->len); - xdefine("pclntab", SRODATA, pclntab->vaddr); - xdefine("epclntab", SRODATA, pclntab->vaddr + pclntab->len); - xdefine("data", SBSS, data->vaddr); - xdefine("edata", SBSS, data->vaddr + data->len); - xdefine("end", SBSS, segdata.vaddr + segdata.len); -} diff --git a/src/cmd/ld/doc.go b/src/cmd/ld/doc.go deleted file mode 100644 index 972e2a32c..000000000 --- a/src/cmd/ld/doc.go +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -/* - -This directory contains the portable section of the Plan 9 C linkers. -See ../6l, ../8l, and ../5l for more information. - -*/ -package documentation diff --git a/src/cmd/ld/dwarf.c b/src/cmd/ld/dwarf.c deleted file mode 100644 index 1c10dc796..000000000 --- a/src/cmd/ld/dwarf.c +++ /dev/null @@ -1,2598 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// TODO/NICETOHAVE: -// - eliminate DW_CLS_ if not used -// - package info in compilation units -// - assign global variables and types to their packages -// - gdb uses c syntax, meaning clumsy quoting is needed for go identifiers. eg -// ptype struct '[]uint8' and qualifiers need to be quoted away -// - lexical scoping is lost, so gdb gets confused as to which 'main.i' you mean. -// - file:line info for variables -// - make strings a typedef so prettyprinters can see the underlying string type -// -#include "l.h" -#include "lib.h" -#include "../ld/dwarf.h" -#include "../ld/dwarf_defs.h" -#include "../ld/elf.h" -#include "../ld/macho.h" -#include "../ld/pe.h" - -/* - * Offsets and sizes of the debug_* sections in the cout file. - */ - -static vlong abbrevo; -static vlong abbrevsize; -static vlong lineo; -static vlong linesize; -static vlong infoo; // also the base for DWDie->offs and reference attributes. -static vlong infosize; -static vlong frameo; -static vlong framesize; -static vlong pubnameso; -static vlong pubnamessize; -static vlong pubtypeso; -static vlong pubtypessize; -static vlong arangeso; -static vlong arangessize; -static vlong gdbscripto; -static vlong gdbscriptsize; - -static char gdbscript[1024]; - -/* - * Basic I/O - */ - -static void -addrput(vlong addr) -{ - switch(PtrSize) { - case 4: - LPUT(addr); - break; - case 8: - VPUT(addr); - break; - } -} - -static int -uleb128enc(uvlong v, char* dst) -{ - uint8 c, len; - - len = 0; - do { - c = v & 0x7f; - v >>= 7; - if (v) - c |= 0x80; - if (dst) - *dst++ = c; - len++; - } while (c & 0x80); - return len; -}; - -static int -sleb128enc(vlong v, char *dst) -{ - uint8 c, s, len; - - len = 0; - do { - c = v & 0x7f; - s = v & 0x40; - v >>= 7; - if ((v != -1 || !s) && (v != 0 || s)) - c |= 0x80; - if (dst) - *dst++ = c; - len++; - } while(c & 0x80); - return len; -} - -static void -uleb128put(vlong v) -{ - char buf[10]; - strnput(buf, uleb128enc(v, buf)); -} - -static void -sleb128put(vlong v) -{ - char buf[10]; - strnput(buf, sleb128enc(v, buf)); -} - -/* - * Defining Abbrevs. This is hardcoded, and there will be - * only a handful of them. The DWARF spec places no restriction on - * the ordering of atributes in the Abbrevs and DIEs, and we will - * always write them out in the order of declaration in the abbrev. - * This implementation relies on tag, attr < 127, so they serialize as - * a char. Higher numbered user-defined tags or attributes can be used - * for storing internal data but won't be serialized. - */ -typedef struct DWAttrForm DWAttrForm; -struct DWAttrForm { - uint8 attr; - uint8 form; -}; - -// Index into the abbrevs table below. -// Keep in sync with ispubname() and ispubtype() below. -// ispubtype considers >= NULLTYPE public -enum -{ - DW_ABRV_NULL, - DW_ABRV_COMPUNIT, - DW_ABRV_FUNCTION, - DW_ABRV_VARIABLE, - DW_ABRV_AUTO, - DW_ABRV_PARAM, - DW_ABRV_STRUCTFIELD, - DW_ABRV_FUNCTYPEPARAM, - DW_ABRV_DOTDOTDOT, - DW_ABRV_ARRAYRANGE, - DW_ABRV_NULLTYPE, - DW_ABRV_BASETYPE, - DW_ABRV_ARRAYTYPE, - DW_ABRV_CHANTYPE, - DW_ABRV_FUNCTYPE, - DW_ABRV_IFACETYPE, - DW_ABRV_MAPTYPE, - DW_ABRV_PTRTYPE, - DW_ABRV_SLICETYPE, - DW_ABRV_STRINGTYPE, - DW_ABRV_STRUCTTYPE, - DW_ABRV_TYPEDECL, - DW_NABRV -}; - -typedef struct DWAbbrev DWAbbrev; -static struct DWAbbrev { - uint8 tag; - uint8 children; - DWAttrForm attr[30]; -} abbrevs[DW_NABRV] = { - /* The mandatory DW_ABRV_NULL entry. */ - { 0 }, - /* COMPUNIT */ - { - DW_TAG_compile_unit, DW_CHILDREN_yes, - DW_AT_name, DW_FORM_string, - DW_AT_language, DW_FORM_data1, - DW_AT_low_pc, DW_FORM_addr, - DW_AT_high_pc, DW_FORM_addr, - DW_AT_stmt_list, DW_FORM_data4, - 0, 0 - }, - /* FUNCTION */ - { - DW_TAG_subprogram, DW_CHILDREN_yes, - DW_AT_name, DW_FORM_string, - DW_AT_low_pc, DW_FORM_addr, - DW_AT_high_pc, DW_FORM_addr, - DW_AT_external, DW_FORM_flag, - 0, 0 - }, - /* VARIABLE */ - { - DW_TAG_variable, DW_CHILDREN_no, - DW_AT_name, DW_FORM_string, - DW_AT_location, DW_FORM_block1, - DW_AT_type, DW_FORM_ref_addr, - DW_AT_external, DW_FORM_flag, - 0, 0 - }, - /* AUTO */ - { - DW_TAG_variable, DW_CHILDREN_no, - DW_AT_name, DW_FORM_string, - DW_AT_location, DW_FORM_block1, - DW_AT_type, DW_FORM_ref_addr, - 0, 0 - }, - /* PARAM */ - { - DW_TAG_formal_parameter, DW_CHILDREN_no, - DW_AT_name, DW_FORM_string, - DW_AT_location, DW_FORM_block1, - DW_AT_type, DW_FORM_ref_addr, - 0, 0 - }, - /* STRUCTFIELD */ - { - DW_TAG_member, DW_CHILDREN_no, - DW_AT_name, DW_FORM_string, - DW_AT_data_member_location, DW_FORM_block1, - DW_AT_type, DW_FORM_ref_addr, - 0, 0 - }, - /* FUNCTYPEPARAM */ - { - DW_TAG_formal_parameter, DW_CHILDREN_no, - // No name! - DW_AT_type, DW_FORM_ref_addr, - 0, 0 - }, - - /* DOTDOTDOT */ - { - DW_TAG_unspecified_parameters, DW_CHILDREN_no, - 0, 0 - }, - /* ARRAYRANGE */ - { - DW_TAG_subrange_type, DW_CHILDREN_no, - // No name! - DW_AT_type, DW_FORM_ref_addr, - DW_AT_upper_bound, DW_FORM_data1, - 0, 0 - }, - - // Below here are the types considered public by ispubtype - /* NULLTYPE */ - { - DW_TAG_unspecified_type, DW_CHILDREN_no, - DW_AT_name, DW_FORM_string, - 0, 0 - }, - /* BASETYPE */ - { - DW_TAG_base_type, DW_CHILDREN_no, - DW_AT_name, DW_FORM_string, - DW_AT_encoding, DW_FORM_data1, - DW_AT_byte_size, DW_FORM_data1, - 0, 0 - }, - /* ARRAYTYPE */ - // child is subrange with upper bound - { - DW_TAG_array_type, DW_CHILDREN_yes, - DW_AT_name, DW_FORM_string, - DW_AT_type, DW_FORM_ref_addr, - DW_AT_byte_size, DW_FORM_udata, - 0, 0 - }, - - /* CHANTYPE */ - { - DW_TAG_typedef, DW_CHILDREN_no, - DW_AT_name, DW_FORM_string, - DW_AT_type, DW_FORM_ref_addr, - 0, 0 - }, - - /* FUNCTYPE */ - { - DW_TAG_subroutine_type, DW_CHILDREN_yes, - DW_AT_name, DW_FORM_string, -// DW_AT_type, DW_FORM_ref_addr, - 0, 0 - }, - - /* IFACETYPE */ - { - DW_TAG_typedef, DW_CHILDREN_yes, - DW_AT_name, DW_FORM_string, - DW_AT_type, DW_FORM_ref_addr, - 0, 0 - }, - - /* MAPTYPE */ - { - DW_TAG_typedef, DW_CHILDREN_no, - DW_AT_name, DW_FORM_string, - DW_AT_type, DW_FORM_ref_addr, - 0, 0 - }, - - /* PTRTYPE */ - { - DW_TAG_pointer_type, DW_CHILDREN_no, - DW_AT_name, DW_FORM_string, - DW_AT_type, DW_FORM_ref_addr, - 0, 0 - }, - - /* SLICETYPE */ - { - DW_TAG_structure_type, DW_CHILDREN_yes, - DW_AT_name, DW_FORM_string, - DW_AT_byte_size, DW_FORM_udata, - 0, 0 - }, - - /* STRINGTYPE */ - { - DW_TAG_structure_type, DW_CHILDREN_yes, - DW_AT_name, DW_FORM_string, - DW_AT_byte_size, DW_FORM_udata, - 0, 0 - }, - - /* STRUCTTYPE */ - { - DW_TAG_structure_type, DW_CHILDREN_yes, - DW_AT_name, DW_FORM_string, - DW_AT_byte_size, DW_FORM_udata, - 0, 0 - }, - - /* TYPEDECL */ - { - DW_TAG_typedef, DW_CHILDREN_no, - DW_AT_name, DW_FORM_string, - DW_AT_type, DW_FORM_ref_addr, - 0, 0 - }, -}; - -static void -writeabbrev(void) -{ - int i, n; - - abbrevo = cpos(); - for (i = 1; i < DW_NABRV; i++) { - // See section 7.5.3 - uleb128put(i); - uleb128put(abbrevs[i].tag); - cput(abbrevs[i].children); - // 0 is not a valid attr or form, and DWAbbrev.attr is - // 0-terminated, so we can treat it as a string - n = strlen((char*)abbrevs[i].attr) / 2; - strnput((char*)abbrevs[i].attr, - (n+1) * sizeof(DWAttrForm)); - } - cput(0); - abbrevsize = cpos() - abbrevo; -} - -/* - * Debugging Information Entries and their attributes. - */ - -enum -{ - HASHSIZE = 107 -}; - -static uint32 -hashstr(char* s) -{ - uint32 h; - - h = 0; - while (*s) - h = h+h+h + *s++; - return h % HASHSIZE; -} - -// For DW_CLS_string and _block, value should contain the length, and -// data the data, for _reference, value is 0 and data is a DWDie* to -// the referenced instance, for all others, value is the whole thing -// and data is null. - -typedef struct DWAttr DWAttr; -struct DWAttr { - DWAttr *link; - uint8 atr; // DW_AT_ - uint8 cls; // DW_CLS_ - vlong value; - char *data; -}; - -typedef struct DWDie DWDie; -struct DWDie { - int abbrev; - DWDie *link; - DWDie *child; - DWAttr *attr; - // offset into .debug_info section, i.e relative to - // infoo. only valid after call to putdie() - vlong offs; - DWDie **hash; // optional index of children by name, enabled by mkindex() - DWDie *hlink; // bucket chain in parent's index -}; - -/* - * Root DIEs for compilation units, types and global variables. - */ - -static DWDie dwroot; -static DWDie dwtypes; -static DWDie dwglobals; - -static DWAttr* -newattr(DWDie *die, uint8 attr, int cls, vlong value, char *data) -{ - DWAttr *a; - - a = mal(sizeof *a); - a->link = die->attr; - die->attr = a; - a->atr = attr; - a->cls = cls; - a->value = value; - a->data = data; - return a; -} - -// Each DIE (except the root ones) has at least 1 attribute: its -// name. getattr moves the desired one to the front so -// frequently searched ones are found faster. -static DWAttr* -getattr(DWDie *die, uint8 attr) -{ - DWAttr *a, *b; - - if (die->attr->atr == attr) - return die->attr; - - a = die->attr; - b = a->link; - while (b != nil) { - if (b->atr == attr) { - a->link = b->link; - b->link = die->attr; - die->attr = b; - return b; - } - a = b; - b = b->link; - } - return nil; -} - -// Every DIE has at least a DW_AT_name attribute (but it will only be -// written out if it is listed in the abbrev). If its parent is -// keeping an index, the new DIE will be inserted there. -static DWDie* -newdie(DWDie *parent, int abbrev, char *name) -{ - DWDie *die; - int h; - - die = mal(sizeof *die); - die->abbrev = abbrev; - die->link = parent->child; - parent->child = die; - - newattr(die, DW_AT_name, DW_CLS_STRING, strlen(name), name); - - if (parent->hash) { - h = hashstr(name); - die->hlink = parent->hash[h]; - parent->hash[h] = die; - } - - return die; -} - -static void -mkindex(DWDie *die) -{ - die->hash = mal(HASHSIZE * sizeof(DWDie*)); -} - -// Find child by AT_name using hashtable if available or linear scan -// if not. -static DWDie* -find(DWDie *die, char* name) -{ - DWDie *a, *b; - int h; - - if (die->hash == nil) { - for (a = die->child; a != nil; a = a->link) - if (strcmp(name, getattr(a, DW_AT_name)->data) == 0) - return a; - return nil; - } - - h = hashstr(name); - a = die->hash[h]; - - if (a == nil) - return nil; - - - if (strcmp(name, getattr(a, DW_AT_name)->data) == 0) - return a; - - // Move found ones to head of the list. - b = a->hlink; - while (b != nil) { - if (strcmp(name, getattr(b, DW_AT_name)->data) == 0) { - a->hlink = b->hlink; - b->hlink = die->hash[h]; - die->hash[h] = b; - return b; - } - a = b; - b = b->hlink; - } - return nil; -} - -static DWDie* -find_or_diag(DWDie *die, char* name) -{ - DWDie *r; - r = find(die, name); - if (r == nil) { - diag("dwarf find: %s has no %s", getattr(die, DW_AT_name)->data, name); - errorexit(); - } - return r; -} - -static DWAttr* -newrefattr(DWDie *die, uint8 attr, DWDie* ref) -{ - if (ref == nil) - return nil; - return newattr(die, attr, DW_CLS_REFERENCE, 0, (char*)ref); -} - -static int fwdcount; - -static void -putattr(int form, int cls, vlong value, char *data) -{ - switch(form) { - case DW_FORM_addr: // address - addrput(value); - break; - - case DW_FORM_block1: // block - value &= 0xff; - cput(value); - while(value--) - cput(*data++); - break; - - case DW_FORM_block2: // block - value &= 0xffff; - WPUT(value); - while(value--) - cput(*data++); - break; - - case DW_FORM_block4: // block - value &= 0xffffffff; - LPUT(value); - while(value--) - cput(*data++); - break; - - case DW_FORM_block: // block - uleb128put(value); - while(value--) - cput(*data++); - break; - - case DW_FORM_data1: // constant - cput(value); - break; - - case DW_FORM_data2: // constant - WPUT(value); - break; - - case DW_FORM_data4: // constant, {line,loclist,mac,rangelist}ptr - LPUT(value); - break; - - case DW_FORM_data8: // constant, {line,loclist,mac,rangelist}ptr - VPUT(value); - break; - - case DW_FORM_sdata: // constant - sleb128put(value); - break; - - case DW_FORM_udata: // constant - uleb128put(value); - break; - - case DW_FORM_string: // string - strnput(data, value+1); - break; - - case DW_FORM_flag: // flag - cput(value?1:0); - break; - - case DW_FORM_ref_addr: // reference to a DIE in the .info section - if (data == nil) { - diag("dwarf: null reference"); - LPUT(0); // invalid dwarf, gdb will complain. - } else { - if (((DWDie*)data)->offs == 0) - fwdcount++; - LPUT(((DWDie*)data)->offs); - } - break; - - case DW_FORM_ref1: // reference within the compilation unit - case DW_FORM_ref2: // reference - case DW_FORM_ref4: // reference - case DW_FORM_ref8: // reference - case DW_FORM_ref_udata: // reference - - case DW_FORM_strp: // string - case DW_FORM_indirect: // (see Section 7.5.3) - default: - diag("dwarf: unsupported attribute form %d / class %d", form, cls); - errorexit(); - } -} - -// Note that we can (and do) add arbitrary attributes to a DIE, but -// only the ones actually listed in the Abbrev will be written out. -static void -putattrs(int abbrev, DWAttr* attr) -{ - DWAttr *attrs[DW_AT_recursive + 1]; - DWAttrForm* af; - - memset(attrs, 0, sizeof attrs); - for( ; attr; attr = attr->link) - if (attr->atr < nelem(attrs)) - attrs[attr->atr] = attr; - - for(af = abbrevs[abbrev].attr; af->attr; af++) - if (attrs[af->attr]) - putattr(af->form, - attrs[af->attr]->cls, - attrs[af->attr]->value, - attrs[af->attr]->data); - else - putattr(af->form, 0, 0, 0); -} - -static void putdie(DWDie* die); - -static void -putdies(DWDie* die) -{ - for(; die; die = die->link) - putdie(die); -} - -static void -putdie(DWDie* die) -{ - die->offs = cpos() - infoo; - uleb128put(die->abbrev); - putattrs(die->abbrev, die->attr); - if (abbrevs[die->abbrev].children) { - putdies(die->child); - cput(0); - } -} - -static void -reverselist(DWDie** list) -{ - DWDie *curr, *prev; - - curr = *list; - prev = nil; - while(curr != nil) { - DWDie* next = curr->link; - curr->link = prev; - prev = curr; - curr = next; - } - *list = prev; -} - -static void -reversetree(DWDie** list) -{ - DWDie *die; - - reverselist(list); - for (die = *list; die != nil; die = die->link) - if (abbrevs[die->abbrev].children) - reversetree(&die->child); -} - -static void -newmemberoffsetattr(DWDie *die, int32 offs) -{ - char block[10]; - int i; - - i = 0; - if (offs != 0) { - block[i++] = DW_OP_consts; - i += sleb128enc(offs, block+i); - block[i++] = DW_OP_plus; - } - newattr(die, DW_AT_data_member_location, DW_CLS_BLOCK, i, mal(i)); - memmove(die->attr->data, block, i); -} - -// GDB doesn't like DW_FORM_addr for DW_AT_location, so emit a -// location expression that evals to a const. -static void -newabslocexprattr(DWDie *die, vlong addr) -{ - char block[10]; - int i; - - i = 0; - block[i++] = DW_OP_constu; - i += uleb128enc(addr, block+i); - newattr(die, DW_AT_location, DW_CLS_BLOCK, i, mal(i)); - memmove(die->attr->data, block, i); -} - -// Decoding the type.* symbols. This has to be in sync with -// ../../pkg/runtime/type.go, or more specificaly, with what -// ../gc/reflect.c stuffs in these. - -enum { - KindBool = 1, - KindInt, - KindInt8, - KindInt16, - KindInt32, - KindInt64, - KindUint, - KindUint8, - KindUint16, - KindUint32, - KindUint64, - KindUintptr, - KindFloat32, - KindFloat64, - KindComplex64, - KindComplex128, - KindArray, - KindChan, - KindFunc, - KindInterface, - KindMap, - KindPtr, - KindSlice, - KindString, - KindStruct, - KindUnsafePointer, - - KindNoPointers = 1<<7, - - // size of Type interface header + CommonType structure. - CommonSize = 2*PtrSize+ 4*PtrSize + 8, -}; - -static Reloc* -decode_reloc(Sym *s, int32 off) -{ - int i; - - for (i = 0; i < s->nr; i++) - if (s->r[i].off == off) - return s->r + i; - return nil; -} - -static Sym* -decode_reloc_sym(Sym *s, int32 off) -{ - Reloc *r; - - r = decode_reloc(s,off); - if (r == nil) - return nil; - return r->sym; -} - -static uvlong -decode_inuxi(uchar* p, int sz) -{ - uint64 v; - uint32 l; - uchar *cast, *inuxi; - int i; - - v = l = 0; - cast = nil; - inuxi = nil; - switch (sz) { - case 2: - cast = (uchar*)&l; - inuxi = inuxi2; - break; - case 4: - cast = (uchar*)&l; - inuxi = inuxi4; - break; - case 8: - cast = (uchar*)&v; - inuxi = inuxi8; - break; - default: - diag("dwarf: decode inuxi %d", sz); - errorexit(); - } - for (i = 0; i < sz; i++) - cast[inuxi[i]] = p[i]; - if (sz == 8) - return v; - return l; -} - -// Type.commonType.kind -static uint8 -decodetype_kind(Sym *s) -{ - return s->p[3*PtrSize + 7] & ~KindNoPointers; // 0x13 / 0x1f -} - -// Type.commonType.size -static vlong -decodetype_size(Sym *s) -{ - return decode_inuxi(s->p + 2*PtrSize, PtrSize); // 0x8 / 0x10 -} - -// Type.ArrayType.elem and Type.SliceType.Elem -static Sym* -decodetype_arrayelem(Sym *s) -{ - return decode_reloc_sym(s, CommonSize); // 0x1c / 0x30 -} - -static vlong -decodetype_arraylen(Sym *s) -{ - return decode_inuxi(s->p + CommonSize+PtrSize, PtrSize); -} - -// Type.PtrType.elem -static Sym* -decodetype_ptrelem(Sym *s) -{ - return decode_reloc_sym(s, CommonSize); // 0x1c / 0x30 -} - -// Type.MapType.key, elem -static Sym* -decodetype_mapkey(Sym *s) -{ - return decode_reloc_sym(s, CommonSize); // 0x1c / 0x30 -} -static Sym* -decodetype_mapvalue(Sym *s) -{ - return decode_reloc_sym(s, CommonSize+PtrSize); // 0x20 / 0x38 -} - -// Type.ChanType.elem -static Sym* -decodetype_chanelem(Sym *s) -{ - return decode_reloc_sym(s, CommonSize); // 0x1c / 0x30 -} - -// Type.FuncType.dotdotdot -static int -decodetype_funcdotdotdot(Sym *s) -{ - return s->p[CommonSize]; -} - -// Type.FuncType.in.len -static int -decodetype_funcincount(Sym *s) -{ - return decode_inuxi(s->p + CommonSize+2*PtrSize, 4); -} - -static int -decodetype_funcoutcount(Sym *s) -{ - return decode_inuxi(s->p + CommonSize+3*PtrSize + 2*4, 4); -} - -static Sym* -decodetype_funcintype(Sym *s, int i) -{ - Reloc *r; - - r = decode_reloc(s, CommonSize + PtrSize); - if (r == nil) - return nil; - return decode_reloc_sym(r->sym, r->add + i * PtrSize); -} - -static Sym* -decodetype_funcouttype(Sym *s, int i) -{ - Reloc *r; - - r = decode_reloc(s, CommonSize + 2*PtrSize + 2*4); - if (r == nil) - return nil; - return decode_reloc_sym(r->sym, r->add + i * PtrSize); -} - -// Type.StructType.fields.Slice::len -static int -decodetype_structfieldcount(Sym *s) -{ - return decode_inuxi(s->p + CommonSize + PtrSize, 4); -} - -enum { - StructFieldSize = 5*PtrSize -}; -// Type.StructType.fields[]-> name, typ and offset. -static char* -decodetype_structfieldname(Sym *s, int i) -{ - Reloc *r; - - // go.string."foo" 0x28 / 0x40 - s = decode_reloc_sym(s, CommonSize + PtrSize + 2*4 + i*StructFieldSize); - if (s == nil) // embedded structs have a nil name. - return nil; - r = decode_reloc(s, 0); // s has a pointer to the string data at offset 0 - if (r == nil) // shouldn't happen. - return nil; - return (char*) r->sym->p + r->add; // the c-string -} - -static Sym* -decodetype_structfieldtype(Sym *s, int i) -{ - return decode_reloc_sym(s, CommonSize + PtrSize + 2*4 + i*StructFieldSize + 2*PtrSize); -} - -static vlong -decodetype_structfieldoffs(Sym *s, int i) -{ - return decode_inuxi(s->p + CommonSize + PtrSize + 2*4 + i*StructFieldSize + 4*PtrSize, 4); -} - -// InterfaceTYpe.methods.len -static vlong -decodetype_ifacemethodcount(Sym *s) -{ - return decode_inuxi(s->p + CommonSize + PtrSize, 4); -} - - -// Fake attributes for slices, maps and channel -enum { - DW_AT_internal_elem_type = 250, // channels and slices - DW_AT_internal_key_type = 251, // maps - DW_AT_internal_val_type = 252, // maps - DW_AT_internal_location = 253, // params and locals -}; - -static DWDie* defptrto(DWDie *dwtype); // below - -// Lookup predefined types -static Sym* -lookup_or_diag(char *n) -{ - Sym *s; - - s = rlookup(n, 0); - if (s == nil || s->size == 0) { - diag("dwarf: missing type: %s", n); - errorexit(); - } - return s; -} - -// Define gotype, for composite ones recurse into constituents. -static DWDie* -defgotype(Sym *gotype) -{ - DWDie *die, *fld; - Sym *s; - char *name, *f; - uint8 kind; - vlong bytesize; - int i, nfields; - - if (gotype == nil) - return find_or_diag(&dwtypes, "<unspecified>"); - - if (strncmp("type.", gotype->name, 5) != 0) { - diag("dwarf: type name doesn't start with \".type\": %s", gotype->name); - return find_or_diag(&dwtypes, "<unspecified>"); - } - name = gotype->name + 5; // could also decode from Type.string - - die = find(&dwtypes, name); - if (die != nil) - return die; - - if (0 && debug['v'] > 2) - print("new type: %Y\n", gotype); - - kind = decodetype_kind(gotype); - bytesize = decodetype_size(gotype); - - switch (kind) { - case KindBool: - die = newdie(&dwtypes, DW_ABRV_BASETYPE, name); - newattr(die, DW_AT_encoding, DW_CLS_CONSTANT, DW_ATE_boolean, 0); - newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0); - break; - - case KindInt: - case KindInt8: - case KindInt16: - case KindInt32: - case KindInt64: - die = newdie(&dwtypes, DW_ABRV_BASETYPE, name); - newattr(die, DW_AT_encoding, DW_CLS_CONSTANT, DW_ATE_signed, 0); - newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0); - break; - - case KindUint: - case KindUint8: - case KindUint16: - case KindUint32: - case KindUint64: - case KindUintptr: - die = newdie(&dwtypes, DW_ABRV_BASETYPE, name); - newattr(die, DW_AT_encoding, DW_CLS_CONSTANT, DW_ATE_unsigned, 0); - newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0); - break; - - case KindFloat32: - case KindFloat64: - die = newdie(&dwtypes, DW_ABRV_BASETYPE, name); - newattr(die, DW_AT_encoding, DW_CLS_CONSTANT, DW_ATE_float, 0); - newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0); - break; - - case KindComplex64: - case KindComplex128: - die = newdie(&dwtypes, DW_ABRV_BASETYPE, name); - newattr(die, DW_AT_encoding, DW_CLS_CONSTANT, DW_ATE_complex_float, 0); - newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0); - break; - - case KindArray: - die = newdie(&dwtypes, DW_ABRV_ARRAYTYPE, name); - newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0); - s = decodetype_arrayelem(gotype); - newrefattr(die, DW_AT_type, defgotype(s)); - fld = newdie(die, DW_ABRV_ARRAYRANGE, "range"); - newattr(fld, DW_AT_upper_bound, DW_CLS_CONSTANT, decodetype_arraylen(gotype), 0); - newrefattr(fld, DW_AT_type, find_or_diag(&dwtypes, "uintptr")); - break; - - case KindChan: - die = newdie(&dwtypes, DW_ABRV_CHANTYPE, name); - newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0); - s = decodetype_chanelem(gotype); - newrefattr(die, DW_AT_internal_elem_type, defgotype(s)); - break; - - case KindFunc: - die = newdie(&dwtypes, DW_ABRV_FUNCTYPE, name); - newrefattr(die, DW_AT_type, find_or_diag(&dwtypes, "void")); - nfields = decodetype_funcincount(gotype); - for (i = 0; i < nfields; i++) { - s = decodetype_funcintype(gotype, i); - fld = newdie(die, DW_ABRV_FUNCTYPEPARAM, s->name+5); - newrefattr(fld, DW_AT_type, defgotype(s)); - } - if (decodetype_funcdotdotdot(gotype)) - newdie(die, DW_ABRV_DOTDOTDOT, "..."); - nfields = decodetype_funcoutcount(gotype); - for (i = 0; i < nfields; i++) { - s = decodetype_funcouttype(gotype, i); - fld = newdie(die, DW_ABRV_FUNCTYPEPARAM, s->name+5); - newrefattr(fld, DW_AT_type, defptrto(defgotype(s))); - } - break; - - case KindInterface: - die = newdie(&dwtypes, DW_ABRV_IFACETYPE, name); - newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0); - nfields = decodetype_ifacemethodcount(gotype); - if (nfields == 0) - s = lookup_or_diag("type.runtime.eface"); - else - s = lookup_or_diag("type.runtime.iface"); - newrefattr(die, DW_AT_type, defgotype(s)); - break; - - case KindMap: - die = newdie(&dwtypes, DW_ABRV_MAPTYPE, name); - s = decodetype_mapkey(gotype); - newrefattr(die, DW_AT_internal_key_type, defgotype(s)); - s = decodetype_mapvalue(gotype); - newrefattr(die, DW_AT_internal_val_type, defgotype(s)); - break; - - case KindPtr: - die = newdie(&dwtypes, DW_ABRV_PTRTYPE, name); - s = decodetype_ptrelem(gotype); - newrefattr(die, DW_AT_type, defgotype(s)); - break; - - case KindSlice: - die = newdie(&dwtypes, DW_ABRV_SLICETYPE, name); - newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0); - s = decodetype_arrayelem(gotype); - newrefattr(die, DW_AT_internal_elem_type, defgotype(s)); - break; - - case KindString: - die = newdie(&dwtypes, DW_ABRV_STRINGTYPE, name); - newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0); - break; - - case KindStruct: - die = newdie(&dwtypes, DW_ABRV_STRUCTTYPE, name); - newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0); - nfields = decodetype_structfieldcount(gotype); - for (i = 0; i < nfields; i++) { - f = decodetype_structfieldname(gotype, i); - s = decodetype_structfieldtype(gotype, i); - if (f == nil) - f = s->name + 5; // skip "type." - fld = newdie(die, DW_ABRV_STRUCTFIELD, f); - newrefattr(fld, DW_AT_type, defgotype(s)); - newmemberoffsetattr(fld, decodetype_structfieldoffs(gotype, i)); - } - break; - - case KindUnsafePointer: - die = newdie(&dwtypes, DW_ABRV_PTRTYPE, name); - newrefattr(die, DW_AT_type, find(&dwtypes, "void")); - break; - - default: - diag("dwarf: definition of unknown kind %d: %s", kind, gotype->name); - die = newdie(&dwtypes, DW_ABRV_TYPEDECL, name); - newrefattr(die, DW_AT_type, find_or_diag(&dwtypes, "<unspecified>")); - } - - return die; -} - -// Find or construct *T given T. -static DWDie* -defptrto(DWDie *dwtype) -{ - char ptrname[1024]; - DWDie *die; - - snprint(ptrname, sizeof ptrname, "*%s", getattr(dwtype, DW_AT_name)->data); - die = find(&dwtypes, ptrname); - if (die == nil) { - die = newdie(&dwtypes, DW_ABRV_PTRTYPE, - strcpy(mal(strlen(ptrname)+1), ptrname)); - newrefattr(die, DW_AT_type, dwtype); - } - return die; -} - -// Copies src's children into dst. Copies attributes by value. -// DWAttr.data is copied as pointer only. -static void -copychildren(DWDie *dst, DWDie *src) -{ - DWDie *c; - DWAttr *a; - - for (src = src->child; src != nil; src = src->link) { - c = newdie(dst, src->abbrev, getattr(src, DW_AT_name)->data); - for (a = src->attr; a != nil; a = a->link) - newattr(c, a->atr, a->cls, a->value, a->data); - copychildren(c, src); - } - reverselist(&dst->child); -} - -// Search children (assumed to have DW_TAG_member) for the one named -// field and set it's DW_AT_type to dwtype -static void -substitutetype(DWDie *structdie, char *field, DWDie* dwtype) -{ - DWDie *child; - DWAttr *a; - - child = find_or_diag(structdie, field); - if (child == nil) - return; - - a = getattr(child, DW_AT_type); - if (a != nil) - a->data = (char*) dwtype; - else - newrefattr(child, DW_AT_type, dwtype); -} - -static void -synthesizestringtypes(DWDie* die) -{ - DWDie *prototype; - - prototype = defgotype(lookup_or_diag("type.runtime._string")); - if (prototype == nil) - return; - - for (; die != nil; die = die->link) { - if (die->abbrev != DW_ABRV_STRINGTYPE) - continue; - copychildren(die, prototype); - } -} - -static void -synthesizeslicetypes(DWDie *die) -{ - DWDie *prototype, *elem; - - prototype = defgotype(lookup_or_diag("type.runtime.slice")); - if (prototype == nil) - return; - - for (; die != nil; die = die->link) { - if (die->abbrev != DW_ABRV_SLICETYPE) - continue; - copychildren(die, prototype); - elem = (DWDie*) getattr(die, DW_AT_internal_elem_type)->data; - substitutetype(die, "array", defptrto(elem)); - } -} - -static char* -mkinternaltypename(char *base, char *arg1, char *arg2) -{ - char buf[1024]; - char *n; - - if (arg2 == nil) - snprint(buf, sizeof buf, "%s<%s>", base, arg1); - else - snprint(buf, sizeof buf, "%s<%s,%s>", base, arg1, arg2); - n = mal(strlen(buf) + 1); - memmove(n, buf, strlen(buf)); - return n; -} - - -// synthesizemaptypes is way too closely married to runtime/hashmap.c -enum { - MaxValsize = 256 - 64 -}; - -static void -synthesizemaptypes(DWDie *die) -{ - - DWDie *hash, *hash_subtable, *hash_entry, - *dwh, *dwhs, *dwhe, *dwhash, *keytype, *valtype, *fld; - int hashsize, keysize, valsize, datsize, valsize_in_hash, datavo; - DWAttr *a; - - hash = defgotype(lookup_or_diag("type.runtime.hmap")); - hash_subtable = defgotype(lookup_or_diag("type.runtime.hash_subtable")); - hash_entry = defgotype(lookup_or_diag("type.runtime.hash_entry")); - - if (hash == nil || hash_subtable == nil || hash_entry == nil) - return; - - dwhash = (DWDie*)getattr(find_or_diag(hash_entry, "hash"), DW_AT_type)->data; - if (dwhash == nil) - return; - - hashsize = getattr(dwhash, DW_AT_byte_size)->value; - - for (; die != nil; die = die->link) { - if (die->abbrev != DW_ABRV_MAPTYPE) - continue; - - keytype = (DWDie*) getattr(die, DW_AT_internal_key_type)->data; - valtype = (DWDie*) getattr(die, DW_AT_internal_val_type)->data; - - a = getattr(keytype, DW_AT_byte_size); - keysize = a ? a->value : PtrSize; // We don't store size with Pointers - - a = getattr(valtype, DW_AT_byte_size); - valsize = a ? a->value : PtrSize; - - // This is what happens in hash_init and makemap_c - valsize_in_hash = valsize; - if (valsize > MaxValsize) - valsize_in_hash = PtrSize; - datavo = keysize; - if (valsize_in_hash >= PtrSize) - datavo = rnd(keysize, PtrSize); - datsize = datavo + valsize_in_hash; - if (datsize < PtrSize) - datsize = PtrSize; - datsize = rnd(datsize, PtrSize); - - // Construct struct hash_entry<K,V> - dwhe = newdie(&dwtypes, DW_ABRV_STRUCTTYPE, - mkinternaltypename("hash_entry", - getattr(keytype, DW_AT_name)->data, - getattr(valtype, DW_AT_name)->data)); - - fld = newdie(dwhe, DW_ABRV_STRUCTFIELD, "hash"); - newrefattr(fld, DW_AT_type, dwhash); - newmemberoffsetattr(fld, 0); - - fld = newdie(dwhe, DW_ABRV_STRUCTFIELD, "key"); - newrefattr(fld, DW_AT_type, keytype); - newmemberoffsetattr(fld, hashsize); - - fld = newdie(dwhe, DW_ABRV_STRUCTFIELD, "val"); - if (valsize > MaxValsize) - valtype = defptrto(valtype); - newrefattr(fld, DW_AT_type, valtype); - newmemberoffsetattr(fld, hashsize + datavo); - newattr(dwhe, DW_AT_byte_size, DW_CLS_CONSTANT, hashsize + datsize, nil); - - // Construct hash_subtable<hash_entry<K,V>> - dwhs = newdie(&dwtypes, DW_ABRV_STRUCTTYPE, - mkinternaltypename("hash_subtable", - getattr(keytype, DW_AT_name)->data, - getattr(valtype, DW_AT_name)->data)); - copychildren(dwhs, hash_subtable); - substitutetype(dwhs, "end", defptrto(dwhe)); - substitutetype(dwhs, "entry", dwhe); // todo: []hash_entry with dynamic size - newattr(dwhs, DW_AT_byte_size, DW_CLS_CONSTANT, - getattr(hash_subtable, DW_AT_byte_size)->value, nil); - - // Construct hash<K,V> - dwh = newdie(&dwtypes, DW_ABRV_STRUCTTYPE, - mkinternaltypename("hash", - getattr(keytype, DW_AT_name)->data, - getattr(valtype, DW_AT_name)->data)); - copychildren(dwh, hash); - substitutetype(dwh, "st", defptrto(dwhs)); - newattr(dwh, DW_AT_byte_size, DW_CLS_CONSTANT, - getattr(hash, DW_AT_byte_size)->value, nil); - - newrefattr(die, DW_AT_type, defptrto(dwh)); - } -} - -static void -synthesizechantypes(DWDie *die) -{ - DWDie *sudog, *waitq, *hchan, - *dws, *dww, *dwh, *elemtype; - DWAttr *a; - int elemsize, sudogsize; - - sudog = defgotype(lookup_or_diag("type.runtime.sudog")); - waitq = defgotype(lookup_or_diag("type.runtime.waitq")); - hchan = defgotype(lookup_or_diag("type.runtime.hchan")); - if (sudog == nil || waitq == nil || hchan == nil) - return; - - sudogsize = getattr(sudog, DW_AT_byte_size)->value; - - for (; die != nil; die = die->link) { - if (die->abbrev != DW_ABRV_CHANTYPE) - continue; - elemtype = (DWDie*) getattr(die, DW_AT_internal_elem_type)->data; - a = getattr(elemtype, DW_AT_byte_size); - elemsize = a ? a->value : PtrSize; - - // sudog<T> - dws = newdie(&dwtypes, DW_ABRV_STRUCTTYPE, - mkinternaltypename("sudog", - getattr(elemtype, DW_AT_name)->data, nil)); - copychildren(dws, sudog); - substitutetype(dws, "elem", elemtype); - newattr(dws, DW_AT_byte_size, DW_CLS_CONSTANT, - sudogsize + (elemsize > 8 ? elemsize - 8 : 0), nil); - - // waitq<T> - dww = newdie(&dwtypes, DW_ABRV_STRUCTTYPE, - mkinternaltypename("waitq", getattr(elemtype, DW_AT_name)->data, nil)); - copychildren(dww, waitq); - substitutetype(dww, "first", defptrto(dws)); - substitutetype(dww, "last", defptrto(dws)); - newattr(dww, DW_AT_byte_size, DW_CLS_CONSTANT, - getattr(waitq, DW_AT_byte_size)->value, nil); - - // hchan<T> - dwh = newdie(&dwtypes, DW_ABRV_STRUCTTYPE, - mkinternaltypename("hchan", getattr(elemtype, DW_AT_name)->data, nil)); - copychildren(dwh, hchan); - substitutetype(dwh, "recvq", dww); - substitutetype(dwh, "sendq", dww); - substitutetype(dwh, "free", defptrto(dws)); - newattr(dwh, DW_AT_byte_size, DW_CLS_CONSTANT, - getattr(hchan, DW_AT_byte_size)->value, nil); - - newrefattr(die, DW_AT_type, defptrto(dwh)); - } -} - -// For use with pass.c::genasmsym -static void -defdwsymb(Sym* sym, char *s, int t, vlong v, vlong size, int ver, Sym *gotype) -{ - DWDie *dv, *dt; - - USED(size); - if (strncmp(s, "go.string.", 10) == 0) - return; - - if (strncmp(s, "type.", 5) == 0 && strcmp(s, "type.*") != 0) { - defgotype(sym); - return; - } - - dv = nil; - - switch (t) { - default: - return; - case 'd': - case 'b': - case 'D': - case 'B': - dv = newdie(&dwglobals, DW_ABRV_VARIABLE, s); - newabslocexprattr(dv, v); - if (ver == 0) - newattr(dv, DW_AT_external, DW_CLS_FLAG, 1, 0); - // fallthrough - case 'a': - case 'p': - dt = defgotype(gotype); - } - - if (dv != nil) - newrefattr(dv, DW_AT_type, dt); -} - -// TODO(lvd) For now, just append them all to the first compilation -// unit (that should be main), in the future distribute them to the -// appropriate compilation units. -static void -movetomodule(DWDie *parent) -{ - DWDie *die; - - for (die = dwroot.child->child; die->link != nil; die = die->link) /* nix */; - die->link = parent->child; -} - -/* - * Filename fragments for the line history stack. - */ - -static char **ftab; -static int ftabsize; - -void -dwarfaddfrag(int n, char *frag) -{ - int s; - - if (n >= ftabsize) { - s = ftabsize; - ftabsize = 1 + n + (n >> 2); - ftab = realloc(ftab, ftabsize * sizeof(ftab[0])); - memset(ftab + s, 0, (ftabsize - s) * sizeof(ftab[0])); - } - - if (*frag == '<') - frag++; - ftab[n] = frag; -} - -// Returns a malloc'ed string, piecewise copied from the ftab. -static char * -decodez(char *s) -{ - int len, o; - char *ss, *f; - char *r, *rb, *re; - - len = 0; - ss = s + 1; // first is 0 - while((o = ((uint8)ss[0] << 8) | (uint8)ss[1]) != 0) { - if (o < 0 || o >= ftabsize) { - diag("dwarf: corrupt z entry"); - return 0; - } - f = ftab[o]; - if (f == nil) { - diag("dwarf: corrupt z entry"); - return 0; - } - len += strlen(f) + 1; // for the '/' - ss += 2; - } - - if (len == 0) - return 0; - - r = malloc(len + 1); - rb = r; - re = rb + len + 1; - - s++; - while((o = ((uint8)s[0] << 8) | (uint8)s[1]) != 0) { - f = ftab[o]; - if (rb == r || rb[-1] == '/') - rb = seprint(rb, re, "%s", f); - else - rb = seprint(rb, re, "/%s", f); - s += 2; - } - return r; -} - -/* - * The line history itself - */ - -static char **histfile; // [0] holds "<eof>", DW_LNS_set_file arguments must be > 0. -static int histfilesize; -static int histfilecap; - -static void -clearhistfile(void) -{ - int i; - - // [0] holds "<eof>" - for (i = 1; i < histfilesize; i++) - free(histfile[i]); - histfilesize = 0; -} - -static int -addhistfile(char *zentry) -{ - char *fname; - - if (histfilesize == histfilecap) { - histfilecap = 2 * histfilecap + 2; - histfile = realloc(histfile, histfilecap * sizeof(char*)); - } - if (histfilesize == 0) - histfile[histfilesize++] = "<eof>"; - - fname = decodez(zentry); - if (fname == 0) - return -1; - // Don't fill with duplicates (check only top one). - if (strcmp(fname, histfile[histfilesize-1]) == 0) { - free(fname); - return histfilesize - 1; - } - histfile[histfilesize++] = fname; - return histfilesize - 1; -} - -// if the histfile stack contains ..../runtime/runtime_defs.go -// use that to set gdbscript -static void -finddebugruntimepath(void) -{ - int i, l; - char *c; - - for (i = 1; i < histfilesize; i++) { - if ((c = strstr(histfile[i], "runtime/runtime_defs.go")) != nil) { - l = c - histfile[i]; - memmove(gdbscript, histfile[i], l); - memmove(gdbscript + l, "runtime/runtime-gdb.py", strlen("runtime/runtime-gdb.py") + 1); - break; - } - } -} - -// Go's runtime C sources are sane, and Go sources nest only 1 level, -// so 16 should be plenty. -static struct { - int file; - vlong line; -} includestack[16]; -static int includetop; -static vlong absline; - -typedef struct Linehist Linehist; -struct Linehist { - Linehist *link; - vlong absline; - vlong line; - int file; -}; - -static Linehist *linehist; - -static void -checknesting(void) -{ - int i; - - if (includetop < 0) { - diag("dwarf: corrupt z stack"); - errorexit(); - } - if (includetop >= nelem(includestack)) { - diag("dwarf: nesting too deep"); - for (i = 0; i < nelem(includestack); i++) - diag("\t%s", histfile[includestack[i].file]); - errorexit(); - } -} - -/* - * Return false if the a->link chain contains no history, otherwise - * returns true and finds z and Z entries in the Auto list (of a - * Prog), and resets the history stack - */ -static int -inithist(Auto *a) -{ - Linehist *lh; - - for (; a; a = a->link) - if (a->type == D_FILE) - break; - if (a==nil) - return 0; - - // We have a new history. They are guaranteed to come completely - // at the beginning of the compilation unit. - if (a->aoffset != 1) { - diag("dwarf: stray 'z' with offset %d", a->aoffset); - return 0; - } - - // Clear the history. - clearhistfile(); - includetop = 0; - includestack[includetop].file = 0; - includestack[includetop].line = -1; - absline = 0; - while (linehist != nil) { - lh = linehist->link; - free(linehist); - linehist = lh; - } - - // Construct the new one. - for (; a; a = a->link) { - if (a->type == D_FILE) { // 'z' - int f = addhistfile(a->asym->name); - if (f < 0) { // pop file - includetop--; - checknesting(); - } else if(f != includestack[includetop].file) { // pushed a new file - includestack[includetop].line += a->aoffset - absline; - includetop++; - checknesting(); - includestack[includetop].file = f; - includestack[includetop].line = 1; - } - absline = a->aoffset; - } else if (a->type == D_FILE1) { // 'Z' - // We could just fixup the current - // linehist->line, but there doesn't appear to - // be a guarantee that every 'Z' is preceded - // by it's own 'z', so do the safe thing and - // update the stack and push a new Linehist - // entry - includestack[includetop].line = a->aoffset; - } else - continue; - if (linehist == 0 || linehist->absline != absline) { - Linehist* lh = malloc(sizeof *lh); - lh->link = linehist; - lh->absline = absline; - linehist = lh; - } - linehist->file = includestack[includetop].file; - linehist->line = includestack[includetop].line; - } - return 1; -} - -static Linehist * -searchhist(vlong absline) -{ - Linehist *lh; - - for (lh = linehist; lh; lh = lh->link) - if (lh->absline <= absline) - break; - return lh; -} - -static int -guesslang(char *s) -{ - if(strlen(s) >= 3 && strcmp(s+strlen(s)-3, ".go") == 0) - return DW_LANG_Go; - - return DW_LANG_C; -} - -/* - * Generate short opcodes when possible, long ones when neccesary. - * See section 6.2.5 - */ - -enum { - LINE_BASE = -1, - LINE_RANGE = 4, - OPCODE_BASE = 5 -}; - -static void -putpclcdelta(vlong delta_pc, vlong delta_lc) -{ - if (LINE_BASE <= delta_lc && delta_lc < LINE_BASE+LINE_RANGE) { - vlong opcode = OPCODE_BASE + (delta_lc - LINE_BASE) + (LINE_RANGE * delta_pc); - if (OPCODE_BASE <= opcode && opcode < 256) { - cput(opcode); - return; - } - } - - if (delta_pc) { - cput(DW_LNS_advance_pc); - sleb128put(delta_pc); - } - - cput(DW_LNS_advance_line); - sleb128put(delta_lc); - cput(DW_LNS_copy); -} - -static void -newcfaoffsetattr(DWDie *die, int32 offs) -{ - char block[10]; - int i; - - i = 0; - - block[i++] = DW_OP_call_frame_cfa; - if (offs != 0) { - block[i++] = DW_OP_consts; - i += sleb128enc(offs, block+i); - block[i++] = DW_OP_plus; - } - newattr(die, DW_AT_location, DW_CLS_BLOCK, i, mal(i)); - memmove(die->attr->data, block, i); -} - -static char* -mkvarname(char* name, int da) -{ - char buf[1024]; - char *n; - - snprint(buf, sizeof buf, "%s#%d", name, da); - n = mal(strlen(buf) + 1); - memmove(n, buf, strlen(buf)); - return n; -} - -/* - * Walk prog table, emit line program and build DIE tree. - */ - -// flush previous compilation unit. -static void -flushunit(DWDie *dwinfo, vlong pc, vlong unitstart, int32 header_length) -{ - vlong here; - - if (dwinfo != nil && pc != 0) { - newattr(dwinfo, DW_AT_high_pc, DW_CLS_ADDRESS, pc+1, 0); - } - - if (unitstart >= 0) { - cput(0); // start extended opcode - uleb128put(1); - cput(DW_LNE_end_sequence); - cflush(); - - here = cpos(); - seek(cout, unitstart, 0); - LPUT(here - unitstart - sizeof(int32)); // unit_length - WPUT(3); // dwarf version - LPUT(header_length); // header length starting here - cflush(); - seek(cout, here, 0); - } -} - -static void -writelines(void) -{ - Prog *q; - Sym *s; - Auto *a; - vlong unitstart, headerend, offs; - vlong pc, epc, lc, llc, lline; - int currfile; - int i, lang, da, dt; - Linehist *lh; - DWDie *dwinfo, *dwfunc, *dwvar, **dws; - DWDie *varhash[HASHSIZE]; - char *n, *nn; - - unitstart = -1; - headerend = -1; - pc = 0; - epc = 0; - lc = 1; - llc = 1; - currfile = -1; - lineo = cpos(); - dwinfo = nil; - - for(cursym = textp; cursym != nil; cursym = cursym->next) { - s = cursym; - if(s->text == P) - continue; - - // Look for history stack. If we find one, - // we're entering a new compilation unit - - if (inithist(s->autom)) { - flushunit(dwinfo, epc, unitstart, headerend - unitstart - 10); - unitstart = cpos(); - - if(debug['v'] > 1) { - print("dwarf writelines found %s\n", histfile[1]); - Linehist* lh; - for (lh = linehist; lh; lh = lh->link) - print("\t%8lld: [%4lld]%s\n", - lh->absline, lh->line, histfile[lh->file]); - } - - lang = guesslang(histfile[1]); - finddebugruntimepath(); - - dwinfo = newdie(&dwroot, DW_ABRV_COMPUNIT, strdup(histfile[1])); - newattr(dwinfo, DW_AT_language, DW_CLS_CONSTANT,lang, 0); - newattr(dwinfo, DW_AT_stmt_list, DW_CLS_PTR, unitstart - lineo, 0); - newattr(dwinfo, DW_AT_low_pc, DW_CLS_ADDRESS, s->text->pc, 0); - - // Write .debug_line Line Number Program Header (sec 6.2.4) - // Fields marked with (*) must be changed for 64-bit dwarf - LPUT(0); // unit_length (*), will be filled in by flushunit. - WPUT(3); // dwarf version (appendix F) - LPUT(0); // header_length (*), filled in by flushunit. - // cpos == unitstart + 4 + 2 + 4 - cput(1); // minimum_instruction_length - cput(1); // default_is_stmt - cput(LINE_BASE); // line_base - cput(LINE_RANGE); // line_range - cput(OPCODE_BASE); // opcode_base (we only use 1..4) - cput(0); // standard_opcode_lengths[1] - cput(1); // standard_opcode_lengths[2] - cput(1); // standard_opcode_lengths[3] - cput(1); // standard_opcode_lengths[4] - cput(0); // include_directories (empty) - - for (i=1; i < histfilesize; i++) { - strnput(histfile[i], strlen(histfile[i]) + 4); - // 4 zeros: the string termination + 3 fields. - } - - cput(0); // terminate file_names. - headerend = cpos(); - - pc = s->text->pc; - epc = pc; - currfile = 1; - lc = 1; - llc = 1; - - cput(0); // start extended opcode - uleb128put(1 + PtrSize); - cput(DW_LNE_set_address); - addrput(pc); - } - if(s->text == nil) - continue; - - if (unitstart < 0) { - diag("dwarf: reachable code before seeing any history: %P", s->text); - continue; - } - - dwfunc = newdie(dwinfo, DW_ABRV_FUNCTION, s->name); - newattr(dwfunc, DW_AT_low_pc, DW_CLS_ADDRESS, s->value, 0); - epc = s->value + s->size; - newattr(dwfunc, DW_AT_high_pc, DW_CLS_ADDRESS, epc, 0); - if (s->version == 0) - newattr(dwfunc, DW_AT_external, DW_CLS_FLAG, 1, 0); - - if(s->text->link == nil) - continue; - - for(q = s->text; q != P; q = q->link) { - lh = searchhist(q->line); - if (lh == nil) { - diag("dwarf: corrupt history or bad absolute line: %P", q); - continue; - } - - if (lh->file < 1) { // 0 is the past-EOF entry. - // diag("instruction with line number past EOF in %s: %P", histfile[1], q); - continue; - } - - lline = lh->line + q->line - lh->absline; - if (debug['v'] > 1) - print("%6llux %s[%lld] %P\n", (vlong)q->pc, histfile[lh->file], lline, q); - - if (q->line == lc) - continue; - if (currfile != lh->file) { - currfile = lh->file; - cput(DW_LNS_set_file); - uleb128put(currfile); - } - putpclcdelta(q->pc - pc, lline - llc); - pc = q->pc; - lc = q->line; - llc = lline; - } - - da = 0; - dwfunc->hash = varhash; // enable indexing of children by name - memset(varhash, 0, sizeof varhash); - for(a = s->autom; a; a = a->link) { - switch (a->type) { - case D_AUTO: - dt = DW_ABRV_AUTO; - offs = a->aoffset - PtrSize; - break; - case D_PARAM: - dt = DW_ABRV_PARAM; - offs = a->aoffset; - break; - default: - continue; - } - if (strstr(a->asym->name, ".autotmp_")) - continue; - if (find(dwfunc, a->asym->name) != nil) - n = mkvarname(a->asym->name, da); - else - n = a->asym->name; - // Drop the package prefix from locals and arguments. - nn = strrchr(n, '.'); - if (nn) - n = nn + 1; - - dwvar = newdie(dwfunc, dt, n); - newcfaoffsetattr(dwvar, offs); - newrefattr(dwvar, DW_AT_type, defgotype(a->gotype)); - - // push dwvar down dwfunc->child to preserve order - newattr(dwvar, DW_AT_internal_location, DW_CLS_CONSTANT, offs, nil); - dwfunc->child = dwvar->link; // take dwvar out from the top of the list - for (dws = &dwfunc->child; *dws != nil; dws = &(*dws)->link) - if (offs > getattr(*dws, DW_AT_internal_location)->value) - break; - dwvar->link = *dws; - *dws = dwvar; - - da++; - } - - dwfunc->hash = nil; - } - - flushunit(dwinfo, epc, unitstart, headerend - unitstart - 10); - linesize = cpos() - lineo; -} - -/* - * Emit .debug_frame - */ -enum -{ - CIERESERVE = 16, - DATAALIGNMENTFACTOR = -4, // TODO -PtrSize? - FAKERETURNCOLUMN = 16 // TODO gdb6 doesnt like > 15? -}; - -static void -putpccfadelta(vlong deltapc, vlong cfa) -{ - if (deltapc < 0x40) { - cput(DW_CFA_advance_loc + deltapc); - } else if (deltapc < 0x100) { - cput(DW_CFA_advance_loc1); - cput(deltapc); - } else if (deltapc < 0x10000) { - cput(DW_CFA_advance_loc2); - WPUT(deltapc); - } else { - cput(DW_CFA_advance_loc4); - LPUT(deltapc); - } - - cput(DW_CFA_def_cfa_offset_sf); - sleb128put(cfa / DATAALIGNMENTFACTOR); -} - -static void -writeframes(void) -{ - Prog *p, *q; - Sym *s; - vlong fdeo, fdesize, pad, cfa, pc; - - frameo = cpos(); - - // Emit the CIE, Section 6.4.1 - LPUT(CIERESERVE); // initial length, must be multiple of PtrSize - LPUT(0xffffffff); // cid. - cput(3); // dwarf version (appendix F) - cput(0); // augmentation "" - uleb128put(1); // code_alignment_factor - sleb128put(DATAALIGNMENTFACTOR); // guess - uleb128put(FAKERETURNCOLUMN); // return_address_register - - cput(DW_CFA_def_cfa); - uleb128put(DWARFREGSP); // register SP (**ABI-dependent, defined in l.h) - uleb128put(PtrSize); // offset - - cput(DW_CFA_offset + FAKERETURNCOLUMN); // return address - uleb128put(-PtrSize / DATAALIGNMENTFACTOR); // at cfa - x*4 - - // 4 is to exclude the length field. - pad = CIERESERVE + frameo + 4 - cpos(); - if (pad < 0) { - diag("dwarf: CIERESERVE too small by %lld bytes.", -pad); - errorexit(); - } - strnput("", pad); - - for(cursym = textp; cursym != nil; cursym = cursym->next) { - s = cursym; - if(s->text == nil) - continue; - - fdeo = cpos(); - // Emit a FDE, Section 6.4.1, starting wit a placeholder. - LPUT(0); // length, must be multiple of PtrSize - LPUT(0); // Pointer to the CIE above, at offset 0 - addrput(0); // initial location - addrput(0); // address range - - cfa = PtrSize; // CFA starts at sp+PtrSize - p = s->text; - pc = p->pc; - - for(q = p; q->link != P; q = q->link) { - if (q->spadj == 0) - continue; - cfa += q->spadj; - putpccfadelta(q->link->pc - pc, cfa); - pc = q->link->pc; - } - - fdesize = cpos() - fdeo - 4; // exclude the length field. - pad = rnd(fdesize, PtrSize) - fdesize; - strnput("", pad); - fdesize += pad; - cflush(); - - // Emit the FDE header for real, Section 6.4.1. - seek(cout, fdeo, 0); - LPUT(fdesize); - LPUT(0); - addrput(p->pc); - addrput(s->size); - - cflush(); - seek(cout, fdeo + 4 + fdesize, 0); - } - - cflush(); - framesize = cpos() - frameo; -} - -/* - * Walk DWarfDebugInfoEntries, and emit .debug_info - */ -enum -{ - COMPUNITHEADERSIZE = 4+2+4+1 -}; - -static void -writeinfo(void) -{ - DWDie *compunit; - vlong unitstart, here; - - fwdcount = 0; - - for (compunit = dwroot.child; compunit; compunit = compunit->link) { - unitstart = cpos(); - - // Write .debug_info Compilation Unit Header (sec 7.5.1) - // Fields marked with (*) must be changed for 64-bit dwarf - // This must match COMPUNITHEADERSIZE above. - LPUT(0); // unit_length (*), will be filled in later. - WPUT(3); // dwarf version (appendix F) - LPUT(0); // debug_abbrev_offset (*) - cput(PtrSize); // address_size - - putdie(compunit); - - cflush(); - here = cpos(); - seek(cout, unitstart, 0); - LPUT(here - unitstart - 4); // exclude the length field. - cflush(); - seek(cout, here, 0); - } - -} - -/* - * Emit .debug_pubnames/_types. _info must have been written before, - * because we need die->offs and infoo/infosize; - */ -static int -ispubname(DWDie *die) { - DWAttr *a; - - switch(die->abbrev) { - case DW_ABRV_FUNCTION: - case DW_ABRV_VARIABLE: - a = getattr(die, DW_AT_external); - return a && a->value; - } - return 0; -} - -static int -ispubtype(DWDie *die) { - return die->abbrev >= DW_ABRV_NULLTYPE; -} - -static vlong -writepub(int (*ispub)(DWDie*)) -{ - DWDie *compunit, *die; - DWAttr *dwa; - vlong unitstart, unitend, sectionstart, here; - - sectionstart = cpos(); - - for (compunit = dwroot.child; compunit != nil; compunit = compunit->link) { - unitstart = compunit->offs - COMPUNITHEADERSIZE; - if (compunit->link != nil) - unitend = compunit->link->offs - COMPUNITHEADERSIZE; - else - unitend = infoo + infosize; - - // Write .debug_pubnames/types Header (sec 6.1.1) - LPUT(0); // unit_length (*), will be filled in later. - WPUT(2); // dwarf version (appendix F) - LPUT(unitstart); // debug_info_offset (of the Comp unit Header) - LPUT(unitend - unitstart); // debug_info_length - - for (die = compunit->child; die != nil; die = die->link) { - if (!ispub(die)) continue; - LPUT(die->offs - unitstart); - dwa = getattr(die, DW_AT_name); - strnput(dwa->data, dwa->value + 1); - } - LPUT(0); - - cflush(); - here = cpos(); - seek(cout, sectionstart, 0); - LPUT(here - sectionstart - 4); // exclude the length field. - cflush(); - seek(cout, here, 0); - - } - - return sectionstart; -} - -/* - * emit .debug_aranges. _info must have been written before, - * because we need die->offs of dw_globals. - */ -static vlong -writearanges(void) -{ - DWDie *compunit; - DWAttr *b, *e; - int headersize; - vlong sectionstart; - - sectionstart = cpos(); - headersize = rnd(4+2+4+1+1, PtrSize); // don't count unit_length field itself - - for (compunit = dwroot.child; compunit != nil; compunit = compunit->link) { - b = getattr(compunit, DW_AT_low_pc); - if (b == nil) - continue; - e = getattr(compunit, DW_AT_high_pc); - if (e == nil) - continue; - - // Write .debug_aranges Header + entry (sec 6.1.2) - LPUT(headersize + 4*PtrSize - 4); // unit_length (*) - WPUT(2); // dwarf version (appendix F) - LPUT(compunit->offs - COMPUNITHEADERSIZE); // debug_info_offset - cput(PtrSize); // address_size - cput(0); // segment_size - strnput("", headersize - (4+2+4+1+1)); // align to PtrSize - - addrput(b->value); - addrput(e->value - b->value); - addrput(0); - addrput(0); - } - cflush(); - return sectionstart; -} - -static vlong -writegdbscript(void) -{ - vlong sectionstart; - - sectionstart = cpos(); - - if (gdbscript[0]) { - cput(1); // magic 1 byte? - strnput(gdbscript, strlen(gdbscript)+1); - cflush(); - } - return sectionstart; -} - -static void -align(vlong size) -{ - if(HEADTYPE == Hwindows) // Only Windows PE need section align. - strnput("", rnd(size, PEFILEALIGN) - size); -} - -/* - * This is the main entry point for generating dwarf. After emitting - * the mandatory debug_abbrev section, it calls writelines() to set up - * the per-compilation unit part of the DIE tree, while simultaneously - * emitting the debug_line section. When the final tree contains - * forward references, it will write the debug_info section in 2 - * passes. - * - */ -void -dwarfemitdebugsections(void) -{ - vlong infoe; - DWDie* die; - - if(debug['w']) // disable dwarf - return; - - // For diagnostic messages. - newattr(&dwtypes, DW_AT_name, DW_CLS_STRING, strlen("dwtypes"), "dwtypes"); - - mkindex(&dwroot); - mkindex(&dwtypes); - mkindex(&dwglobals); - - // Some types that must exist to define other ones. - newdie(&dwtypes, DW_ABRV_NULLTYPE, "<unspecified>"); - newdie(&dwtypes, DW_ABRV_NULLTYPE, "void"); - newrefattr(newdie(&dwtypes, DW_ABRV_PTRTYPE, "unsafe.Pointer"), - DW_AT_type, find(&dwtypes, "void")); - die = newdie(&dwtypes, DW_ABRV_BASETYPE, "uintptr"); // needed for array size - newattr(die, DW_AT_encoding, DW_CLS_CONSTANT, DW_ATE_unsigned, 0); - newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, PtrSize, 0); - - // Needed by the prettyprinter code for interface inspection. - defgotype(lookup_or_diag("type.runtime.commonType")); - defgotype(lookup_or_diag("type.runtime.InterfaceType")); - defgotype(lookup_or_diag("type.runtime.itab")); - - genasmsym(defdwsymb); - - writeabbrev(); - align(abbrevsize); - writelines(); - align(linesize); - writeframes(); - align(framesize); - - synthesizestringtypes(dwtypes.child); - synthesizeslicetypes(dwtypes.child); - synthesizemaptypes(dwtypes.child); - synthesizechantypes(dwtypes.child); - - reversetree(&dwroot.child); - reversetree(&dwtypes.child); - reversetree(&dwglobals.child); - - movetomodule(&dwtypes); - movetomodule(&dwglobals); - - infoo = cpos(); - writeinfo(); - infoe = cpos(); - pubnameso = infoe; - pubtypeso = infoe; - arangeso = infoe; - gdbscripto = infoe; - - if (fwdcount > 0) { - if (debug['v']) - Bprint(&bso, "%5.2f dwarf pass 2.\n", cputime()); - seek(cout, infoo, 0); - writeinfo(); - if (fwdcount > 0) { - diag("dwarf: unresolved references after first dwarf info pass"); - errorexit(); - } - if (infoe != cpos()) { - diag("dwarf: inconsistent second dwarf info pass"); - errorexit(); - } - } - infosize = infoe - infoo; - align(infosize); - - pubnameso = writepub(ispubname); - pubnamessize = cpos() - pubnameso; - align(pubnamessize); - - pubtypeso = writepub(ispubtype); - pubtypessize = cpos() - pubtypeso; - align(pubtypessize); - - arangeso = writearanges(); - arangessize = cpos() - arangeso; - align(arangessize); - - gdbscripto = writegdbscript(); - gdbscriptsize = cpos() - gdbscripto; - align(gdbscriptsize); -} - -/* - * Elf. - */ -enum -{ - ElfStrDebugAbbrev, - ElfStrDebugAranges, - ElfStrDebugFrame, - ElfStrDebugInfo, - ElfStrDebugLine, - ElfStrDebugLoc, - ElfStrDebugMacinfo, - ElfStrDebugPubNames, - ElfStrDebugPubTypes, - ElfStrDebugRanges, - ElfStrDebugStr, - ElfStrGDBScripts, - NElfStrDbg -}; - -vlong elfstrdbg[NElfStrDbg]; - -void -dwarfaddshstrings(Sym *shstrtab) -{ - if(debug['w']) // disable dwarf - return; - - elfstrdbg[ElfStrDebugAbbrev] = addstring(shstrtab, ".debug_abbrev"); - elfstrdbg[ElfStrDebugAranges] = addstring(shstrtab, ".debug_aranges"); - elfstrdbg[ElfStrDebugFrame] = addstring(shstrtab, ".debug_frame"); - elfstrdbg[ElfStrDebugInfo] = addstring(shstrtab, ".debug_info"); - elfstrdbg[ElfStrDebugLine] = addstring(shstrtab, ".debug_line"); - elfstrdbg[ElfStrDebugLoc] = addstring(shstrtab, ".debug_loc"); - elfstrdbg[ElfStrDebugMacinfo] = addstring(shstrtab, ".debug_macinfo"); - elfstrdbg[ElfStrDebugPubNames] = addstring(shstrtab, ".debug_pubnames"); - elfstrdbg[ElfStrDebugPubTypes] = addstring(shstrtab, ".debug_pubtypes"); - elfstrdbg[ElfStrDebugRanges] = addstring(shstrtab, ".debug_ranges"); - elfstrdbg[ElfStrDebugStr] = addstring(shstrtab, ".debug_str"); - elfstrdbg[ElfStrGDBScripts] = addstring(shstrtab, ".debug_gdb_scripts"); -} - -void -dwarfaddelfheaders(void) -{ - ElfShdr *sh; - - if(debug['w']) // disable dwarf - return; - - sh = newElfShdr(elfstrdbg[ElfStrDebugAbbrev]); - sh->type = SHT_PROGBITS; - sh->off = abbrevo; - sh->size = abbrevsize; - sh->addralign = 1; - - sh = newElfShdr(elfstrdbg[ElfStrDebugLine]); - sh->type = SHT_PROGBITS; - sh->off = lineo; - sh->size = linesize; - sh->addralign = 1; - - sh = newElfShdr(elfstrdbg[ElfStrDebugFrame]); - sh->type = SHT_PROGBITS; - sh->off = frameo; - sh->size = framesize; - sh->addralign = 1; - - sh = newElfShdr(elfstrdbg[ElfStrDebugInfo]); - sh->type = SHT_PROGBITS; - sh->off = infoo; - sh->size = infosize; - sh->addralign = 1; - - if (pubnamessize > 0) { - sh = newElfShdr(elfstrdbg[ElfStrDebugPubNames]); - sh->type = SHT_PROGBITS; - sh->off = pubnameso; - sh->size = pubnamessize; - sh->addralign = 1; - } - - if (pubtypessize > 0) { - sh = newElfShdr(elfstrdbg[ElfStrDebugPubTypes]); - sh->type = SHT_PROGBITS; - sh->off = pubtypeso; - sh->size = pubtypessize; - sh->addralign = 1; - } - - if (arangessize) { - sh = newElfShdr(elfstrdbg[ElfStrDebugAranges]); - sh->type = SHT_PROGBITS; - sh->off = arangeso; - sh->size = arangessize; - sh->addralign = 1; - } - - if (gdbscriptsize) { - sh = newElfShdr(elfstrdbg[ElfStrGDBScripts]); - sh->type = SHT_PROGBITS; - sh->off = gdbscripto; - sh->size = gdbscriptsize; - sh->addralign = 1; - } -} - -/* - * Macho - */ -void -dwarfaddmachoheaders(void) -{ - MachoSect *msect; - MachoSeg *ms; - vlong fakestart; - int nsect; - - if(debug['w']) // disable dwarf - return; - - // Zero vsize segments won't be loaded in memory, even so they - // have to be page aligned in the file. - fakestart = abbrevo & ~0xfff; - - nsect = 4; - if (pubnamessize > 0) - nsect++; - if (pubtypessize > 0) - nsect++; - if (arangessize > 0) - nsect++; - if (gdbscriptsize > 0) - nsect++; - - ms = newMachoSeg("__DWARF", nsect); - ms->fileoffset = fakestart; - ms->filesize = abbrevo-fakestart; - - msect = newMachoSect(ms, "__debug_abbrev"); - msect->off = abbrevo; - msect->size = abbrevsize; - ms->filesize += msect->size; - - msect = newMachoSect(ms, "__debug_line"); - msect->off = lineo; - msect->size = linesize; - ms->filesize += msect->size; - - msect = newMachoSect(ms, "__debug_frame"); - msect->off = frameo; - msect->size = framesize; - ms->filesize += msect->size; - - msect = newMachoSect(ms, "__debug_info"); - msect->off = infoo; - msect->size = infosize; - ms->filesize += msect->size; - - if (pubnamessize > 0) { - msect = newMachoSect(ms, "__debug_pubnames"); - msect->off = pubnameso; - msect->size = pubnamessize; - ms->filesize += msect->size; - } - - if (pubtypessize > 0) { - msect = newMachoSect(ms, "__debug_pubtypes"); - msect->off = pubtypeso; - msect->size = pubtypessize; - ms->filesize += msect->size; - } - - if (arangessize > 0) { - msect = newMachoSect(ms, "__debug_aranges"); - msect->off = arangeso; - msect->size = arangessize; - ms->filesize += msect->size; - } - - // TODO(lvd) fix gdb/python to load MachO (16 char section name limit) - if (gdbscriptsize > 0) { - msect = newMachoSect(ms, "__debug_gdb_scripts"); - msect->off = gdbscripto; - msect->size = gdbscriptsize; - ms->filesize += msect->size; - } -} - -/* - * Windows PE - */ -void -dwarfaddpeheaders(void) -{ - if(debug['w']) // disable dwarf - return; - - newPEDWARFSection(".debug_abbrev", abbrevsize); - newPEDWARFSection(".debug_line", linesize); - newPEDWARFSection(".debug_frame", framesize); - newPEDWARFSection(".debug_info", infosize); - newPEDWARFSection(".debug_pubnames", pubnamessize); - newPEDWARFSection(".debug_pubtypes", pubtypessize); - newPEDWARFSection(".debug_aranges", arangessize); - newPEDWARFSection(".debug_gdb_scripts", gdbscriptsize); -} diff --git a/src/cmd/ld/dwarf.h b/src/cmd/ld/dwarf.h deleted file mode 100644 index f0df2f9b1..000000000 --- a/src/cmd/ld/dwarf.h +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -/* - * Register 'f' symbol file fragments. Doing this while parsing the - * .6 input saves a pass over the symbol table later. - */ -void dwarfaddfrag(int n, char* frag); - -/* - * Emit debug_abbrevs, debug_info and debug_line sections to current - * offset in cout. - */ -void dwarfemitdebugsections(void); - -/* - * Add the dwarf section names to the ELF - * s[ection]h[eader]str[ing]tab. Prerequisite for - * dwarfaddelfheaders(). - */ -void dwarfaddshstrings(Sym *shstrtab); - -/* - * Add section headers pointing to the sections emitted in - * dwarfemitdebugsections. - */ -void dwarfaddelfheaders(void); -void dwarfaddmachoheaders(void); -void dwarfaddpeheaders(void); diff --git a/src/cmd/ld/dwarf_defs.h b/src/cmd/ld/dwarf_defs.h deleted file mode 100644 index eed143dff..000000000 --- a/src/cmd/ld/dwarf_defs.h +++ /dev/null @@ -1,503 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Cut, pasted, tr-and-awk'ed from tables in -// http://dwarfstd.org/doc/Dwarf3.pdf - -// Table 18 -enum -{ - DW_TAG_array_type = 0x01, - DW_TAG_class_type = 0x02, - DW_TAG_entry_point = 0x03, - DW_TAG_enumeration_type = 0x04, - DW_TAG_formal_parameter = 0x05, - DW_TAG_imported_declaration = 0x08, - DW_TAG_label = 0x0a, - DW_TAG_lexical_block = 0x0b, - DW_TAG_member = 0x0d, - DW_TAG_pointer_type = 0x0f, - DW_TAG_reference_type = 0x10, - DW_TAG_compile_unit = 0x11, - DW_TAG_string_type = 0x12, - DW_TAG_structure_type = 0x13, - DW_TAG_subroutine_type = 0x15, - DW_TAG_typedef = 0x16, - DW_TAG_union_type = 0x17, - DW_TAG_unspecified_parameters = 0x18, - DW_TAG_variant = 0x19, - DW_TAG_common_block = 0x1a, - DW_TAG_common_inclusion = 0x1b, - DW_TAG_inheritance = 0x1c, - DW_TAG_inlined_subroutine = 0x1d, - DW_TAG_module = 0x1e, - DW_TAG_ptr_to_member_type = 0x1f, - DW_TAG_set_type = 0x20, - DW_TAG_subrange_type = 0x21, - DW_TAG_with_stmt = 0x22, - DW_TAG_access_declaration = 0x23, - DW_TAG_base_type = 0x24, - DW_TAG_catch_block = 0x25, - DW_TAG_const_type = 0x26, - DW_TAG_constant = 0x27, - DW_TAG_enumerator = 0x28, - DW_TAG_file_type = 0x29, - DW_TAG_friend = 0x2a, - DW_TAG_namelist = 0x2b, - DW_TAG_namelist_item = 0x2c, - DW_TAG_packed_type = 0x2d, - DW_TAG_subprogram = 0x2e, - DW_TAG_template_type_parameter = 0x2f, - DW_TAG_template_value_parameter = 0x30, - DW_TAG_thrown_type = 0x31, - DW_TAG_try_block = 0x32, - DW_TAG_variant_part = 0x33, - DW_TAG_variable = 0x34, - DW_TAG_volatile_type = 0x35, - // Dwarf3 - DW_TAG_dwarf_procedure = 0x36, - DW_TAG_restrict_type = 0x37, - DW_TAG_interface_type = 0x38, - DW_TAG_namespace = 0x39, - DW_TAG_imported_module = 0x3a, - DW_TAG_unspecified_type = 0x3b, - DW_TAG_partial_unit = 0x3c, - DW_TAG_imported_unit = 0x3d, - DW_TAG_condition = 0x3f, - DW_TAG_shared_type = 0x40, - // Dwarf4 - DW_TAG_type_unit = 0x41, - DW_TAG_rvalue_reference_type = 0x42, - DW_TAG_template_alias = 0x43, - - // User defined - DW_TAG_lo_user = 0x4080, - DW_TAG_hi_user = 0xffff, - -}; - -// Table 19 -enum -{ - DW_CHILDREN_no = 0x00, - DW_CHILDREN_yes = 0x01, -}; - -// Not from the spec, but logicaly belongs here -enum -{ - DW_CLS_ADDRESS = 0x01, - DW_CLS_BLOCK, - DW_CLS_CONSTANT, - DW_CLS_FLAG, - DW_CLS_PTR, // lineptr, loclistptr, macptr, rangelistptr - DW_CLS_REFERENCE, - DW_CLS_STRING -}; - -// Table 20 -enum -{ - DW_AT_sibling = 0x01, // reference - DW_AT_location = 0x02, // block, loclistptr - DW_AT_name = 0x03, // string - DW_AT_ordering = 0x09, // constant - DW_AT_byte_size = 0x0b, // block, constant, reference - DW_AT_bit_offset = 0x0c, // block, constant, reference - DW_AT_bit_size = 0x0d, // block, constant, reference - DW_AT_stmt_list = 0x10, // lineptr - DW_AT_low_pc = 0x11, // address - DW_AT_high_pc = 0x12, // address - DW_AT_language = 0x13, // constant - DW_AT_discr = 0x15, // reference - DW_AT_discr_value = 0x16, // constant - DW_AT_visibility = 0x17, // constant - DW_AT_import = 0x18, // reference - DW_AT_string_length = 0x19, // block, loclistptr - DW_AT_common_reference = 0x1a, // reference - DW_AT_comp_dir = 0x1b, // string - DW_AT_const_value = 0x1c, // block, constant, string - DW_AT_containing_type = 0x1d, // reference - DW_AT_default_value = 0x1e, // reference - DW_AT_inline = 0x20, // constant - DW_AT_is_optional = 0x21, // flag - DW_AT_lower_bound = 0x22, // block, constant, reference - DW_AT_producer = 0x25, // string - DW_AT_prototyped = 0x27, // flag - DW_AT_return_addr = 0x2a, // block, loclistptr - DW_AT_start_scope = 0x2c, // constant - DW_AT_bit_stride = 0x2e, // constant - DW_AT_upper_bound = 0x2f, // block, constant, reference - DW_AT_abstract_origin = 0x31, // reference - DW_AT_accessibility = 0x32, // constant - DW_AT_address_class = 0x33, // constant - DW_AT_artificial = 0x34, // flag - DW_AT_base_types = 0x35, // reference - DW_AT_calling_convention = 0x36, // constant - DW_AT_count = 0x37, // block, constant, reference - DW_AT_data_member_location = 0x38, // block, constant, loclistptr - DW_AT_decl_column = 0x39, // constant - DW_AT_decl_file = 0x3a, // constant - DW_AT_decl_line = 0x3b, // constant - DW_AT_declaration = 0x3c, // flag - DW_AT_discr_list = 0x3d, // block - DW_AT_encoding = 0x3e, // constant - DW_AT_external = 0x3f, // flag - DW_AT_frame_base = 0x40, // block, loclistptr - DW_AT_friend = 0x41, // reference - DW_AT_identifier_case = 0x42, // constant - DW_AT_macro_info = 0x43, // macptr - DW_AT_namelist_item = 0x44, // block - DW_AT_priority = 0x45, // reference - DW_AT_segment = 0x46, // block, loclistptr - DW_AT_specification = 0x47, // reference - DW_AT_static_link = 0x48, // block, loclistptr - DW_AT_type = 0x49, // reference - DW_AT_use_location = 0x4a, // block, loclistptr - DW_AT_variable_parameter = 0x4b, // flag - DW_AT_virtuality = 0x4c, // constant - DW_AT_vtable_elem_location = 0x4d, // block, loclistptr - // Dwarf3 - DW_AT_allocated = 0x4e, // block, constant, reference - DW_AT_associated = 0x4f, // block, constant, reference - DW_AT_data_location = 0x50, // block - DW_AT_byte_stride = 0x51, // block, constant, reference - DW_AT_entry_pc = 0x52, // address - DW_AT_use_UTF8 = 0x53, // flag - DW_AT_extension = 0x54, // reference - DW_AT_ranges = 0x55, // rangelistptr - DW_AT_trampoline = 0x56, // address, flag, reference, string - DW_AT_call_column = 0x57, // constant - DW_AT_call_file = 0x58, // constant - DW_AT_call_line = 0x59, // constant - DW_AT_description = 0x5a, // string - DW_AT_binary_scale = 0x5b, // constant - DW_AT_decimal_scale = 0x5c, // constant - DW_AT_small = 0x5d, // reference - DW_AT_decimal_sign = 0x5e, // constant - DW_AT_digit_count = 0x5f, // constant - DW_AT_picture_string = 0x60, // string - DW_AT_mutable = 0x61, // flag - DW_AT_threads_scaled = 0x62, // flag - DW_AT_explicit = 0x63, // flag - DW_AT_object_pointer = 0x64, // reference - DW_AT_endianity = 0x65, // constant - DW_AT_elemental = 0x66, // flag - DW_AT_pure = 0x67, // flag - DW_AT_recursive = 0x68, // flag - - DW_AT_lo_user = 0x2000, // --- - DW_AT_hi_user = 0x3fff, // --- - -}; - -// Table 21 -enum -{ - DW_FORM_addr = 0x01, // address - DW_FORM_block2 = 0x03, // block - DW_FORM_block4 = 0x04, // block - DW_FORM_data2 = 0x05, // constant - DW_FORM_data4 = 0x06, // constant, lineptr, loclistptr, macptr, rangelistptr - DW_FORM_data8 = 0x07, // constant, lineptr, loclistptr, macptr, rangelistptr - DW_FORM_string = 0x08, // string - DW_FORM_block = 0x09, // block - DW_FORM_block1 = 0x0a, // block - DW_FORM_data1 = 0x0b, // constant - DW_FORM_flag = 0x0c, // flag - DW_FORM_sdata = 0x0d, // constant - DW_FORM_strp = 0x0e, // string - DW_FORM_udata = 0x0f, // constant - DW_FORM_ref_addr = 0x10, // reference - DW_FORM_ref1 = 0x11, // reference - DW_FORM_ref2 = 0x12, // reference - DW_FORM_ref4 = 0x13, // reference - DW_FORM_ref8 = 0x14, // reference - DW_FORM_ref_udata = 0x15, // reference - DW_FORM_indirect = 0x16, // (see Section 7.5.3) -}; - -// Table 24 (#operands, notes) -enum -{ - DW_OP_addr = 0x03, // 1 constant address (size target specific) - DW_OP_deref = 0x06, // 0 - DW_OP_const1u = 0x08, // 1 1-byte constant - DW_OP_const1s = 0x09, // 1 1-byte constant - DW_OP_const2u = 0x0a, // 1 2-byte constant - DW_OP_const2s = 0x0b, // 1 2-byte constant - DW_OP_const4u = 0x0c, // 1 4-byte constant - DW_OP_const4s = 0x0d, // 1 4-byte constant - DW_OP_const8u = 0x0e, // 1 8-byte constant - DW_OP_const8s = 0x0f, // 1 8-byte constant - DW_OP_constu = 0x10, // 1 ULEB128 constant - DW_OP_consts = 0x11, // 1 SLEB128 constant - DW_OP_dup = 0x12, // 0 - DW_OP_drop = 0x13, // 0 - DW_OP_over = 0x14, // 0 - DW_OP_pick = 0x15, // 1 1-byte stack index - DW_OP_swap = 0x16, // 0 - DW_OP_rot = 0x17, // 0 - DW_OP_xderef = 0x18, // 0 - DW_OP_abs = 0x19, // 0 - DW_OP_and = 0x1a, // 0 - DW_OP_div = 0x1b, // 0 - DW_OP_minus = 0x1c, // 0 - DW_OP_mod = 0x1d, // 0 - DW_OP_mul = 0x1e, // 0 - DW_OP_neg = 0x1f, // 0 - DW_OP_not = 0x20, // 0 - DW_OP_or = 0x21, // 0 - DW_OP_plus = 0x22, // 0 - DW_OP_plus_uconst = 0x23, // 1 ULEB128 addend - DW_OP_shl = 0x24, // 0 - DW_OP_shr = 0x25, // 0 - DW_OP_shra = 0x26, // 0 - DW_OP_xor = 0x27, // 0 - DW_OP_skip = 0x2f, // 1 signed 2-byte constant - DW_OP_bra = 0x28, // 1 signed 2-byte constant - DW_OP_eq = 0x29, // 0 - DW_OP_ge = 0x2a, // 0 - DW_OP_gt = 0x2b, // 0 - DW_OP_le = 0x2c, // 0 - DW_OP_lt = 0x2d, // 0 - DW_OP_ne = 0x2e, // 0 - DW_OP_lit0 = 0x30, // 0 ... - DW_OP_lit31 = 0x4f, // 0 literals 0..31 = (DW_OP_lit0 + - // literal) - DW_OP_reg0 = 0x50, // 0 .. - DW_OP_reg31 = 0x6f, // 0 reg 0..31 = (DW_OP_reg0 + regnum) - DW_OP_breg0 = 0x70, // 1 ... - DW_OP_breg31 = 0x8f, // 1 SLEB128 offset base register 0..31 = (DW_OP_breg0 + regnum) - DW_OP_regx = 0x90, // 1 ULEB128 register - DW_OP_fbreg = 0x91, // 1 SLEB128 offset - DW_OP_bregx = 0x92, // 2 ULEB128 register followed by SLEB128 offset - DW_OP_piece = 0x93, // 1 ULEB128 size of piece addressed - DW_OP_deref_size = 0x94, // 1 1-byte size of data retrieved - DW_OP_xderef_size = 0x95, // 1 1-byte size of data retrieved - DW_OP_nop = 0x96, // 0 - DW_OP_push_object_address = 0x97, // 0 - DW_OP_call2 = 0x98, // 1 2-byte offset of DIE - DW_OP_call4 = 0x99, // 1 4-byte offset of DIE - DW_OP_call_ref = 0x9a, // 1 4- or 8-byte offset of DIE - DW_OP_form_tls_address = 0x9b, // 0 - DW_OP_call_frame_cfa = 0x9c, // 0 - DW_OP_bit_piece = 0x9d, // 2 - DW_OP_lo_user = 0xe0, - DW_OP_hi_user = 0xff, -}; - -// Table 25 -enum -{ - DW_ATE_address = 0x01, - DW_ATE_boolean = 0x02, - DW_ATE_complex_float = 0x03, - DW_ATE_float = 0x04, - DW_ATE_signed = 0x05, - DW_ATE_signed_char = 0x06, - DW_ATE_unsigned = 0x07, - DW_ATE_unsigned_char = 0x08, - DW_ATE_imaginary_float = 0x09, - DW_ATE_packed_decimal = 0x0a, - DW_ATE_numeric_string = 0x0b, - DW_ATE_edited = 0x0c, - DW_ATE_signed_fixed = 0x0d, - DW_ATE_unsigned_fixed = 0x0e, - DW_ATE_decimal_float = 0x0f, - DW_ATE_lo_user = 0x80, - DW_ATE_hi_user = 0xff, -}; - -// Table 26 -enum -{ - DW_DS_unsigned = 0x01, - DW_DS_leading_overpunch = 0x02, - DW_DS_trailing_overpunch = 0x03, - DW_DS_leading_separate = 0x04, - DW_DS_trailing_separate = 0x05, -}; - -// Table 27 -enum -{ - DW_END_default = 0x00, - DW_END_big = 0x01, - DW_END_little = 0x02, - DW_END_lo_user = 0x40, - DW_END_hi_user = 0xff, -}; - -// Table 28 -enum -{ - DW_ACCESS_public = 0x01, - DW_ACCESS_protected = 0x02, - DW_ACCESS_private = 0x03, -}; - -// Table 29 -enum -{ - DW_VIS_local = 0x01, - DW_VIS_exported = 0x02, - DW_VIS_qualified = 0x03, -}; - -// Table 30 -enum -{ - DW_VIRTUALITY_none = 0x00, - DW_VIRTUALITY_virtual = 0x01, - DW_VIRTUALITY_pure_virtual = 0x02, -}; - -// Table 31 -enum -{ - DW_LANG_C89 = 0x0001, - DW_LANG_C = 0x0002, - DW_LANG_Ada83 = 0x0003, - DW_LANG_C_plus_plus = 0x0004, - DW_LANG_Cobol74 = 0x0005, - DW_LANG_Cobol85 = 0x0006, - DW_LANG_Fortran77 = 0x0007, - DW_LANG_Fortran90 = 0x0008, - DW_LANG_Pascal83 = 0x0009, - DW_LANG_Modula2 = 0x000a, - // Dwarf3 - DW_LANG_Java = 0x000b, - DW_LANG_C99 = 0x000c, - DW_LANG_Ada95 = 0x000d, - DW_LANG_Fortran95 = 0x000e, - DW_LANG_PLI = 0x000f, - DW_LANG_ObjC = 0x0010, - DW_LANG_ObjC_plus_plus = 0x0011, - DW_LANG_UPC = 0x0012, - DW_LANG_D = 0x0013, - // Dwarf4 - DW_LANG_Python = 0x0014, - // Dwarf5 - DW_LANG_Go = 0x0016, - - DW_LANG_lo_user = 0x8000, - DW_LANG_hi_user = 0xffff, -}; - -// Table 32 -enum -{ - DW_ID_case_sensitive = 0x00, - DW_ID_up_case = 0x01, - DW_ID_down_case = 0x02, - DW_ID_case_insensitive = 0x03, -}; - -// Table 33 -enum -{ - DW_CC_normal = 0x01, - DW_CC_program = 0x02, - DW_CC_nocall = 0x03, - DW_CC_lo_user = 0x40, - DW_CC_hi_user = 0xff, -}; - -// Table 34 -enum -{ - DW_INL_not_inlined = 0x00, - DW_INL_inlined = 0x01, - DW_INL_declared_not_inlined = 0x02, - DW_INL_declared_inlined = 0x03, -}; - -// Table 35 -enum -{ - DW_ORD_row_major = 0x00, - DW_ORD_col_major = 0x01, -}; - -// Table 36 -enum -{ - DW_DSC_label = 0x00, - DW_DSC_range = 0x01, -}; - -// Table 37 -enum -{ - DW_LNS_copy = 0x01, - DW_LNS_advance_pc = 0x02, - DW_LNS_advance_line = 0x03, - DW_LNS_set_file = 0x04, - DW_LNS_set_column = 0x05, - DW_LNS_negate_stmt = 0x06, - DW_LNS_set_basic_block = 0x07, - DW_LNS_const_add_pc = 0x08, - DW_LNS_fixed_advance_pc = 0x09, - // Dwarf3 - DW_LNS_set_prologue_end = 0x0a, - DW_LNS_set_epilogue_begin = 0x0b, - DW_LNS_set_isa = 0x0c, -}; - -// Table 38 -enum -{ - DW_LNE_end_sequence = 0x01, - DW_LNE_set_address = 0x02, - DW_LNE_define_file = 0x03, - DW_LNE_lo_user = 0x80, - DW_LNE_hi_user = 0xff, -}; - -// Table 39 -enum -{ - DW_MACINFO_define = 0x01, - DW_MACINFO_undef = 0x02, - DW_MACINFO_start_file = 0x03, - DW_MACINFO_end_file = 0x04, - DW_MACINFO_vendor_ext = 0xff, -}; - -// Table 40. -enum -{ // operand,... - DW_CFA_nop = 0x00, - DW_CFA_set_loc = 0x01, // address - DW_CFA_advance_loc1 = 0x02, // 1-byte delta - DW_CFA_advance_loc2 = 0x03, // 2-byte delta - DW_CFA_advance_loc4 = 0x04, // 4-byte delta - DW_CFA_offset_extended = 0x05, // ULEB128 register, ULEB128 offset - DW_CFA_restore_extended = 0x06, // ULEB128 register - DW_CFA_undefined = 0x07, // ULEB128 register - DW_CFA_same_value = 0x08, // ULEB128 register - DW_CFA_register = 0x09, // ULEB128 register, ULEB128 register - DW_CFA_remember_state = 0x0a, - DW_CFA_restore_state = 0x0b, - DW_CFA_def_cfa = 0x0c, // ULEB128 register, ULEB128 offset - DW_CFA_def_cfa_register = 0x0d, // ULEB128 register - DW_CFA_def_cfa_offset = 0x0e, // ULEB128 offset - DW_CFA_def_cfa_expression = 0x0f, // BLOCK - DW_CFA_expression = 0x10, // ULEB128 register, BLOCK - DW_CFA_offset_extended_sf = 0x11, // ULEB128 register, SLEB128 offset - DW_CFA_def_cfa_sf = 0x12, // ULEB128 register, SLEB128 offset - DW_CFA_def_cfa_offset_sf = 0x13, // SLEB128 offset - DW_CFA_val_offset = 0x14, // ULEB128, ULEB128 - DW_CFA_val_offset_sf = 0x15, // ULEB128, SLEB128 - DW_CFA_val_expression = 0x16, // ULEB128, BLOCK - - DW_CFA_lo_user = 0x1c, - DW_CFA_hi_user = 0x3f, - - // Opcodes that take an addend operand. - DW_CFA_advance_loc = 0x1<<6, // +delta - DW_CFA_offset = 0x2<<6, // +register (ULEB128 offset) - DW_CFA_restore = 0x3<<6, // +register -}; diff --git a/src/cmd/ld/elf.c b/src/cmd/ld/elf.c deleted file mode 100644 index fc917b203..000000000 --- a/src/cmd/ld/elf.c +++ /dev/null @@ -1,558 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include "l.h" -#include "lib.h" -#include "../ld/elf.h" - -/* - * We use the 64-bit data structures on both 32- and 64-bit machines - * in order to write the code just once. The 64-bit data structure is - * written in the 32-bit format on the 32-bit machines. - */ -#define NSECT 32 - -int iself; - -static int elf64; -static ElfEhdr hdr; -static ElfPhdr *phdr[NSECT]; -static ElfShdr *shdr[NSECT]; -static char *interp; - -typedef struct Elfstring Elfstring; -struct Elfstring -{ - char *s; - int off; -}; - -static Elfstring elfstr[100]; -static int nelfstr; - -/* - Initialize the global variable that describes the ELF header. It will be updated as - we write section and prog headers. - */ -void -elfinit(void) -{ - iself = 1; - - switch(thechar) { - // 64-bit architectures - case '6': - elf64 = 1; - hdr.phoff = ELF64HDRSIZE; /* Must be be ELF64HDRSIZE: first PHdr must follow ELF header */ - hdr.shoff = ELF64HDRSIZE; /* Will move as we add PHeaders */ - hdr.ehsize = ELF64HDRSIZE; /* Must be ELF64HDRSIZE */ - hdr.phentsize = ELF64PHDRSIZE; /* Must be ELF64PHDRSIZE */ - hdr.shentsize = ELF64SHDRSIZE; /* Must be ELF64SHDRSIZE */ - break; - - // 32-bit architectures - default: - hdr.phoff = ELF32HDRSIZE; /* Must be be ELF32HDRSIZE: first PHdr must follow ELF header */ - hdr.shoff = ELF32HDRSIZE; /* Will move as we add PHeaders */ - hdr.ehsize = ELF32HDRSIZE; /* Must be ELF32HDRSIZE */ - hdr.phentsize = ELF32PHDRSIZE; /* Must be ELF32PHDRSIZE */ - hdr.shentsize = ELF32SHDRSIZE; /* Must be ELF32SHDRSIZE */ - } -} - -void -elf64phdr(ElfPhdr *e) -{ - LPUT(e->type); - LPUT(e->flags); - VPUT(e->off); - VPUT(e->vaddr); - VPUT(e->paddr); - VPUT(e->filesz); - VPUT(e->memsz); - VPUT(e->align); -} - -void -elf32phdr(ElfPhdr *e) -{ - LPUT(e->type); - LPUT(e->off); - LPUT(e->vaddr); - LPUT(e->paddr); - LPUT(e->filesz); - LPUT(e->memsz); - LPUT(e->flags); - LPUT(e->align); -} - -void -elf64shdr(ElfShdr *e) -{ - LPUT(e->name); - LPUT(e->type); - VPUT(e->flags); - VPUT(e->addr); - VPUT(e->off); - VPUT(e->size); - LPUT(e->link); - LPUT(e->info); - VPUT(e->addralign); - VPUT(e->entsize); -} - -void -elf32shdr(ElfShdr *e) -{ - LPUT(e->name); - LPUT(e->type); - LPUT(e->flags); - LPUT(e->addr); - LPUT(e->off); - LPUT(e->size); - LPUT(e->link); - LPUT(e->info); - LPUT(e->addralign); - LPUT(e->entsize); -} - -uint32 -elfwriteshdrs(void) -{ - int i; - - if (elf64) { - for (i = 0; i < hdr.shnum; i++) - elf64shdr(shdr[i]); - return hdr.shnum * ELF64SHDRSIZE; - } - for (i = 0; i < hdr.shnum; i++) - elf32shdr(shdr[i]); - return hdr.shnum * ELF32SHDRSIZE; -} - -void -elfsetstring(char *s, int off) -{ - if(nelfstr >= nelem(elfstr)) { - diag("too many elf strings"); - errorexit(); - } - elfstr[nelfstr].s = s; - elfstr[nelfstr].off = off; - nelfstr++; -} - -uint32 -elfwritephdrs(void) -{ - int i; - - if (elf64) { - for (i = 0; i < hdr.phnum; i++) - elf64phdr(phdr[i]); - return hdr.phnum * ELF64PHDRSIZE; - } - for (i = 0; i < hdr.phnum; i++) - elf32phdr(phdr[i]); - return hdr.phnum * ELF32PHDRSIZE; -} - -ElfPhdr* -newElfPhdr(void) -{ - ElfPhdr *e; - - e = mal(sizeof *e); - if (hdr.phnum >= NSECT) - diag("too many phdrs"); - else - phdr[hdr.phnum++] = e; - if (elf64) - hdr.shoff += ELF64PHDRSIZE; - else - hdr.shoff += ELF32PHDRSIZE; - return e; -} - -ElfShdr* -newElfShstrtab(vlong name) -{ - hdr.shstrndx = hdr.shnum; - return newElfShdr(name); -} - -ElfShdr* -newElfShdr(vlong name) -{ - ElfShdr *e; - - e = mal(sizeof *e); - e->name = name; - if (hdr.shnum >= NSECT) { - diag("too many shdrs"); - } else { - shdr[hdr.shnum++] = e; - } - return e; -} - -ElfEhdr* -getElfEhdr(void) -{ - return &hdr; -} - -uint32 -elf64writehdr(void) -{ - int i; - - for (i = 0; i < EI_NIDENT; i++) - cput(hdr.ident[i]); - WPUT(hdr.type); - WPUT(hdr.machine); - LPUT(hdr.version); - VPUT(hdr.entry); - VPUT(hdr.phoff); - VPUT(hdr.shoff); - LPUT(hdr.flags); - WPUT(hdr.ehsize); - WPUT(hdr.phentsize); - WPUT(hdr.phnum); - WPUT(hdr.shentsize); - WPUT(hdr.shnum); - WPUT(hdr.shstrndx); - return ELF64HDRSIZE; -} - -uint32 -elf32writehdr(void) -{ - int i; - - for (i = 0; i < EI_NIDENT; i++) - cput(hdr.ident[i]); - WPUT(hdr.type); - WPUT(hdr.machine); - LPUT(hdr.version); - LPUT(hdr.entry); - LPUT(hdr.phoff); - LPUT(hdr.shoff); - LPUT(hdr.flags); - WPUT(hdr.ehsize); - WPUT(hdr.phentsize); - WPUT(hdr.phnum); - WPUT(hdr.shentsize); - WPUT(hdr.shnum); - WPUT(hdr.shstrndx); - return ELF32HDRSIZE; -} - -uint32 -elfwritehdr(void) -{ - if(elf64) - return elf64writehdr(); - return elf32writehdr(); -} - -/* Taken directly from the definition document for ELF64 */ -uint32 -elfhash(uchar *name) -{ - uint32 h = 0, g; - while (*name) { - h = (h << 4) + *name++; - if (g = h & 0xf0000000) - h ^= g >> 24; - h &= 0x0fffffff; - } - return h; -} - -void -elfwritedynent(Sym *s, int tag, uint64 val) -{ - if(elf64) { - adduint64(s, tag); - adduint64(s, val); - } else { - adduint32(s, tag); - adduint32(s, val); - } -} - -void -elfwritedynentsym(Sym *s, int tag, Sym *t) -{ - if(elf64) - adduint64(s, tag); - else - adduint32(s, tag); - addaddr(s, t); -} - -void -elfwritedynentsymsize(Sym *s, int tag, Sym *t) -{ - if(elf64) - adduint64(s, tag); - else - adduint32(s, tag); - addsize(s, t); -} - -int -elfwriteinterp(void) -{ - int n; - - if(interp == nil) - return 0; - - n = strlen(interp)+1; - seek(cout, ELFRESERVE-n, 0); - ewrite(cout, interp, n); - return n; -} - -void -elfinterp(ElfShdr *sh, uint64 startva, char *p) -{ - int n; - - interp = p; - n = strlen(interp)+1; - sh->addr = startva + ELFRESERVE - n; - sh->off = ELFRESERVE - n; - sh->size = n; -} - -extern int nelfsym; -int elfverneed; - -typedef struct Elfaux Elfaux; -typedef struct Elflib Elflib; - -struct Elflib -{ - Elflib *next; - Elfaux *aux; - char *file; -}; - -struct Elfaux -{ - Elfaux *next; - int num; - char *vers; -}; - -Elfaux* -addelflib(Elflib **list, char *file, char *vers) -{ - Elflib *lib; - Elfaux *aux; - - for(lib=*list; lib; lib=lib->next) - if(strcmp(lib->file, file) == 0) - goto havelib; - lib = mal(sizeof *lib); - lib->next = *list; - lib->file = file; - *list = lib; -havelib: - for(aux=lib->aux; aux; aux=aux->next) - if(strcmp(aux->vers, vers) == 0) - goto haveaux; - aux = mal(sizeof *aux); - aux->next = lib->aux; - aux->vers = vers; - lib->aux = aux; -haveaux: - return aux; -} - -void -elfdynhash(void) -{ - Sym *s, *sy, *dynstr; - int i, j, nbucket, b, nfile; - uint32 hc, *chain, *buckets; - int nsym; - char *name; - Elfaux **need; - Elflib *needlib; - Elflib *l; - Elfaux *x; - - if(!iself) - return; - - nsym = nelfsym; - s = lookup(".hash", 0); - s->type = SELFDATA; - s->reachable = 1; - - i = nsym; - nbucket = 1; - while(i > 0) { - ++nbucket; - i >>= 1; - } - - needlib = nil; - need = malloc(nsym * sizeof need[0]); - chain = malloc(nsym * sizeof chain[0]); - buckets = malloc(nbucket * sizeof buckets[0]); - if(need == nil || chain == nil || buckets == nil) { - cursym = nil; - diag("out of memory"); - errorexit(); - } - memset(need, 0, nsym * sizeof need[0]); - memset(chain, 0, nsym * sizeof chain[0]); - memset(buckets, 0, nbucket * sizeof buckets[0]); - for(sy=allsym; sy!=S; sy=sy->allsym) { - if (sy->dynid <= 0) - continue; - - if(sy->dynimpvers) - need[sy->dynid] = addelflib(&needlib, sy->dynimplib, sy->dynimpvers); - - name = sy->dynimpname; - if(name == nil) - name = sy->name; - hc = elfhash((uchar*)name); - - b = hc % nbucket; - chain[sy->dynid] = buckets[b]; - buckets[b] = sy->dynid; - } - - adduint32(s, nbucket); - adduint32(s, nsym); - for(i = 0; i<nbucket; i++) - adduint32(s, buckets[i]); - for(i = 0; i<nsym; i++) - adduint32(s, chain[i]); - - free(chain); - free(buckets); - - // version symbols - dynstr = lookup(".dynstr", 0); - s = lookup(".gnu.version_r", 0); - i = 2; - nfile = 0; - for(l=needlib; l; l=l->next) { - nfile++; - // header - adduint16(s, 1); // table version - j = 0; - for(x=l->aux; x; x=x->next) - j++; - adduint16(s, j); // aux count - adduint32(s, addstring(dynstr, l->file)); // file string offset - adduint32(s, 16); // offset from header to first aux - if(l->next) - adduint32(s, 16+j*16); // offset from this header to next - else - adduint32(s, 0); - - for(x=l->aux; x; x=x->next) { - x->num = i++; - // aux struct - adduint32(s, elfhash((uchar*)x->vers)); // hash - adduint16(s, 0); // flags - adduint16(s, x->num); // other - index we refer to this by - adduint32(s, addstring(dynstr, x->vers)); // version string offset - if(x->next) - adduint32(s, 16); // offset from this aux to next - else - adduint32(s, 0); - } - } - - // version references - s = lookup(".gnu.version", 0); - for(i=0; i<nsym; i++) { - if(i == 0) - adduint16(s, 0); // first entry - no symbol - else if(need[i] == nil) - adduint16(s, 1); // global - else - adduint16(s, need[i]->num); - } - - free(need); - - s = lookup(".dynamic", 0); - elfverneed = nfile; - if(elfverneed) { - elfwritedynentsym(s, DT_VERNEED, lookup(".gnu.version_r", 0)); - elfwritedynent(s, DT_VERNEEDNUM, nfile); - elfwritedynentsym(s, DT_VERSYM, lookup(".gnu.version", 0)); - } - elfwritedynent(s, DT_NULL, 0); -} - -ElfPhdr* -elfphload(Segment *seg) -{ - ElfPhdr *ph; - - ph = newElfPhdr(); - ph->type = PT_LOAD; - if(seg->rwx & 4) - ph->flags |= PF_R; - if(seg->rwx & 2) - ph->flags |= PF_W; - if(seg->rwx & 1) - ph->flags |= PF_X; - ph->vaddr = seg->vaddr; - ph->paddr = seg->vaddr; - ph->memsz = seg->len; - ph->off = seg->fileoff; - ph->filesz = seg->filelen; - ph->align = INITRND; - - return ph; -} - -ElfShdr* -elfshbits(Section *sect) -{ - int i, off; - ElfShdr *sh; - - for(i=0; i<nelfstr; i++) { - if(strcmp(sect->name, elfstr[i].s) == 0) { - off = elfstr[i].off; - goto found; - } - } - diag("cannot find elf name %s", sect->name); - errorexit(); - return nil; - -found: - sh = newElfShdr(off); - if(sect->vaddr < sect->seg->vaddr + sect->seg->filelen) - sh->type = SHT_PROGBITS; - else - sh->type = SHT_NOBITS; - sh->flags = SHF_ALLOC; - if(sect->rwx & 1) - sh->flags |= SHF_EXECINSTR; - if(sect->rwx & 2) - sh->flags |= SHF_WRITE; - sh->addr = sect->vaddr; - sh->addralign = PtrSize; - sh->size = sect->len; - sh->off = sect->seg->fileoff + sect->vaddr - sect->seg->vaddr; - - return sh; -} diff --git a/src/cmd/ld/elf.h b/src/cmd/ld/elf.h deleted file mode 100644 index c63df2241..000000000 --- a/src/cmd/ld/elf.h +++ /dev/null @@ -1,989 +0,0 @@ -/* - * Derived from: - * $FreeBSD: src/sys/sys/elf32.h,v 1.8.14.1 2005/12/30 22:13:58 marcel Exp $ - * $FreeBSD: src/sys/sys/elf64.h,v 1.10.14.1 2005/12/30 22:13:58 marcel Exp $ - * $FreeBSD: src/sys/sys/elf_common.h,v 1.15.8.1 2005/12/30 22:13:58 marcel Exp $ - * $FreeBSD: src/sys/alpha/include/elf.h,v 1.14 2003/09/25 01:10:22 peter Exp $ - * $FreeBSD: src/sys/amd64/include/elf.h,v 1.18 2004/08/03 08:21:48 dfr Exp $ - * $FreeBSD: src/sys/arm/include/elf.h,v 1.5.2.1 2006/06/30 21:42:52 cognet Exp $ - * $FreeBSD: src/sys/i386/include/elf.h,v 1.16 2004/08/02 19:12:17 dfr Exp $ - * $FreeBSD: src/sys/powerpc/include/elf.h,v 1.7 2004/11/02 09:47:01 ssouhlal Exp $ - * $FreeBSD: src/sys/sparc64/include/elf.h,v 1.12 2003/09/25 01:10:26 peter Exp $ - * - * Copyright (c) 1996-1998 John D. Polstra. All rights reserved. - * Copyright (c) 2001 David E. O'Brien - * Portions Copyright 2009 The Go Authors. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - */ - -/* - * ELF definitions that are independent of architecture or word size. - */ - -/* - * Note header. The ".note" section contains an array of notes. Each - * begins with this header, aligned to a word boundary. Immediately - * following the note header is n_namesz bytes of name, padded to the - * next word boundary. Then comes n_descsz bytes of descriptor, again - * padded to a word boundary. The values of n_namesz and n_descsz do - * not include the padding. - */ - -typedef struct { - uint32 n_namesz; /* Length of name. */ - uint32 n_descsz; /* Length of descriptor. */ - uint32 n_type; /* Type of this note. */ -} Elf_Note; - -/* Indexes into the e_ident array. Keep synced with - http://www.sco.com/developer/gabi/ch4.eheader.html */ -#define EI_MAG0 0 /* Magic number, byte 0. */ -#define EI_MAG1 1 /* Magic number, byte 1. */ -#define EI_MAG2 2 /* Magic number, byte 2. */ -#define EI_MAG3 3 /* Magic number, byte 3. */ -#define EI_CLASS 4 /* Class of machine. */ -#define EI_DATA 5 /* Data format. */ -#define EI_VERSION 6 /* ELF format version. */ -#define EI_OSABI 7 /* Operating system / ABI identification */ -#define EI_ABIVERSION 8 /* ABI version */ -#define OLD_EI_BRAND 8 /* Start of architecture identification. */ -#define EI_PAD 9 /* Start of padding (per SVR4 ABI). */ -#define EI_NIDENT 16 /* Size of e_ident array. */ - -/* Values for the magic number bytes. */ -#define ELFMAG0 0x7f -#define ELFMAG1 'E' -#define ELFMAG2 'L' -#define ELFMAG3 'F' -#define ELFMAG "\177ELF" /* magic string */ -#define SELFMAG 4 /* magic string size */ - -/* Values for e_ident[EI_VERSION] and e_version. */ -#define EV_NONE 0 -#define EV_CURRENT 1 - -/* Values for e_ident[EI_CLASS]. */ -#define ELFCLASSNONE 0 /* Unknown class. */ -#define ELFCLASS32 1 /* 32-bit architecture. */ -#define ELFCLASS64 2 /* 64-bit architecture. */ - -/* Values for e_ident[EI_DATA]. */ -#define ELFDATANONE 0 /* Unknown data format. */ -#define ELFDATA2LSB 1 /* 2's complement little-endian. */ -#define ELFDATA2MSB 2 /* 2's complement big-endian. */ - -/* Values for e_ident[EI_OSABI]. */ -#define ELFOSABI_NONE 0 /* UNIX System V ABI */ -#define ELFOSABI_HPUX 1 /* HP-UX operating system */ -#define ELFOSABI_NETBSD 2 /* NetBSD */ -#define ELFOSABI_LINUX 3 /* GNU/Linux */ -#define ELFOSABI_HURD 4 /* GNU/Hurd */ -#define ELFOSABI_86OPEN 5 /* 86Open common IA32 ABI */ -#define ELFOSABI_SOLARIS 6 /* Solaris */ -#define ELFOSABI_AIX 7 /* AIX */ -#define ELFOSABI_IRIX 8 /* IRIX */ -#define ELFOSABI_FREEBSD 9 /* FreeBSD */ -#define ELFOSABI_TRU64 10 /* TRU64 UNIX */ -#define ELFOSABI_MODESTO 11 /* Novell Modesto */ -#define ELFOSABI_OPENBSD 12 /* OpenBSD */ -#define ELFOSABI_OPENVMS 13 /* Open VMS */ -#define ELFOSABI_NSK 14 /* HP Non-Stop Kernel */ -#define ELFOSABI_ARM 97 /* ARM */ -#define ELFOSABI_STANDALONE 255 /* Standalone (embedded) application */ - -#define ELFOSABI_SYSV ELFOSABI_NONE /* symbol used in old spec */ -#define ELFOSABI_MONTEREY ELFOSABI_AIX /* Monterey */ - -/* e_ident */ -#define IS_ELF(ehdr) ((ehdr).e_ident[EI_MAG0] == ELFMAG0 && \ - (ehdr).e_ident[EI_MAG1] == ELFMAG1 && \ - (ehdr).e_ident[EI_MAG2] == ELFMAG2 && \ - (ehdr).e_ident[EI_MAG3] == ELFMAG3) - -/* Values for e_type. */ -#define ET_NONE 0 /* Unknown type. */ -#define ET_REL 1 /* Relocatable. */ -#define ET_EXEC 2 /* Executable. */ -#define ET_DYN 3 /* Shared object. */ -#define ET_CORE 4 /* Core file. */ -#define ET_LOOS 0xfe00 /* First operating system specific. */ -#define ET_HIOS 0xfeff /* Last operating system-specific. */ -#define ET_LOPROC 0xff00 /* First processor-specific. */ -#define ET_HIPROC 0xffff /* Last processor-specific. */ - -/* Values for e_machine. */ -#define EM_NONE 0 /* Unknown machine. */ -#define EM_M32 1 /* AT&T WE32100. */ -#define EM_SPARC 2 /* Sun SPARC. */ -#define EM_386 3 /* Intel i386. */ -#define EM_68K 4 /* Motorola 68000. */ -#define EM_88K 5 /* Motorola 88000. */ -#define EM_860 7 /* Intel i860. */ -#define EM_MIPS 8 /* MIPS R3000 Big-Endian only. */ -#define EM_S370 9 /* IBM System/370. */ -#define EM_MIPS_RS3_LE 10 /* MIPS R3000 Little-Endian. */ -#define EM_PARISC 15 /* HP PA-RISC. */ -#define EM_VPP500 17 /* Fujitsu VPP500. */ -#define EM_SPARC32PLUS 18 /* SPARC v8plus. */ -#define EM_960 19 /* Intel 80960. */ -#define EM_PPC 20 /* PowerPC 32-bit. */ -#define EM_PPC64 21 /* PowerPC 64-bit. */ -#define EM_S390 22 /* IBM System/390. */ -#define EM_V800 36 /* NEC V800. */ -#define EM_FR20 37 /* Fujitsu FR20. */ -#define EM_RH32 38 /* TRW RH-32. */ -#define EM_RCE 39 /* Motorola RCE. */ -#define EM_ARM 40 /* ARM. */ -#define EM_SH 42 /* Hitachi SH. */ -#define EM_SPARCV9 43 /* SPARC v9 64-bit. */ -#define EM_TRICORE 44 /* Siemens TriCore embedded processor. */ -#define EM_ARC 45 /* Argonaut RISC Core. */ -#define EM_H8_300 46 /* Hitachi H8/300. */ -#define EM_H8_300H 47 /* Hitachi H8/300H. */ -#define EM_H8S 48 /* Hitachi H8S. */ -#define EM_H8_500 49 /* Hitachi H8/500. */ -#define EM_IA_64 50 /* Intel IA-64 Processor. */ -#define EM_MIPS_X 51 /* Stanford MIPS-X. */ -#define EM_COLDFIRE 52 /* Motorola ColdFire. */ -#define EM_68HC12 53 /* Motorola M68HC12. */ -#define EM_MMA 54 /* Fujitsu MMA. */ -#define EM_PCP 55 /* Siemens PCP. */ -#define EM_NCPU 56 /* Sony nCPU. */ -#define EM_NDR1 57 /* Denso NDR1 microprocessor. */ -#define EM_STARCORE 58 /* Motorola Star*Core processor. */ -#define EM_ME16 59 /* Toyota ME16 processor. */ -#define EM_ST100 60 /* STMicroelectronics ST100 processor. */ -#define EM_TINYJ 61 /* Advanced Logic Corp. TinyJ processor. */ -#define EM_X86_64 62 /* Advanced Micro Devices x86-64 */ - -/* Non-standard or deprecated. */ -#define EM_486 6 /* Intel i486. */ -#define EM_MIPS_RS4_BE 10 /* MIPS R4000 Big-Endian */ -#define EM_ALPHA_STD 41 /* Digital Alpha (standard value). */ -#define EM_ALPHA 0x9026 /* Alpha (written in the absence of an ABI) */ - -/* Special section indexes. */ -#define SHN_UNDEF 0 /* Undefined, missing, irrelevant. */ -#define SHN_LORESERVE 0xff00 /* First of reserved range. */ -#define SHN_LOPROC 0xff00 /* First processor-specific. */ -#define SHN_HIPROC 0xff1f /* Last processor-specific. */ -#define SHN_LOOS 0xff20 /* First operating system-specific. */ -#define SHN_HIOS 0xff3f /* Last operating system-specific. */ -#define SHN_ABS 0xfff1 /* Absolute values. */ -#define SHN_COMMON 0xfff2 /* Common data. */ -#define SHN_XINDEX 0xffff /* Escape -- index stored elsewhere. */ -#define SHN_HIRESERVE 0xffff /* Last of reserved range. */ - -/* sh_type */ -#define SHT_NULL 0 /* inactive */ -#define SHT_PROGBITS 1 /* program defined information */ -#define SHT_SYMTAB 2 /* symbol table section */ -#define SHT_STRTAB 3 /* string table section */ -#define SHT_RELA 4 /* relocation section with addends */ -#define SHT_HASH 5 /* symbol hash table section */ -#define SHT_DYNAMIC 6 /* dynamic section */ -#define SHT_NOTE 7 /* note section */ -#define SHT_NOBITS 8 /* no space section */ -#define SHT_REL 9 /* relocation section - no addends */ -#define SHT_SHLIB 10 /* reserved - purpose unknown */ -#define SHT_DYNSYM 11 /* dynamic symbol table section */ -#define SHT_INIT_ARRAY 14 /* Initialization function pointers. */ -#define SHT_FINI_ARRAY 15 /* Termination function pointers. */ -#define SHT_PREINIT_ARRAY 16 /* Pre-initialization function ptrs. */ -#define SHT_GROUP 17 /* Section group. */ -#define SHT_SYMTAB_SHNDX 18 /* Section indexes (see SHN_XINDEX). */ -#define SHT_LOOS 0x60000000 /* First of OS specific semantics */ -#define SHT_HIOS 0x6fffffff /* Last of OS specific semantics */ -#define SHT_GNU_VERDEF 0x6ffffffd -#define SHT_GNU_VERNEED 0x6ffffffe -#define SHT_GNU_VERSYM 0x6fffffff -#define SHT_LOPROC 0x70000000 /* reserved range for processor */ -#define SHT_HIPROC 0x7fffffff /* specific section header types */ -#define SHT_LOUSER 0x80000000 /* reserved range for application */ -#define SHT_HIUSER 0xffffffff /* specific indexes */ - -/* Flags for sh_flags. */ -#define SHF_WRITE 0x1 /* Section contains writable data. */ -#define SHF_ALLOC 0x2 /* Section occupies memory. */ -#define SHF_EXECINSTR 0x4 /* Section contains instructions. */ -#define SHF_MERGE 0x10 /* Section may be merged. */ -#define SHF_STRINGS 0x20 /* Section contains strings. */ -#define SHF_INFO_LINK 0x40 /* sh_info holds section index. */ -#define SHF_LINK_ORDER 0x80 /* Special ordering requirements. */ -#define SHF_OS_NONCONFORMING 0x100 /* OS-specific processing required. */ -#define SHF_GROUP 0x200 /* Member of section group. */ -#define SHF_TLS 0x400 /* Section contains TLS data. */ -#define SHF_MASKOS 0x0ff00000 /* OS-specific semantics. */ -#define SHF_MASKPROC 0xf0000000 /* Processor-specific semantics. */ - -/* Values for p_type. */ -#define PT_NULL 0 /* Unused entry. */ -#define PT_LOAD 1 /* Loadable segment. */ -#define PT_DYNAMIC 2 /* Dynamic linking information segment. */ -#define PT_INTERP 3 /* Pathname of interpreter. */ -#define PT_NOTE 4 /* Auxiliary information. */ -#define PT_SHLIB 5 /* Reserved (not used). */ -#define PT_PHDR 6 /* Location of program header itself. */ -#define PT_TLS 7 /* Thread local storage segment */ -#define PT_LOOS 0x60000000 /* First OS-specific. */ -#define PT_HIOS 0x6fffffff /* Last OS-specific. */ -#define PT_LOPROC 0x70000000 /* First processor-specific type. */ -#define PT_HIPROC 0x7fffffff /* Last processor-specific type. */ -#define PT_GNU_STACK 0x6474e551 - -/* Values for p_flags. */ -#define PF_X 0x1 /* Executable. */ -#define PF_W 0x2 /* Writable. */ -#define PF_R 0x4 /* Readable. */ -#define PF_MASKOS 0x0ff00000 /* Operating system-specific. */ -#define PF_MASKPROC 0xf0000000 /* Processor-specific. */ - -/* Values for d_tag. */ -#define DT_NULL 0 /* Terminating entry. */ -/* String table offset of a needed shared library. */ -#define DT_NEEDED 1 -#define DT_PLTRELSZ 2 /* Total size in bytes of PLT relocations. */ -#define DT_PLTGOT 3 /* Processor-dependent address. */ -#define DT_HASH 4 /* Address of symbol hash table. */ -#define DT_STRTAB 5 /* Address of string table. */ -#define DT_SYMTAB 6 /* Address of symbol table. */ -#define DT_RELA 7 /* Address of ElfNN_Rela relocations. */ -#define DT_RELASZ 8 /* Total size of ElfNN_Rela relocations. */ -#define DT_RELAENT 9 /* Size of each ElfNN_Rela relocation entry. */ -#define DT_STRSZ 10 /* Size of string table. */ -#define DT_SYMENT 11 /* Size of each symbol table entry. */ -#define DT_INIT 12 /* Address of initialization function. */ -#define DT_FINI 13 /* Address of finalization function. */ -/* String table offset of shared object name. */ -#define DT_SONAME 14 -#define DT_RPATH 15 /* String table offset of library path. [sup] */ -#define DT_SYMBOLIC 16 /* Indicates "symbolic" linking. [sup] */ -#define DT_REL 17 /* Address of ElfNN_Rel relocations. */ -#define DT_RELSZ 18 /* Total size of ElfNN_Rel relocations. */ -#define DT_RELENT 19 /* Size of each ElfNN_Rel relocation. */ -#define DT_PLTREL 20 /* Type of relocation used for PLT. */ -#define DT_DEBUG 21 /* Reserved (not used). */ -/* Indicates there may be relocations in non-writable segments. [sup] */ -#define DT_TEXTREL 22 -#define DT_JMPREL 23 /* Address of PLT relocations. */ -#define DT_BIND_NOW 24 /* [sup] */ -/* Address of the array of pointers to initialization functions */ -#define DT_INIT_ARRAY 25 -/* Address of the array of pointers to termination functions */ -#define DT_FINI_ARRAY 26 -/* Size in bytes of the array of initialization functions. */ -#define DT_INIT_ARRAYSZ 27 -/* Size in bytes of the array of terminationfunctions. */ -#define DT_FINI_ARRAYSZ 28 -/* String table offset of a null-terminated library search path string. */ -#define DT_RUNPATH 29 -#define DT_FLAGS 30 /* Object specific flag values. */ -/* Values greater than or equal to DT_ENCODING and less than - DT_LOOS follow the rules for the interpretation of the d_un - union as follows: even == 'd_ptr', even == 'd_val' or none */ -#define DT_ENCODING 32 -/* Address of the array of pointers to pre-initialization functions. */ -#define DT_PREINIT_ARRAY 32 -/* Size in bytes of the array of pre-initialization functions. */ -#define DT_PREINIT_ARRAYSZ 33 -#define DT_LOOS 0x6000000d /* First OS-specific */ -#define DT_HIOS 0x6ffff000 /* Last OS-specific */ -#define DT_LOPROC 0x70000000 /* First processor-specific type. */ -#define DT_HIPROC 0x7fffffff /* Last processor-specific type. */ - -#define DT_VERNEED 0x6ffffffe -#define DT_VERNEEDNUM 0x6fffffff -#define DT_VERSYM 0x6ffffff0 - -/* Values for DT_FLAGS */ -/* Indicates that the object being loaded may make reference to - the $ORIGIN substitution string */ -#define DF_ORIGIN 0x0001 -#define DF_SYMBOLIC 0x0002 /* Indicates "symbolic" linking. */ -/* Indicates there may be relocations in non-writable segments. */ -#define DF_TEXTREL 0x0004 -/* Indicates that the dynamic linker should process all - relocations for the object containing this entry before - transferring control to the program. */ -#define DF_BIND_NOW 0x0008 -/* Indicates that the shared object or executable contains code - using a static thread-local storage scheme. */ -#define DF_STATIC_TLS 0x0010 - -/* Values for n_type. Used in core files. */ -#define NT_PRSTATUS 1 /* Process status. */ -#define NT_FPREGSET 2 /* Floating point registers. */ -#define NT_PRPSINFO 3 /* Process state info. */ - -/* Symbol Binding - ELFNN_ST_BIND - st_info */ -#define STB_LOCAL 0 /* Local symbol */ -#define STB_GLOBAL 1 /* Global symbol */ -#define STB_WEAK 2 /* like global - lower precedence */ -#define STB_LOOS 10 /* Reserved range for operating system */ -#define STB_HIOS 12 /* specific semantics. */ -#define STB_LOPROC 13 /* reserved range for processor */ -#define STB_HIPROC 15 /* specific semantics. */ - -/* Symbol type - ELFNN_ST_TYPE - st_info */ -#define STT_NOTYPE 0 /* Unspecified type. */ -#define STT_OBJECT 1 /* Data object. */ -#define STT_FUNC 2 /* Function. */ -#define STT_SECTION 3 /* Section. */ -#define STT_FILE 4 /* Source file. */ -#define STT_COMMON 5 /* Uninitialized common block. */ -#define STT_TLS 6 /* TLS object. */ -#define STT_LOOS 10 /* Reserved range for operating system */ -#define STT_HIOS 12 /* specific semantics. */ -#define STT_LOPROC 13 /* reserved range for processor */ -#define STT_HIPROC 15 /* specific semantics. */ - -/* Symbol visibility - ELFNN_ST_VISIBILITY - st_other */ -#define STV_DEFAULT 0x0 /* Default visibility (see binding). */ -#define STV_INTERNAL 0x1 /* Special meaning in relocatable objects. */ -#define STV_HIDDEN 0x2 /* Not visible. */ -#define STV_PROTECTED 0x3 /* Visible but not preemptible. */ - -/* Special symbol table indexes. */ -#define STN_UNDEF 0 /* Undefined symbol index. */ - -/* - * ELF definitions common to all 32-bit architectures. - */ - -typedef uint32 Elf32_Addr; -typedef uint16 Elf32_Half; -typedef uint32 Elf32_Off; -typedef int32 Elf32_Sword; -typedef uint32 Elf32_Word; - -typedef Elf32_Word Elf32_Hashelt; - -/* Non-standard class-dependent datatype used for abstraction. */ -typedef Elf32_Word Elf32_Size; -typedef Elf32_Sword Elf32_Ssize; - -/* - * ELF header. - */ - -typedef struct { - unsigned char ident[EI_NIDENT]; /* File identification. */ - Elf32_Half type; /* File type. */ - Elf32_Half machine; /* Machine architecture. */ - Elf32_Word version; /* ELF format version. */ - Elf32_Addr entry; /* Entry point. */ - Elf32_Off phoff; /* Program header file offset. */ - Elf32_Off shoff; /* Section header file offset. */ - Elf32_Word flags; /* Architecture-specific flags. */ - Elf32_Half ehsize; /* Size of ELF header in bytes. */ - Elf32_Half phentsize; /* Size of program header entry. */ - Elf32_Half phnum; /* Number of program header entries. */ - Elf32_Half shentsize; /* Size of section header entry. */ - Elf32_Half shnum; /* Number of section header entries. */ - Elf32_Half shstrndx; /* Section name strings section. */ -} Elf32_Ehdr; - -/* - * Section header. - */ - -typedef struct { - Elf32_Word name; /* Section name (index into the - section header string table). */ - Elf32_Word type; /* Section type. */ - Elf32_Word flags; /* Section flags. */ - Elf32_Addr vaddr; /* Address in memory image. */ - Elf32_Off off; /* Offset in file. */ - Elf32_Word size; /* Size in bytes. */ - Elf32_Word link; /* Index of a related section. */ - Elf32_Word info; /* Depends on section type. */ - Elf32_Word addralign; /* Alignment in bytes. */ - Elf32_Word entsize; /* Size of each entry in section. */ -} Elf32_Shdr; - -/* - * Program header. - */ - -typedef struct { - Elf32_Word type; /* Entry type. */ - Elf32_Off off; /* File offset of contents. */ - Elf32_Addr vaddr; /* Virtual address in memory image. */ - Elf32_Addr paddr; /* Physical address (not used). */ - Elf32_Word filesz; /* Size of contents in file. */ - Elf32_Word memsz; /* Size of contents in memory. */ - Elf32_Word flags; /* Access permission flags. */ - Elf32_Word align; /* Alignment in memory and file. */ -} Elf32_Phdr; - -/* - * Dynamic structure. The ".dynamic" section contains an array of them. - */ - -typedef struct { - Elf32_Sword d_tag; /* Entry type. */ - union { - Elf32_Word d_val; /* Integer value. */ - Elf32_Addr d_ptr; /* Address value. */ - } d_un; -} Elf32_Dyn; - -/* - * Relocation entries. - */ - -/* Relocations that don't need an addend field. */ -typedef struct { - Elf32_Addr off; /* Location to be relocated. */ - Elf32_Word info; /* Relocation type and symbol index. */ -} Elf32_Rel; - -/* Relocations that need an addend field. */ -typedef struct { - Elf32_Addr off; /* Location to be relocated. */ - Elf32_Word info; /* Relocation type and symbol index. */ - Elf32_Sword addend; /* Addend. */ -} Elf32_Rela; - -/* Macros for accessing the fields of r_info. */ -#define ELF32_R_SYM(info) ((info) >> 8) -#define ELF32_R_TYPE(info) ((unsigned char)(info)) - -/* Macro for constructing r_info from field values. */ -#define ELF32_R_INFO(sym, type) (((sym) << 8) + (unsigned char)(type)) - -/* - * Relocation types. - */ - -#define R_X86_64_NONE 0 /* No relocation. */ -#define R_X86_64_64 1 /* Add 64 bit symbol value. */ -#define R_X86_64_PC32 2 /* PC-relative 32 bit signed sym value. */ -#define R_X86_64_GOT32 3 /* PC-relative 32 bit GOT offset. */ -#define R_X86_64_PLT32 4 /* PC-relative 32 bit PLT offset. */ -#define R_X86_64_COPY 5 /* Copy data from shared object. */ -#define R_X86_64_GLOB_DAT 6 /* Set GOT entry to data address. */ -#define R_X86_64_JMP_SLOT 7 /* Set GOT entry to code address. */ -#define R_X86_64_RELATIVE 8 /* Add load address of shared object. */ -#define R_X86_64_GOTPCREL 9 /* Add 32 bit signed pcrel offset to GOT. */ -#define R_X86_64_32 10 /* Add 32 bit zero extended symbol value */ -#define R_X86_64_32S 11 /* Add 32 bit sign extended symbol value */ -#define R_X86_64_16 12 /* Add 16 bit zero extended symbol value */ -#define R_X86_64_PC16 13 /* Add 16 bit signed extended pc relative symbol value */ -#define R_X86_64_8 14 /* Add 8 bit zero extended symbol value */ -#define R_X86_64_PC8 15 /* Add 8 bit signed extended pc relative symbol value */ -#define R_X86_64_DTPMOD64 16 /* ID of module containing symbol */ -#define R_X86_64_DTPOFF64 17 /* Offset in TLS block */ -#define R_X86_64_TPOFF64 18 /* Offset in static TLS block */ -#define R_X86_64_TLSGD 19 /* PC relative offset to GD GOT entry */ -#define R_X86_64_TLSLD 20 /* PC relative offset to LD GOT entry */ -#define R_X86_64_DTPOFF32 21 /* Offset in TLS block */ -#define R_X86_64_GOTTPOFF 22 /* PC relative offset to IE GOT entry */ -#define R_X86_64_TPOFF32 23 /* Offset in static TLS block */ - -#define R_X86_64_COUNT 24 /* Count of defined relocation types. */ - - -#define R_ALPHA_NONE 0 /* No reloc */ -#define R_ALPHA_REFLONG 1 /* Direct 32 bit */ -#define R_ALPHA_REFQUAD 2 /* Direct 64 bit */ -#define R_ALPHA_GPREL32 3 /* GP relative 32 bit */ -#define R_ALPHA_LITERAL 4 /* GP relative 16 bit w/optimization */ -#define R_ALPHA_LITUSE 5 /* Optimization hint for LITERAL */ -#define R_ALPHA_GPDISP 6 /* Add displacement to GP */ -#define R_ALPHA_BRADDR 7 /* PC+4 relative 23 bit shifted */ -#define R_ALPHA_HINT 8 /* PC+4 relative 16 bit shifted */ -#define R_ALPHA_SREL16 9 /* PC relative 16 bit */ -#define R_ALPHA_SREL32 10 /* PC relative 32 bit */ -#define R_ALPHA_SREL64 11 /* PC relative 64 bit */ -#define R_ALPHA_OP_PUSH 12 /* OP stack push */ -#define R_ALPHA_OP_STORE 13 /* OP stack pop and store */ -#define R_ALPHA_OP_PSUB 14 /* OP stack subtract */ -#define R_ALPHA_OP_PRSHIFT 15 /* OP stack right shift */ -#define R_ALPHA_GPVALUE 16 -#define R_ALPHA_GPRELHIGH 17 -#define R_ALPHA_GPRELLOW 18 -#define R_ALPHA_IMMED_GP_16 19 -#define R_ALPHA_IMMED_GP_HI32 20 -#define R_ALPHA_IMMED_SCN_HI32 21 -#define R_ALPHA_IMMED_BR_HI32 22 -#define R_ALPHA_IMMED_LO32 23 -#define R_ALPHA_COPY 24 /* Copy symbol at runtime */ -#define R_ALPHA_GLOB_DAT 25 /* Create GOT entry */ -#define R_ALPHA_JMP_SLOT 26 /* Create PLT entry */ -#define R_ALPHA_RELATIVE 27 /* Adjust by program base */ - -#define R_ALPHA_COUNT 28 - - -#define R_ARM_NONE 0 /* No relocation. */ -#define R_ARM_PC24 1 -#define R_ARM_ABS32 2 -#define R_ARM_REL32 3 -#define R_ARM_PC13 4 -#define R_ARM_ABS16 5 -#define R_ARM_ABS12 6 -#define R_ARM_THM_ABS5 7 -#define R_ARM_ABS8 8 -#define R_ARM_SBREL32 9 -#define R_ARM_THM_PC22 10 -#define R_ARM_THM_PC8 11 -#define R_ARM_AMP_VCALL9 12 -#define R_ARM_SWI24 13 -#define R_ARM_THM_SWI8 14 -#define R_ARM_XPC25 15 -#define R_ARM_THM_XPC22 16 -#define R_ARM_COPY 20 /* Copy data from shared object. */ -#define R_ARM_GLOB_DAT 21 /* Set GOT entry to data address. */ -#define R_ARM_JUMP_SLOT 22 /* Set GOT entry to code address. */ -#define R_ARM_RELATIVE 23 /* Add load address of shared object. */ -#define R_ARM_GOTOFF 24 /* Add GOT-relative symbol address. */ -#define R_ARM_GOTPC 25 /* Add PC-relative GOT table address. */ -#define R_ARM_GOT32 26 /* Add PC-relative GOT offset. */ -#define R_ARM_PLT32 27 /* Add PC-relative PLT offset. */ -#define R_ARM_GNU_VTENTRY 100 -#define R_ARM_GNU_VTINHERIT 101 -#define R_ARM_RSBREL32 250 -#define R_ARM_THM_RPC22 251 -#define R_ARM_RREL32 252 -#define R_ARM_RABS32 253 -#define R_ARM_RPC24 254 -#define R_ARM_RBASE 255 - -#define R_ARM_COUNT 33 /* Count of defined relocation types. */ - - -#define R_386_NONE 0 /* No relocation. */ -#define R_386_32 1 /* Add symbol value. */ -#define R_386_PC32 2 /* Add PC-relative symbol value. */ -#define R_386_GOT32 3 /* Add PC-relative GOT offset. */ -#define R_386_PLT32 4 /* Add PC-relative PLT offset. */ -#define R_386_COPY 5 /* Copy data from shared object. */ -#define R_386_GLOB_DAT 6 /* Set GOT entry to data address. */ -#define R_386_JMP_SLOT 7 /* Set GOT entry to code address. */ -#define R_386_RELATIVE 8 /* Add load address of shared object. */ -#define R_386_GOTOFF 9 /* Add GOT-relative symbol address. */ -#define R_386_GOTPC 10 /* Add PC-relative GOT table address. */ -#define R_386_TLS_TPOFF 14 /* Negative offset in static TLS block */ -#define R_386_TLS_IE 15 /* Absolute address of GOT for -ve static TLS */ -#define R_386_TLS_GOTIE 16 /* GOT entry for negative static TLS block */ -#define R_386_TLS_LE 17 /* Negative offset relative to static TLS */ -#define R_386_TLS_GD 18 /* 32 bit offset to GOT (index,off) pair */ -#define R_386_TLS_LDM 19 /* 32 bit offset to GOT (index,zero) pair */ -#define R_386_TLS_GD_32 24 /* 32 bit offset to GOT (index,off) pair */ -#define R_386_TLS_GD_PUSH 25 /* pushl instruction for Sun ABI GD sequence */ -#define R_386_TLS_GD_CALL 26 /* call instruction for Sun ABI GD sequence */ -#define R_386_TLS_GD_POP 27 /* popl instruction for Sun ABI GD sequence */ -#define R_386_TLS_LDM_32 28 /* 32 bit offset to GOT (index,zero) pair */ -#define R_386_TLS_LDM_PUSH 29 /* pushl instruction for Sun ABI LD sequence */ -#define R_386_TLS_LDM_CALL 30 /* call instruction for Sun ABI LD sequence */ -#define R_386_TLS_LDM_POP 31 /* popl instruction for Sun ABI LD sequence */ -#define R_386_TLS_LDO_32 32 /* 32 bit offset from start of TLS block */ -#define R_386_TLS_IE_32 33 /* 32 bit offset to GOT static TLS offset entry */ -#define R_386_TLS_LE_32 34 /* 32 bit offset within static TLS block */ -#define R_386_TLS_DTPMOD32 35 /* GOT entry containing TLS index */ -#define R_386_TLS_DTPOFF32 36 /* GOT entry containing TLS offset */ -#define R_386_TLS_TPOFF32 37 /* GOT entry of -ve static TLS offset */ - -#define R_386_COUNT 38 /* Count of defined relocation types. */ - -#define R_PPC_NONE 0 /* No relocation. */ -#define R_PPC_ADDR32 1 -#define R_PPC_ADDR24 2 -#define R_PPC_ADDR16 3 -#define R_PPC_ADDR16_LO 4 -#define R_PPC_ADDR16_HI 5 -#define R_PPC_ADDR16_HA 6 -#define R_PPC_ADDR14 7 -#define R_PPC_ADDR14_BRTAKEN 8 -#define R_PPC_ADDR14_BRNTAKEN 9 -#define R_PPC_REL24 10 -#define R_PPC_REL14 11 -#define R_PPC_REL14_BRTAKEN 12 -#define R_PPC_REL14_BRNTAKEN 13 -#define R_PPC_GOT16 14 -#define R_PPC_GOT16_LO 15 -#define R_PPC_GOT16_HI 16 -#define R_PPC_GOT16_HA 17 -#define R_PPC_PLTREL24 18 -#define R_PPC_COPY 19 -#define R_PPC_GLOB_DAT 20 -#define R_PPC_JMP_SLOT 21 -#define R_PPC_RELATIVE 22 -#define R_PPC_LOCAL24PC 23 -#define R_PPC_UADDR32 24 -#define R_PPC_UADDR16 25 -#define R_PPC_REL32 26 -#define R_PPC_PLT32 27 -#define R_PPC_PLTREL32 28 -#define R_PPC_PLT16_LO 29 -#define R_PPC_PLT16_HI 30 -#define R_PPC_PLT16_HA 31 -#define R_PPC_SDAREL16 32 -#define R_PPC_SECTOFF 33 -#define R_PPC_SECTOFF_LO 34 -#define R_PPC_SECTOFF_HI 35 -#define R_PPC_SECTOFF_HA 36 - -#define R_PPC_COUNT 37 /* Count of defined relocation types. */ - -#define R_PPC_TLS 67 -#define R_PPC_DTPMOD32 68 -#define R_PPC_TPREL16 69 -#define R_PPC_TPREL16_LO 70 -#define R_PPC_TPREL16_HI 71 -#define R_PPC_TPREL16_HA 72 -#define R_PPC_TPREL32 73 -#define R_PPC_DTPREL16 74 -#define R_PPC_DTPREL16_LO 75 -#define R_PPC_DTPREL16_HI 76 -#define R_PPC_DTPREL16_HA 77 -#define R_PPC_DTPREL32 78 -#define R_PPC_GOT_TLSGD16 79 -#define R_PPC_GOT_TLSGD16_LO 80 -#define R_PPC_GOT_TLSGD16_HI 81 -#define R_PPC_GOT_TLSGD16_HA 82 -#define R_PPC_GOT_TLSLD16 83 -#define R_PPC_GOT_TLSLD16_LO 84 -#define R_PPC_GOT_TLSLD16_HI 85 -#define R_PPC_GOT_TLSLD16_HA 86 -#define R_PPC_GOT_TPREL16 87 -#define R_PPC_GOT_TPREL16_LO 88 -#define R_PPC_GOT_TPREL16_HI 89 -#define R_PPC_GOT_TPREL16_HA 90 - -#define R_PPC_EMB_NADDR32 101 -#define R_PPC_EMB_NADDR16 102 -#define R_PPC_EMB_NADDR16_LO 103 -#define R_PPC_EMB_NADDR16_HI 104 -#define R_PPC_EMB_NADDR16_HA 105 -#define R_PPC_EMB_SDAI16 106 -#define R_PPC_EMB_SDA2I16 107 -#define R_PPC_EMB_SDA2REL 108 -#define R_PPC_EMB_SDA21 109 -#define R_PPC_EMB_MRKREF 110 -#define R_PPC_EMB_RELSEC16 111 -#define R_PPC_EMB_RELST_LO 112 -#define R_PPC_EMB_RELST_HI 113 -#define R_PPC_EMB_RELST_HA 114 -#define R_PPC_EMB_BIT_FLD 115 -#define R_PPC_EMB_RELSDA 116 - - /* Count of defined relocation types. */ -#define R_PPC_EMB_COUNT (R_PPC_EMB_RELSDA - R_PPC_EMB_NADDR32 + 1) - - -#define R_SPARC_NONE 0 -#define R_SPARC_8 1 -#define R_SPARC_16 2 -#define R_SPARC_32 3 -#define R_SPARC_DISP8 4 -#define R_SPARC_DISP16 5 -#define R_SPARC_DISP32 6 -#define R_SPARC_WDISP30 7 -#define R_SPARC_WDISP22 8 -#define R_SPARC_HI22 9 -#define R_SPARC_22 10 -#define R_SPARC_13 11 -#define R_SPARC_LO10 12 -#define R_SPARC_GOT10 13 -#define R_SPARC_GOT13 14 -#define R_SPARC_GOT22 15 -#define R_SPARC_PC10 16 -#define R_SPARC_PC22 17 -#define R_SPARC_WPLT30 18 -#define R_SPARC_COPY 19 -#define R_SPARC_GLOB_DAT 20 -#define R_SPARC_JMP_SLOT 21 -#define R_SPARC_RELATIVE 22 -#define R_SPARC_UA32 23 -#define R_SPARC_PLT32 24 -#define R_SPARC_HIPLT22 25 -#define R_SPARC_LOPLT10 26 -#define R_SPARC_PCPLT32 27 -#define R_SPARC_PCPLT22 28 -#define R_SPARC_PCPLT10 29 -#define R_SPARC_10 30 -#define R_SPARC_11 31 -#define R_SPARC_64 32 -#define R_SPARC_OLO10 33 -#define R_SPARC_HH22 34 -#define R_SPARC_HM10 35 -#define R_SPARC_LM22 36 -#define R_SPARC_PC_HH22 37 -#define R_SPARC_PC_HM10 38 -#define R_SPARC_PC_LM22 39 -#define R_SPARC_WDISP16 40 -#define R_SPARC_WDISP19 41 -#define R_SPARC_GLOB_JMP 42 -#define R_SPARC_7 43 -#define R_SPARC_5 44 -#define R_SPARC_6 45 -#define R_SPARC_DISP64 46 -#define R_SPARC_PLT64 47 -#define R_SPARC_HIX22 48 -#define R_SPARC_LOX10 49 -#define R_SPARC_H44 50 -#define R_SPARC_M44 51 -#define R_SPARC_L44 52 -#define R_SPARC_REGISTER 53 -#define R_SPARC_UA64 54 -#define R_SPARC_UA16 55 - - -/* - * Magic number for the elf trampoline, chosen wisely to be an immediate - * value. - */ -#define ARM_MAGIC_TRAMP_NUMBER 0x5c000003 - - -/* - * Symbol table entries. - */ - -typedef struct { - Elf32_Word name; /* String table index of name. */ - Elf32_Addr value; /* Symbol value. */ - Elf32_Word size; /* Size of associated object. */ - unsigned char info; /* Type and binding information. */ - unsigned char other; /* Reserved (not used). */ - Elf32_Half shndx; /* Section index of symbol. */ -} Elf32_Sym; - -/* Macros for accessing the fields of st_info. */ -#define ELF32_ST_BIND(info) ((info) >> 4) -#define ELF32_ST_TYPE(info) ((info) & 0xf) - -/* Macro for constructing st_info from field values. */ -#define ELF32_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xf)) - -/* Macro for accessing the fields of st_other. */ -#define ELF32_ST_VISIBILITY(oth) ((oth) & 0x3) - -/* - * ELF definitions common to all 64-bit architectures. - */ - -typedef uint64 Elf64_Addr; -typedef uint16 Elf64_Half; -typedef uint64 Elf64_Off; -typedef int32 Elf64_Sword; -typedef int64 Elf64_Sxword; -typedef uint32 Elf64_Word; -typedef uint64 Elf64_Xword; - -/* - * Types of dynamic symbol hash table bucket and chain elements. - * - * This is inconsistent among 64 bit architectures, so a machine dependent - * typedef is required. - */ - -#ifdef __alpha__ -typedef Elf64_Off Elf64_Hashelt; -#else -typedef Elf64_Word Elf64_Hashelt; -#endif - -/* Non-standard class-dependent datatype used for abstraction. */ -typedef Elf64_Xword Elf64_Size; -typedef Elf64_Sxword Elf64_Ssize; - -/* - * ELF header. - */ - -typedef struct { - unsigned char ident[EI_NIDENT]; /* File identification. */ - Elf64_Half type; /* File type. */ - Elf64_Half machine; /* Machine architecture. */ - Elf64_Word version; /* ELF format version. */ - Elf64_Addr entry; /* Entry point. */ - Elf64_Off phoff; /* Program header file offset. */ - Elf64_Off shoff; /* Section header file offset. */ - Elf64_Word flags; /* Architecture-specific flags. */ - Elf64_Half ehsize; /* Size of ELF header in bytes. */ - Elf64_Half phentsize; /* Size of program header entry. */ - Elf64_Half phnum; /* Number of program header entries. */ - Elf64_Half shentsize; /* Size of section header entry. */ - Elf64_Half shnum; /* Number of section header entries. */ - Elf64_Half shstrndx; /* Section name strings section. */ -} Elf64_Ehdr; - -/* - * Section header. - */ - -typedef struct { - Elf64_Word name; /* Section name (index into the - section header string table). */ - Elf64_Word type; /* Section type. */ - Elf64_Xword flags; /* Section flags. */ - Elf64_Addr addr; /* Address in memory image. */ - Elf64_Off off; /* Offset in file. */ - Elf64_Xword size; /* Size in bytes. */ - Elf64_Word link; /* Index of a related section. */ - Elf64_Word info; /* Depends on section type. */ - Elf64_Xword addralign; /* Alignment in bytes. */ - Elf64_Xword entsize; /* Size of each entry in section. */ -} Elf64_Shdr; - -/* - * Program header. - */ - -typedef struct { - Elf64_Word type; /* Entry type. */ - Elf64_Word flags; /* Access permission flags. */ - Elf64_Off off; /* File offset of contents. */ - Elf64_Addr vaddr; /* Virtual address in memory image. */ - Elf64_Addr paddr; /* Physical address (not used). */ - Elf64_Xword filesz; /* Size of contents in file. */ - Elf64_Xword memsz; /* Size of contents in memory. */ - Elf64_Xword align; /* Alignment in memory and file. */ -} Elf64_Phdr; - -/* - * Dynamic structure. The ".dynamic" section contains an array of them. - */ - -typedef struct { - Elf64_Sxword d_tag; /* Entry type. */ - union { - Elf64_Xword d_val; /* Integer value. */ - Elf64_Addr d_ptr; /* Address value. */ - } d_un; -} Elf64_Dyn; - -/* - * Relocation entries. - */ - -/* Relocations that don't need an addend field. */ -typedef struct { - Elf64_Addr off; /* Location to be relocated. */ - Elf64_Xword info; /* Relocation type and symbol index. */ -} Elf64_Rel; - -/* Relocations that need an addend field. */ -typedef struct { - Elf64_Addr off; /* Location to be relocated. */ - Elf64_Xword info; /* Relocation type and symbol index. */ - Elf64_Sxword addend; /* Addend. */ -} Elf64_Rela; - -/* Macros for accessing the fields of r_info. */ -#define ELF64_R_SYM(info) ((info) >> 32) -#define ELF64_R_TYPE(info) ((info) & 0xffffffffL) - -/* Macro for constructing r_info from field values. */ -#define ELF64_R_INFO(sym, type) ((((uint64)(sym)) << 32) + (((uint64)(type)) & 0xffffffffULL)) - -/* - * Symbol table entries. - */ - -typedef struct { - Elf64_Word name; /* String table index of name. */ - unsigned char info; /* Type and binding information. */ - unsigned char other; /* Reserved (not used). */ - Elf64_Half shndx; /* Section index of symbol. */ - Elf64_Addr value; /* Symbol value. */ - Elf64_Xword size; /* Size of associated object. */ -} Elf64_Sym; - -/* Macros for accessing the fields of st_info. */ -#define ELF64_ST_BIND(info) ((info) >> 4) -#define ELF64_ST_TYPE(info) ((info) & 0xf) - -/* Macro for constructing st_info from field values. */ -#define ELF64_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xf)) - -/* Macro for accessing the fields of st_other. */ -#define ELF64_ST_VISIBILITY(oth) ((oth) & 0x3) - -/* - * Go linker interface - */ - -#define ELF64HDRSIZE 64 -#define ELF64PHDRSIZE 56 -#define ELF64SHDRSIZE 64 -#define ELF64RELSIZE 16 -#define ELF64RELASIZE 24 -#define ELF64SYMSIZE sizeof(Elf64_Sym) - -#define ELF32HDRSIZE sizeof(Elf32_Ehdr) -#define ELF32PHDRSIZE sizeof(Elf32_Phdr) -#define ELF32SHDRSIZE sizeof(Elf32_Shdr) -#define ELF32SYMSIZE sizeof(Elf32_Sym) -#define ELF32RELSIZE 8 - -/* - * The interface uses the 64-bit structures always, - * to avoid code duplication. The writers know how to - * marshal a 32-bit representation from the 64-bit structure. - */ -typedef Elf64_Ehdr ElfEhdr; -typedef Elf64_Shdr ElfShdr; -typedef Elf64_Phdr ElfPhdr; - -void elfinit(void); -ElfEhdr *getElfEhdr(void); -ElfShdr *newElfShstrtab(vlong); -ElfShdr *newElfShdr(vlong); -ElfPhdr *newElfPhdr(void); -uint32 elfwritehdr(void); -uint32 elfwritephdrs(void); -uint32 elfwriteshdrs(void); -void elfwritedynent(Sym*, int, uint64); -void elfwritedynentsym(Sym*, int, Sym*); -void elfwritedynentsymsize(Sym*, int, Sym*); -uint32 elfhash(uchar*); -uint64 startelf(void); -uint64 endelf(void); -extern int numelfphdr; -extern int numelfshdr; -extern int iself; -extern int elfverneed; -int elfwriteinterp(void); -void elfinterp(ElfShdr*, uint64, char*); -void elfdynhash(void); -ElfPhdr* elfphload(Segment*); -ElfShdr* elfshbits(Section*); -void elfsetstring(char*, int); -void elfaddverneed(Sym*); - -EXTERN int elfstrsize; -EXTERN char* elfstrdat; -EXTERN int elftextsh; - -/* - * Total amount of space to reserve at the start of the file - * for Header, PHeaders, SHeaders, and interp. - * May waste some. - * On FreeBSD, cannot be larger than a page. - */ -#define ELFRESERVE 3072 diff --git a/src/cmd/ld/go.c b/src/cmd/ld/go.c deleted file mode 100644 index 05d1cc136..000000000 --- a/src/cmd/ld/go.c +++ /dev/null @@ -1,710 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// go-specific code shared across loaders (5l, 6l, 8l). - -#include "l.h" -#include "../ld/lib.h" - -// accumulate all type information from .6 files. -// check for inconsistencies. - -// TODO: -// generate debugging section in binary. -// once the dust settles, try to move some code to -// libmach, so that other linkers and ar can share. - -/* - * package import data - */ -typedef struct Import Import; -struct Import -{ - Import *hash; // next in hash table - char *prefix; // "type", "var", "func", "const" - char *name; - char *def; - char *file; -}; -enum { - NIHASH = 1024 -}; -static Import *ihash[NIHASH]; -static int nimport; - -static int -hashstr(char *name) -{ - int h; - char *cp; - - h = 0; - for(cp = name; *cp; h += *cp++) - h *= 1119; - // not if(h < 0) h = ~h, because gcc 4.3 -O2 miscompiles it. - h &= 0xffffff; - return h; -} - -static Import * -ilookup(char *name) -{ - int h; - Import *x; - - h = hashstr(name) % NIHASH; - for(x=ihash[h]; x; x=x->hash) - if(x->name[0] == name[0] && strcmp(x->name, name) == 0) - return x; - x = mal(sizeof *x); - x->name = strdup(name); - x->hash = ihash[h]; - ihash[h] = x; - nimport++; - return x; -} - -static void loadpkgdata(char*, char*, char*, int); -static void loaddynimport(char*, char*, char*, int); -static void loaddynexport(char*, char*, char*, int); -static int parsemethod(char**, char*, char**); -static int parsepkgdata(char*, char*, char**, char*, char**, char**, char**); - -static Sym **dynexp; - -void -ldpkg(Biobuf *f, char *pkg, int64 len, char *filename, int whence) -{ - char *data, *p0, *p1, *name; - - if(debug['g']) - return; - - if((int)len != len) { - fprint(2, "%s: too much pkg data in %s\n", argv0, filename); - if(debug['u']) - errorexit(); - return; - } - data = mal(len+1); - if(Bread(f, data, len) != len) { - fprint(2, "%s: short pkg read %s\n", argv0, filename); - if(debug['u']) - errorexit(); - return; - } - data[len] = '\0'; - - // first \n$$ marks beginning of exports - skip rest of line - p0 = strstr(data, "\n$$"); - if(p0 == nil) { - if(debug['u'] && whence != ArchiveObj) { - fprint(2, "%s: cannot find export data in %s\n", argv0, filename); - errorexit(); - } - return; - } - p0 += 3; - while(*p0 != '\n' && *p0 != '\0') - p0++; - - // second marks end of exports / beginning of local data - p1 = strstr(p0, "\n$$"); - if(p1 == nil) { - fprint(2, "%s: cannot find end of exports in %s\n", argv0, filename); - if(debug['u']) - errorexit(); - return; - } - while(p0 < p1 && (*p0 == ' ' || *p0 == '\t' || *p0 == '\n')) - p0++; - if(p0 < p1) { - if(strncmp(p0, "package ", 8) != 0) { - fprint(2, "%s: bad package section in %s - %s\n", argv0, filename, p0); - if(debug['u']) - errorexit(); - return; - } - p0 += 8; - while(p0 < p1 && (*p0 == ' ' || *p0 == '\t' || *p0 == '\n')) - p0++; - name = p0; - while(p0 < p1 && *p0 != ' ' && *p0 != '\t' && *p0 != '\n') - p0++; - if(debug['u'] && whence != ArchiveObj && - (p0+6 > p1 || memcmp(p0, " safe\n", 6) != 0)) { - fprint(2, "%s: load of unsafe package %s\n", argv0, filename); - nerrors++; - errorexit(); - } - if(p0 < p1) { - if(*p0 == '\n') - *p0++ = '\0'; - else { - *p0++ = '\0'; - while(p0 < p1 && *p0++ != '\n') - ; - } - } - if(strcmp(pkg, "main") == 0 && strcmp(name, "main") != 0) - fprint(2, "%s: %s: not package main (package %s)\n", argv0, filename, name); - loadpkgdata(filename, pkg, p0, p1 - p0); - } - - // The __.PKGDEF archive summary has no local types. - if(whence == Pkgdef) - return; - - // local types begin where exports end. - // skip rest of line after $$ we found above - p0 = p1 + 3; - while(*p0 != '\n' && *p0 != '\0') - p0++; - - // local types end at next \n$$. - p1 = strstr(p0, "\n$$"); - if(p1 == nil) { - fprint(2, "%s: cannot find end of local types in %s\n", argv0, filename); - if(debug['u']) - errorexit(); - return; - } - - loadpkgdata(filename, pkg, p0, p1 - p0); - - // look for dynimport section - p0 = strstr(p1, "\n$$ // dynimport"); - if(p0 != nil) { - p0 = strchr(p0+1, '\n'); - if(p0 == nil) { - fprint(2, "%s: found $$ // dynimport but no newline in %s\n", argv0, filename); - if(debug['u']) - errorexit(); - return; - } - p1 = strstr(p0, "\n$$"); - if(p1 == nil) - p1 = strstr(p0, "\n!\n"); - if(p1 == nil) { - fprint(2, "%s: cannot find end of // dynimport section in %s\n", argv0, filename); - if(debug['u']) - errorexit(); - return; - } - loaddynimport(filename, pkg, p0 + 1, p1 - (p0+1)); - } - - // look for dynexp section - p0 = strstr(p1, "\n$$ // dynexport"); - if(p0 != nil) { - p0 = strchr(p0+1, '\n'); - if(p0 == nil) { - fprint(2, "%s: found $$ // dynexporg but no newline in %s\n", argv0, filename); - if(debug['u']) - errorexit(); - return; - } - p1 = strstr(p0, "\n$$"); - if(p1 == nil) - p1 = strstr(p0, "\n!\n"); - if(p1 == nil) { - fprint(2, "%s: cannot find end of // dynexporg section in %s\n", argv0, filename); - if(debug['u']) - errorexit(); - return; - } - loaddynexport(filename, pkg, p0 + 1, p1 - (p0+1)); - } -} - -static void -loadpkgdata(char *file, char *pkg, char *data, int len) -{ - char *p, *ep, *prefix, *name, *def; - Import *x; - - file = strdup(file); - p = data; - ep = data + len; - while(parsepkgdata(file, pkg, &p, ep, &prefix, &name, &def) > 0) { - x = ilookup(name); - if(x->prefix == nil) { - x->prefix = prefix; - x->def = def; - x->file = file; - } else if(strcmp(x->prefix, prefix) != 0) { - fprint(2, "%s: conflicting definitions for %s\n", argv0, name); - fprint(2, "%s:\t%s %s ...\n", x->file, x->prefix, name); - fprint(2, "%s:\t%s %s ...\n", file, prefix, name); - nerrors++; - } else if(strcmp(x->def, def) != 0) { - fprint(2, "%s: conflicting definitions for %s\n", argv0, name); - fprint(2, "%s:\t%s %s %s\n", x->file, x->prefix, name, x->def); - fprint(2, "%s:\t%s %s %s\n", file, prefix, name, def); - nerrors++; - } - } -} - -// replace all "". with pkg. -char* -expandpkg(char *t0, char *pkg) -{ - int n; - char *p; - char *w, *w0, *t; - - n = 0; - for(p=t0; (p=strstr(p, "\"\".")) != nil; p+=3) - n++; - - if(n == 0) - return t0; - - // use malloc, not mal, so that caller can free - w0 = malloc(strlen(t0) + strlen(pkg)*n); - if(w0 == nil) { - diag("out of memory"); - errorexit(); - } - w = w0; - for(p=t=t0; (p=strstr(p, "\"\".")) != nil; p=t) { - memmove(w, t, p - t); - w += p-t; - strcpy(w, pkg); - w += strlen(pkg); - t = p+2; - } - strcpy(w, t); - return w0; -} - -static int -parsepkgdata(char *file, char *pkg, char **pp, char *ep, char **prefixp, char **namep, char **defp) -{ - char *p, *prefix, *name, *def, *edef, *meth; - int n, inquote; - - // skip white space - p = *pp; -loop: - while(p < ep && (*p == ' ' || *p == '\t' || *p == '\n')) - p++; - if(p == ep || strncmp(p, "$$\n", 3) == 0) - return 0; - - // prefix: (var|type|func|const) - prefix = p; - if(p + 7 > ep) - return -1; - if(strncmp(p, "var ", 4) == 0) - p += 4; - else if(strncmp(p, "type ", 5) == 0) - p += 5; - else if(strncmp(p, "func ", 5) == 0) - p += 5; - else if(strncmp(p, "const ", 6) == 0) - p += 6; - else if(strncmp(p, "import ", 7) == 0) { - p += 7; - while(p < ep && *p != '\n') - p++; - goto loop; - } - else { - fprint(2, "%s: confused in pkg data near <<%.40s>>\n", argv0, prefix); - nerrors++; - return -1; - } - p[-1] = '\0'; - - // name: a.b followed by space - name = p; - inquote = 0; - while(p < ep) { - if (*p == ' ' && !inquote) - break; - - if(*p == '\\') - p++; - else if(*p == '"') - inquote = !inquote; - - p++; - } - - if(p >= ep) - return -1; - *p++ = '\0'; - - // def: free form to new line - def = p; - while(p < ep && *p != '\n') - p++; - if(p >= ep) - return -1; - edef = p; - *p++ = '\0'; - - // include methods on successive lines in def of named type - while(parsemethod(&p, ep, &meth) > 0) { - *edef++ = '\n'; // overwrites '\0' - if(edef+1 > meth) { - // We want to indent methods with a single \t. - // 6g puts at least one char of indent before all method defs, - // so there will be room for the \t. If the method def wasn't - // indented we could do something more complicated, - // but for now just diagnose the problem and assume - // 6g will keep indenting for us. - fprint(2, "%s: %s: expected methods to be indented %p %p %.10s\n", argv0, - file, edef, meth, meth); - nerrors++; - return -1; - } - *edef++ = '\t'; - n = strlen(meth); - memmove(edef, meth, n); - edef += n; - } - - name = expandpkg(name, pkg); - def = expandpkg(def, pkg); - - // done - *pp = p; - *prefixp = prefix; - *namep = name; - *defp = def; - return 1; -} - -static int -parsemethod(char **pp, char *ep, char **methp) -{ - char *p; - - // skip white space - p = *pp; - while(p < ep && (*p == ' ' || *p == '\t')) - p++; - if(p == ep) - return 0; - - // if it says "func (", it's a method - if(p + 6 >= ep || strncmp(p, "func (", 6) != 0) - return 0; - - // definition to end of line - *methp = p; - while(p < ep && *p != '\n') - p++; - if(p >= ep) { - fprint(2, "%s: lost end of line in method definition\n", argv0); - *pp = ep; - return -1; - } - *p++ = '\0'; - *pp = p; - return 1; -} - -static void -loaddynimport(char *file, char *pkg, char *p, int n) -{ - char *pend, *next, *name, *def, *p0, *lib, *q; - Sym *s; - - USED(file); - pend = p + n; - for(; p<pend; p=next) { - next = strchr(p, '\n'); - if(next == nil) - next = ""; - else - *next++ = '\0'; - p0 = p; - if(strncmp(p, "dynimport ", 10) != 0) - goto err; - p += 10; - name = p; - p = strchr(name, ' '); - if(p == nil) - goto err; - while(*p == ' ') - p++; - def = p; - p = strchr(def, ' '); - if(p == nil) - goto err; - while(*p == ' ') - p++; - lib = p; - - // successful parse: now can edit the line - *strchr(name, ' ') = 0; - *strchr(def, ' ') = 0; - - if(debug['d']) { - fprint(2, "%s: %s: cannot use dynamic imports with -d flag\n", argv0, file); - nerrors++; - return; - } - - if(strcmp(name, "_") == 0 && strcmp(def, "_") == 0) { - // allow #pragma dynimport _ _ "foo.so" - // to force a link of foo.so. - havedynamic = 1; - adddynlib(lib); - continue; - } - - name = expandpkg(name, pkg); - q = strchr(def, '@'); - if(q) - *q++ = '\0'; - s = lookup(name, 0); - if(s->type == 0 || s->type == SXREF) { - s->dynimplib = lib; - s->dynimpname = def; - s->dynimpvers = q; - s->type = SDYNIMPORT; - havedynamic = 1; - } - } - return; - -err: - fprint(2, "%s: %s: invalid dynimport line: %s\n", argv0, file, p0); - nerrors++; -} - -static void -loaddynexport(char *file, char *pkg, char *p, int n) -{ - char *pend, *next, *local, *elocal, *remote, *p0; - Sym *s; - - USED(file); - pend = p + n; - for(; p<pend; p=next) { - next = strchr(p, '\n'); - if(next == nil) - next = ""; - else - *next++ = '\0'; - p0 = p; - if(strncmp(p, "dynexport ", 10) != 0) - goto err; - p += 10; - local = p; - p = strchr(local, ' '); - if(p == nil) - goto err; - while(*p == ' ') - p++; - remote = p; - - // successful parse: now can edit the line - *strchr(local, ' ') = 0; - - elocal = expandpkg(local, pkg); - - s = lookup(elocal, 0); - if(s->dynimplib != nil) { - fprint(2, "%s: symbol is both dynimport and dynexport %s\n", argv0, local); - nerrors++; - } - s->dynimpname = remote; - s->dynexport = 1; - - if(ndynexp%32 == 0) - dynexp = realloc(dynexp, (ndynexp+32)*sizeof dynexp[0]); - dynexp[ndynexp++] = s; - - if (elocal != local) - free(elocal); - } - return; - -err: - fprint(2, "%s: invalid dynexport line: %s\n", argv0, p0); - nerrors++; -} - -static int markdepth; - -static void -marktext(Sym *s) -{ - Auto *a; - Prog *p; - - if(s == S) - return; - markdepth++; - if(debug['v'] > 1) - Bprint(&bso, "%d marktext %s\n", markdepth, s->name); - for(a=s->autom; a; a=a->link) - mark(a->gotype); - for(p=s->text; p != P; p=p->link) { - if(p->from.sym) - mark(p->from.sym); - if(p->to.sym) - mark(p->to.sym); - } - markdepth--; -} - -void -mark(Sym *s) -{ - int i; - - if(s == S || s->reachable) - return; - if(strncmp(s->name, "weak.", 5) == 0) - return; - s->reachable = 1; - if(s->text) - marktext(s); - for(i=0; i<s->nr; i++) - mark(s->r[i].sym); - if(s->gotype) - mark(s->gotype); - if(s->sub) - mark(s->sub); - if(s->outer) - mark(s->outer); -} - -static char* -morename[] = -{ - "runtime.morestack", - "runtime.morestackx", - - "runtime.morestack00", - "runtime.morestack10", - "runtime.morestack01", - "runtime.morestack11", - - "runtime.morestack8", - "runtime.morestack16", - "runtime.morestack24", - "runtime.morestack32", - "runtime.morestack40", - "runtime.morestack48", -}; - -static int -isz(Auto *a) -{ - for(; a; a=a->link) - if(a->type == D_FILE || a->type == D_FILE1) - return 1; - return 0; -} - -static void -addz(Sym *s, Auto *z) -{ - Auto *a, *last; - - // strip out non-z - last = nil; - for(a = z; a != nil; a = a->link) { - if(a->type == D_FILE || a->type == D_FILE1) { - if(last == nil) - z = a; - else - last->link = a; - last = a; - } - } - if(last) { - last->link = s->autom; - s->autom = z; - } -} - -void -deadcode(void) -{ - int i; - Sym *s, *last; - Auto *z; - - if(debug['v']) - Bprint(&bso, "%5.2f deadcode\n", cputime()); - - mark(lookup(INITENTRY, 0)); - for(i=0; i<nelem(morename); i++) - mark(lookup(morename[i], 0)); - - for(i=0; i<ndynexp; i++) - mark(dynexp[i]); - - // remove dead text but keep file information (z symbols). - last = nil; - z = nil; - for(s = textp; s != nil; s = s->next) { - if(!s->reachable) { - if(isz(s->autom)) - z = s->autom; - continue; - } - if(last == nil) - textp = s; - else - last->next = s; - last = s; - if(z != nil) { - if(!isz(s->autom)) - addz(s, z); - z = nil; - } - } - if(last == nil) - textp = nil; - else - last->next = nil; - - for(s = allsym; s != S; s = s->allsym) - if(strncmp(s->name, "weak.", 5) == 0) { - s->special = 1; // do not lay out in data segment - s->reachable = 1; - s->hide = 1; - } -} - -void -doweak(void) -{ - Sym *s, *t; - - // resolve weak references only if - // target symbol will be in binary anyway. - for(s = allsym; s != S; s = s->allsym) { - if(strncmp(s->name, "weak.", 5) == 0) { - t = rlookup(s->name+5, s->version); - if(t && t->type != 0 && t->reachable) { - s->value = t->value; - s->type = t->type; - } else { - s->type = SCONST; - s->value = 0; - } - continue; - } - } -} - -void -addexport(void) -{ - int i; - - for(i=0; i<ndynexp; i++) - adddynsym(dynexp[i]); -} diff --git a/src/cmd/ld/ldelf.c b/src/cmd/ld/ldelf.c deleted file mode 100644 index 8334e988e..000000000 --- a/src/cmd/ld/ldelf.c +++ /dev/null @@ -1,816 +0,0 @@ -/* -Derived from Plan 9 from User Space's src/libmach/elf.h, elf.c -http://code.swtch.com/plan9port/src/tip/src/libmach/ - - Copyright © 2004 Russ Cox. - Portions Copyright © 2008-2010 Google Inc. - Portions Copyright © 2010 The Go Authors. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -*/ - -#include "l.h" -#include "lib.h" -#include "../ld/elf.h" - -enum -{ - ElfClassNone = 0, - ElfClass32, - ElfClass64, - - ElfDataNone = 0, - ElfDataLsb, - ElfDataMsb, - - ElfTypeNone = 0, - ElfTypeRelocatable, - ElfTypeExecutable, - ElfTypeSharedObject, - ElfTypeCore, - /* 0xFF00 - 0xFFFF reserved for processor-specific types */ - - ElfMachNone = 0, - ElfMach32100, /* AT&T WE 32100 */ - ElfMachSparc, /* SPARC */ - ElfMach386, /* Intel 80386 */ - ElfMach68000, /* Motorola 68000 */ - ElfMach88000, /* Motorola 88000 */ - ElfMach486, /* Intel 80486, no longer used */ - ElfMach860, /* Intel 80860 */ - ElfMachMips, /* MIPS RS3000 */ - ElfMachS370, /* IBM System/370 */ - ElfMachMipsLe, /* MIPS RS3000 LE */ - ElfMachParisc = 15, /* HP PA RISC */ - ElfMachVpp500 = 17, /* Fujitsu VPP500 */ - ElfMachSparc32Plus, /* SPARC V8+ */ - ElfMach960, /* Intel 80960 */ - ElfMachPower, /* PowerPC */ - ElfMachPower64, /* PowerPC 64 */ - ElfMachS390, /* IBM System/390 */ - ElfMachV800 = 36, /* NEC V800 */ - ElfMachFr20, /* Fujitsu FR20 */ - ElfMachRh32, /* TRW RH-32 */ - ElfMachRce, /* Motorola RCE */ - ElfMachArm, /* ARM */ - ElfMachAlpha, /* Digital Alpha */ - ElfMachSH, /* Hitachi SH */ - ElfMachSparc9, /* SPARC V9 */ - ElfMachAmd64 = 62, - /* and the list goes on... */ - - ElfAbiNone = 0, - ElfAbiSystemV = 0, /* [sic] */ - ElfAbiHPUX, - ElfAbiNetBSD, - ElfAbiLinux, - ElfAbiSolaris = 6, - ElfAbiAix, - ElfAbiIrix, - ElfAbiFreeBSD, - ElfAbiTru64, - ElfAbiModesto, - ElfAbiOpenBSD, - ElfAbiARM = 97, - ElfAbiEmbedded = 255, - - /* some of sections 0xFF00 - 0xFFFF reserved for various things */ - ElfSectNone = 0, - ElfSectProgbits, - ElfSectSymtab, - ElfSectStrtab, - ElfSectRela, - ElfSectHash, - ElfSectDynamic, - ElfSectNote, - ElfSectNobits, - ElfSectRel, - ElfSectShlib, - ElfSectDynsym, - - ElfSectFlagWrite = 0x1, - ElfSectFlagAlloc = 0x2, - ElfSectFlagExec = 0x4, - /* 0xF0000000 are reserved for processor specific */ - - ElfSymBindLocal = 0, - ElfSymBindGlobal, - ElfSymBindWeak, - /* 13-15 reserved */ - - ElfSymTypeNone = 0, - ElfSymTypeObject, - ElfSymTypeFunc, - ElfSymTypeSection, - ElfSymTypeFile, - /* 13-15 reserved */ - - ElfSymShnNone = 0, - ElfSymShnAbs = 0xFFF1, - ElfSymShnCommon = 0xFFF2, - /* 0xFF00-0xFF1F reserved for processors */ - /* 0xFF20-0xFF3F reserved for operating systems */ - - ElfProgNone = 0, - ElfProgLoad, - ElfProgDynamic, - ElfProgInterp, - ElfProgNote, - ElfProgShlib, - ElfProgPhdr, - - ElfProgFlagExec = 0x1, - ElfProgFlagWrite = 0x2, - ElfProgFlagRead = 0x4, - - ElfNotePrStatus = 1, - ElfNotePrFpreg = 2, - ElfNotePrPsinfo = 3, - ElfNotePrTaskstruct = 4, - ElfNotePrAuxv = 6, - ElfNotePrXfpreg = 0x46e62b7f /* for gdb/386 */ -}; - -typedef struct ElfHdrBytes ElfHdrBytes; -typedef struct ElfSectBytes ElfSectBytes; -typedef struct ElfProgBytes ElfProgBytes; -typedef struct ElfSymBytes ElfSymBytes; - -typedef struct ElfHdrBytes64 ElfHdrBytes64; -typedef struct ElfSectBytes64 ElfSectBytes64; -typedef struct ElfProgBytes64 ElfProgBytes64; -typedef struct ElfSymBytes64 ElfSymBytes64; - -struct ElfHdrBytes -{ - uchar ident[16]; - uchar type[2]; - uchar machine[2]; - uchar version[4]; - uchar entry[4]; - uchar phoff[4]; - uchar shoff[4]; - uchar flags[4]; - uchar ehsize[2]; - uchar phentsize[2]; - uchar phnum[2]; - uchar shentsize[2]; - uchar shnum[2]; - uchar shstrndx[2]; -}; - -struct ElfHdrBytes64 -{ - uchar ident[16]; - uchar type[2]; - uchar machine[2]; - uchar version[4]; - uchar entry[8]; - uchar phoff[8]; - uchar shoff[8]; - uchar flags[4]; - uchar ehsize[2]; - uchar phentsize[2]; - uchar phnum[2]; - uchar shentsize[2]; - uchar shnum[2]; - uchar shstrndx[2]; -}; - -struct ElfSectBytes -{ - uchar name[4]; - uchar type[4]; - uchar flags[4]; - uchar addr[4]; - uchar off[4]; - uchar size[4]; - uchar link[4]; - uchar info[4]; - uchar align[4]; - uchar entsize[4]; -}; - -struct ElfSectBytes64 -{ - uchar name[4]; - uchar type[4]; - uchar flags[8]; - uchar addr[8]; - uchar off[8]; - uchar size[8]; - uchar link[4]; - uchar info[4]; - uchar align[8]; - uchar entsize[8]; -}; - -struct ElfSymBytes -{ - uchar name[4]; - uchar value[4]; - uchar size[4]; - uchar info; /* top4: bind, bottom4: type */ - uchar other; - uchar shndx[2]; -}; - -struct ElfSymBytes64 -{ - uchar name[4]; - uchar info; /* top4: bind, bottom4: type */ - uchar other; - uchar shndx[2]; - uchar value[8]; - uchar size[8]; -}; - -typedef struct ElfSect ElfSect; -typedef struct ElfObj ElfObj; -typedef struct ElfSym ElfSym; - -struct ElfSect -{ - char *name; - uint32 type; - uint64 flags; - uint64 addr; - uint64 off; - uint64 size; - uint32 link; - uint32 info; - uint64 align; - uint64 entsize; - uchar *base; - Sym *sym; -}; - -struct ElfObj -{ - Biobuf *f; - int64 base; // offset in f where ELF begins - int64 len; // length of ELF - int is64; - char *name; - - Endian *e; - ElfSect *sect; - uint nsect; - char *shstrtab; - int nsymtab; - ElfSect *symtab; - ElfSect *symstr; - - uint32 type; - uint32 machine; - uint32 version; - uint64 entry; - uint64 phoff; - uint64 shoff; - uint32 flags; - uint32 ehsize; - uint32 phentsize; - uint32 phnum; - uint32 shentsize; - uint32 shnum; - uint32 shstrndx; -}; - -struct ElfSym -{ - char* name; - uint64 value; - uint64 size; - uchar bind; - uchar type; - uchar other; - uint16 shndx; - Sym* sym; -}; - -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 reltype(char*, int, uchar*); - -void -ldelf(Biobuf *f, char *pkg, int64 len, char *pn) -{ - int32 base; - uint64 add, info; - char *name; - int i, j, rela, is64, n; - uchar hdrbuf[64]; - uchar *p; - ElfHdrBytes *hdr; - ElfObj *obj; - ElfSect *sect, *rsect; - ElfSym sym; - Endian *e; - Reloc *r, *rp; - Sym *s; - - USED(pkg); - if(debug['v']) - Bprint(&bso, "%5.2f ldelf %s\n", cputime(), pn); - - version++; - base = Boffset(f); - - if(Bread(f, hdrbuf, sizeof hdrbuf) != sizeof hdrbuf) - goto bad; - hdr = (ElfHdrBytes*)hdrbuf; - if(memcmp(hdr->ident, ElfMagic, 4) != 0) - goto bad; - switch(hdr->ident[5]) { - case ElfDataLsb: - e = ≤ - break; - case ElfDataMsb: - e = &be; - break; - default: - goto bad; - } - - // read header - obj = mal(sizeof *obj); - obj->e = e; - obj->f = f; - obj->base = base; - obj->len = len; - obj->name = pn; - - is64 = 0; - if(hdr->ident[4] == ElfClass64) { - ElfHdrBytes64* hdr; - - is64 = 1; - hdr = (ElfHdrBytes64*)hdrbuf; - obj->type = e->e16(hdr->type); - obj->machine = e->e16(hdr->machine); - obj->version = e->e32(hdr->version); - obj->phoff = e->e64(hdr->phoff); - obj->shoff = e->e64(hdr->shoff); - obj->flags = e->e32(hdr->flags); - obj->ehsize = e->e16(hdr->ehsize); - obj->phentsize = e->e16(hdr->phentsize); - obj->phnum = e->e16(hdr->phnum); - obj->shentsize = e->e16(hdr->shentsize); - obj->shnum = e->e16(hdr->shnum); - obj->shstrndx = e->e16(hdr->shstrndx); - } else { - obj->type = e->e16(hdr->type); - obj->machine = e->e16(hdr->machine); - obj->version = e->e32(hdr->version); - obj->entry = e->e32(hdr->entry); - obj->phoff = e->e32(hdr->phoff); - obj->shoff = e->e32(hdr->shoff); - obj->flags = e->e32(hdr->flags); - obj->ehsize = e->e16(hdr->ehsize); - obj->phentsize = e->e16(hdr->phentsize); - obj->phnum = e->e16(hdr->phnum); - obj->shentsize = e->e16(hdr->shentsize); - obj->shnum = e->e16(hdr->shnum); - obj->shstrndx = e->e16(hdr->shstrndx); - } - obj->is64 = is64; - - if(hdr->ident[6] != obj->version) - goto bad; - - if(e->e16(hdr->type) != ElfTypeRelocatable) { - diag("%s: elf but not elf relocatable object"); - return; - } - - switch(thechar) { - default: - diag("%s: elf %s unimplemented", thestring); - return; - case '5': - if(e != &le || obj->machine != ElfMachArm || hdr->ident[4] != ElfClass32) { - diag("%s: elf object but not arm", pn); - return; - } - break; - case '6': - if(e != &le || obj->machine != ElfMachAmd64 || hdr->ident[4] != ElfClass64) { - diag("%s: elf object but not amd64", pn); - return; - } - break; - case '8': - if(e != &le || obj->machine != ElfMach386 || hdr->ident[4] != ElfClass32) { - diag("%s: elf object but not 386", pn); - return; - } - break; - } - - // load section list into memory. - obj->sect = mal(obj->shnum*sizeof obj->sect[0]); - obj->nsect = obj->shnum; - for(i=0; i<obj->nsect; i++) { - if(Bseek(f, base+obj->shoff+i*obj->shentsize, 0) < 0) - goto bad; - sect = &obj->sect[i]; - if(is64) { - ElfSectBytes64 b; - - werrstr("short read"); - if(Bread(f, &b, sizeof b) != sizeof b) - goto bad; - - sect->name = (char*)(uintptr)e->e32(b.name); - sect->type = e->e32(b.type); - sect->flags = e->e64(b.flags); - sect->addr = e->e64(b.addr); - sect->off = e->e64(b.off); - sect->size = e->e64(b.size); - sect->link = e->e32(b.link); - sect->info = e->e32(b.info); - sect->align = e->e64(b.align); - sect->entsize = e->e64(b.entsize); - } else { - ElfSectBytes b; - - werrstr("short read"); - if(Bread(f, &b, sizeof b) != sizeof b) - goto bad; - - sect->name = (char*)(uintptr)e->e32(b.name); - sect->type = e->e32(b.type); - sect->flags = e->e32(b.flags); - sect->addr = e->e32(b.addr); - sect->off = e->e32(b.off); - sect->size = e->e32(b.size); - sect->link = e->e32(b.link); - sect->info = e->e32(b.info); - sect->align = e->e32(b.align); - sect->entsize = e->e32(b.entsize); - } - } - - // read section string table and translate names - if(obj->shstrndx >= obj->nsect) { - werrstr("shstrndx out of range %d >= %d", obj->shstrndx, obj->nsect); - goto bad; - } - sect = &obj->sect[obj->shstrndx]; - if(map(obj, sect) < 0) - goto bad; - for(i=0; i<obj->nsect; i++) - if(obj->sect[i].name != nil) - obj->sect[i].name = (char*)sect->base + (uintptr)obj->sect[i].name; - - // load string table for symbols into memory. - obj->symtab = section(obj, ".symtab"); - if(obj->symtab == nil) { - // our work is done here - no symbols means nothing can refer to this file - return; - } - if(obj->symtab->link <= 0 || obj->symtab->link >= obj->nsect) { - diag("%s: elf object has symbol table with invalid string table link", pn); - return; - } - obj->symstr = &obj->sect[obj->symtab->link]; - if(is64) - obj->nsymtab = obj->symtab->size / sizeof(ElfSymBytes64); - else - obj->nsymtab = obj->symtab->size / sizeof(ElfSymBytes); - - if(map(obj, obj->symtab) < 0) - goto bad; - if(map(obj, obj->symstr) < 0) - goto bad; - - // load text and data segments into memory. - // they are not as small as the section lists, but we'll need - // the memory anyway for the symbol images, so we might - // as well use one large chunk. - - // create symbols for mapped sections - for(i=0; i<obj->nsect; i++) { - sect = &obj->sect[i]; - if((sect->type != ElfSectProgbits && sect->type != ElfSectNobits) || !(sect->flags&ElfSectFlagAlloc)) - continue; - if(sect->type != ElfSectNobits && map(obj, sect) < 0) - goto bad; - - name = smprint("%s(%s)", pn, sect->name); - s = lookup(name, version); - free(name); - switch((int)sect->flags&(ElfSectFlagAlloc|ElfSectFlagWrite|ElfSectFlagExec)) { - default: - werrstr("unexpected flags for ELF section %s", sect->name); - goto bad; - case ElfSectFlagAlloc: - s->type = SRODATA; - break; - case ElfSectFlagAlloc + ElfSectFlagWrite: - s->type = SDATA; - break; - case ElfSectFlagAlloc + ElfSectFlagExec: - s->type = STEXT; - break; - } - if(sect->type == ElfSectProgbits) { - s->p = sect->base; - s->np = sect->size; - } - s->size = sect->size; - if(s->type == STEXT) { - if(etextp) - etextp->next = s; - else - textp = s; - etextp = s; - } - sect->sym = s; - } - - // load relocations - for(i=0; i<obj->nsect; i++) { - rsect = &obj->sect[i]; - if(rsect->type != ElfSectRela && rsect->type != ElfSectRel) - continue; - if(rsect->info >= obj->nsect || obj->sect[rsect->info].base == nil) - continue; - sect = &obj->sect[rsect->info]; - if(map(obj, rsect) < 0) - goto bad; - rela = rsect->type == ElfSectRela; - n = rsect->size/(4+4*is64)/(2+rela); - r = mal(n*sizeof r[0]); - p = rsect->base; - for(j=0; j<n; j++) { - add = 0; - rp = &r[j]; - if(is64) { - // 64-bit rel/rela - rp->off = e->e64(p); - p += 8; - info = e->e64(p); - p += 8; - if(rela) { - add = e->e64(p); - p += 8; - } - } else { - // 32-bit rel/rela - rp->off = e->e32(p); - p += 4; - info = e->e32(p); - info = info>>8<<32 | (info&0xff); // convert to 64-bit info - p += 4; - if(rela) { - add = e->e32(p); - p += 4; - } - } - if(readsym(obj, info>>32, &sym) < 0) - goto bad; - 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); - goto bad; - } - rp->sym = sym.sym; - rp->type = reltype(pn, (uint32)info, &rp->siz); - if(rela) - rp->add = add; - else { - // load addend from image - if(rp->siz == 4) - rp->add = e->e32(sect->base+rp->off); - else if(rp->siz == 8) - rp->add = e->e64(sect->base+rp->off); - else - diag("invalid rela size %d", rp->siz); - } - } - qsort(r, n, sizeof r[0], rbyoff); // just in case - - s = sect->sym; - s->r = r; - s->nr = n; - } - - // 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; - 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); -} - -static ElfSect* -section(ElfObj *obj, char *name) -{ - int i; - - for(i=0; i<obj->nsect; i++) - if(obj->sect[i].name && name && strcmp(obj->sect[i].name, name) == 0) - return &obj->sect[i]; - return nil; -} - -static int -map(ElfObj *obj, ElfSect *sect) -{ - if(sect->base != nil) - return 0; - - if(sect->off+sect->size > obj->len) { - werrstr("elf section past end of file"); - return -1; - } - - sect->base = mal(sect->size); - werrstr("short read"); - if(Bseek(obj->f, obj->base+sect->off, 0) < 0 || Bread(obj->f, sect->base, sect->size) != sect->size) - return -1; - - return 0; -} - -static int -readsym(ElfObj *obj, int i, ElfSym *sym) -{ - Sym *s; - - if(i >= obj->nsymtab || i < 0) { - werrstr("invalid elf symbol index"); - return -1; - } - - if(obj->is64) { - ElfSymBytes64 *b; - - b = (ElfSymBytes64*)(obj->symtab->base + i*sizeof *b); - sym->name = (char*)obj->symstr->base + obj->e->e32(b->name); - sym->value = obj->e->e64(b->value); - sym->size = obj->e->e64(b->size); - sym->shndx = obj->e->e16(b->shndx); - sym->bind = b->info>>4; - sym->type = b->info&0xf; - sym->other = b->other; - } else { - ElfSymBytes *b; - - b = (ElfSymBytes*)(obj->symtab->base + i*sizeof *b); - sym->name = (char*)obj->symstr->base + obj->e->e32(b->name); - sym->value = obj->e->e32(b->value); - sym->size = obj->e->e32(b->size); - sym->shndx = obj->e->e16(b->shndx); - sym->bind = b->info>>4; - sym->type = b->info&0xf; - sym->other = b->other; - } - - 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; - break; - case ElfSymTypeObject: - case ElfSymTypeFunc: - case ElfSymTypeNone: - switch(sym->bind) { - case ElfSymBindGlobal: - if(sym->other != 2) { - s = lookup(sym->name, 0); - break; - } - // fall through - case ElfSymBindLocal: - s = lookup(sym->name, version); - break; - default: - werrstr("%s: invalid symbol binding %d", sym->name, sym->bind); - return -1; - } - break; - } - if(s != nil && s->type == 0 && sym->type != ElfSymTypeSection) - s->type = SXREF; - sym->sym = s; - - return 0; -} - -int -rbyoff(const void *va, const void *vb) -{ - Reloc *a, *b; - - a = (Reloc*)va; - b = (Reloc*)vb; - if(a->off < b->off) - return -1; - if(a->off > b->off) - return +1; - return 0; -} - -#define R(x, y) ((x)|((y)<<24)) - -static int -reltype(char *pn, int elftype, uchar *siz) -{ - switch(R(thechar, elftype)) { - default: - diag("%s: unknown relocation type %d; compiled without -fpic?", pn, elftype); - case R('6', R_X86_64_PC32): - case R('6', R_X86_64_PLT32): - case R('6', R_X86_64_GOTPCREL): - case R('8', R_386_32): - case R('8', R_386_PC32): - case R('8', R_386_GOT32): - case R('8', R_386_PLT32): - case R('8', R_386_GOTOFF): - case R('8', R_386_GOTPC): - *siz = 4; - break; - case R('6', R_X86_64_64): - *siz = 8; - break; - } - - return 256+elftype; -} diff --git a/src/cmd/ld/ldmacho.c b/src/cmd/ld/ldmacho.c deleted file mode 100644 index abbc3b3cd..000000000 --- a/src/cmd/ld/ldmacho.c +++ /dev/null @@ -1,821 +0,0 @@ -/* -Derived from Plan 9 from User Space's src/libmach/elf.h, elf.c -http://code.swtch.com/plan9port/src/tip/src/libmach/ - - Copyright © 2004 Russ Cox. - Portions Copyright © 2008-2010 Google Inc. - Portions Copyright © 2010 The Go Authors. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -*/ - -#include "l.h" -#include "lib.h" - -enum { - MACHO_FAKE_GOTPCREL = 100, // from macho.h - - N_EXT = 0x01, - N_TYPE = 0x1e, - N_STAB = 0xe0, -}; - -typedef struct MachoObj MachoObj; -typedef struct MachoCmd MachoCmd; -typedef struct MachoSeg MachoSeg; -typedef struct MachoSect MachoSect; -typedef struct MachoRel MachoRel; -typedef struct MachoSymtab MachoSymtab; -typedef struct MachoSym MachoSym; -typedef struct MachoDysymtab MachoDysymtab; - -enum -{ - MachoCpuVax = 1, - MachoCpu68000 = 6, - MachoCpu386 = 7, - MachoCpuAmd64 = 0x1000007, - MachoCpuMips = 8, - MachoCpu98000 = 10, - MachoCpuHppa = 11, - MachoCpuArm = 12, - MachoCpu88000 = 13, - MachoCpuSparc = 14, - MachoCpu860 = 15, - MachoCpuAlpha = 16, - MachoCpuPower = 18, - - MachoCmdSegment = 1, - MachoCmdSymtab = 2, - MachoCmdSymseg = 3, - MachoCmdThread = 4, - MachoCmdDysymtab = 11, - MachoCmdSegment64 = 25, - - MachoFileObject = 1, - MachoFileExecutable = 2, - MachoFileFvmlib = 3, - MachoFileCore = 4, - MachoFilePreload = 5, -}; - -struct MachoSeg -{ - char name[16+1]; - uint64 vmaddr; - uint64 vmsize; - uint32 fileoff; - uint32 filesz; - uint32 maxprot; - uint32 initprot; - uint32 nsect; - uint32 flags; - MachoSect *sect; -}; - -struct MachoSect -{ - char name[16+1]; - char segname[16+1]; - uint64 addr; - uint64 size; - uint32 off; - uint32 align; - uint32 reloff; - uint32 nreloc; - uint32 flags; - uint32 res1; - uint32 res2; - Sym *sym; - - MachoRel *rel; -}; - -struct MachoRel -{ - uint32 addr; - uint32 symnum; - uint8 pcrel; - uint8 length; - uint8 extrn; - uint8 type; - uint8 scattered; - uint32 value; -}; - -struct MachoSymtab -{ - uint32 symoff; - uint32 nsym; - uint32 stroff; - uint32 strsize; - - char *str; - MachoSym *sym; -}; - -struct MachoSym -{ - char *name; - uint8 type; - uint8 sectnum; - uint16 desc; - char kind; - uint64 value; - Sym *sym; -}; - -struct MachoDysymtab -{ - uint32 ilocalsym; - uint32 nlocalsym; - uint32 iextdefsym; - uint32 nextdefsym; - uint32 iundefsym; - uint32 nundefsym; - uint32 tocoff; - uint32 ntoc; - uint32 modtaboff; - uint32 nmodtab; - uint32 extrefsymoff; - uint32 nextrefsyms; - uint32 indirectsymoff; - uint32 nindirectsyms; - uint32 extreloff; - uint32 nextrel; - uint32 locreloff; - uint32 nlocrel; - uint32 *indir; -}; - -struct MachoCmd -{ - int type; - uint32 off; - uint32 size; - MachoSeg seg; - MachoSymtab sym; - MachoDysymtab dsym; -}; - -struct MachoObj -{ - Biobuf *f; - int64 base; // off in f where Mach-O begins - int64 len; // length of Mach-O - int is64; - char *name; - - Endian *e; - uint cputype; - uint subcputype; - uint32 filetype; - uint32 flags; - MachoCmd *cmd; - uint ncmd; -}; - -static int -unpackcmd(uchar *p, MachoObj *m, MachoCmd *c, uint type, uint sz) -{ - uint32 (*e4)(uchar*); - uint64 (*e8)(uchar*); - MachoSect *s; - int i; - - e4 = m->e->e32; - e8 = m->e->e64; - - c->type = type; - c->size = sz; - switch(type){ - default: - return -1; - case MachoCmdSegment: - if(sz < 56) - return -1; - strecpy(c->seg.name, c->seg.name+sizeof c->seg.name, (char*)p+8); - c->seg.vmaddr = e4(p+24); - c->seg.vmsize = e4(p+28); - c->seg.fileoff = e4(p+32); - c->seg.filesz = e4(p+36); - c->seg.maxprot = e4(p+40); - c->seg.initprot = e4(p+44); - c->seg.nsect = e4(p+48); - c->seg.flags = e4(p+52); - c->seg.sect = mal(c->seg.nsect * sizeof c->seg.sect[0]); - if(sz < 56+c->seg.nsect*68) - return -1; - p += 56; - for(i=0; i<c->seg.nsect; i++) { - s = &c->seg.sect[i]; - strecpy(s->name, s->name+sizeof s->name, (char*)p+0); - strecpy(s->segname, s->segname+sizeof s->segname, (char*)p+16); - s->addr = e4(p+32); - s->size = e4(p+36); - s->off = e4(p+40); - s->align = e4(p+44); - s->reloff = e4(p+48); - s->nreloc = e4(p+52); - s->flags = e4(p+56); - s->res1 = e4(p+60); - s->res2 = e4(p+64); - p += 68; - } - break; - case MachoCmdSegment64: - if(sz < 72) - return -1; - strecpy(c->seg.name, c->seg.name+sizeof c->seg.name, (char*)p+8); - c->seg.vmaddr = e8(p+24); - c->seg.vmsize = e8(p+32); - c->seg.fileoff = e8(p+40); - c->seg.filesz = e8(p+48); - c->seg.maxprot = e4(p+56); - c->seg.initprot = e4(p+60); - c->seg.nsect = e4(p+64); - c->seg.flags = e4(p+68); - c->seg.sect = mal(c->seg.nsect * sizeof c->seg.sect[0]); - if(sz < 72+c->seg.nsect*80) - return -1; - p += 72; - for(i=0; i<c->seg.nsect; i++) { - s = &c->seg.sect[i]; - strecpy(s->name, s->name+sizeof s->name, (char*)p+0); - strecpy(s->segname, s->segname+sizeof s->segname, (char*)p+16); - s->addr = e8(p+32); - s->size = e8(p+40); - s->off = e4(p+48); - s->align = e4(p+52); - s->reloff = e4(p+56); - s->nreloc = e4(p+60); - s->flags = e4(p+64); - s->res1 = e4(p+68); - s->res2 = e4(p+72); - // p+76 is reserved - p += 80; - } - break; - case MachoCmdSymtab: - if(sz < 24) - return -1; - c->sym.symoff = e4(p+8); - c->sym.nsym = e4(p+12); - c->sym.stroff = e4(p+16); - c->sym.strsize = e4(p+20); - break; - case MachoCmdDysymtab: - if(sz < 80) - return -1; - c->dsym.ilocalsym = e4(p+8); - c->dsym.nlocalsym = e4(p+12); - c->dsym.iextdefsym = e4(p+16); - c->dsym.nextdefsym = e4(p+20); - c->dsym.iundefsym = e4(p+24); - c->dsym.nundefsym = e4(p+28); - c->dsym.tocoff = e4(p+32); - c->dsym.ntoc = e4(p+36); - c->dsym.modtaboff = e4(p+40); - c->dsym.nmodtab = e4(p+44); - c->dsym.extrefsymoff = e4(p+48); - c->dsym.nextrefsyms = e4(p+52); - c->dsym.indirectsymoff = e4(p+56); - c->dsym.nindirectsyms = e4(p+60); - c->dsym.extreloff = e4(p+64); - c->dsym.nextrel = e4(p+68); - c->dsym.locreloff = e4(p+72); - c->dsym.nlocrel = e4(p+76); - break; - } - return 0; -} - -static int -macholoadrel(MachoObj *m, MachoSect *sect) -{ - MachoRel *rel, *r; - uchar *buf, *p; - int i, n; - uint32 v; - - if(sect->rel != nil || sect->nreloc == 0) - return 0; - rel = mal(sect->nreloc * sizeof r[0]); - n = sect->nreloc * 8; - buf = mal(n); - if(Bseek(m->f, m->base + sect->reloff, 0) < 0 || Bread(m->f, buf, n) != n) - return -1; - for(i=0; i<sect->nreloc; i++) { - r = &rel[i]; - p = buf+i*8; - r->addr = m->e->e32(p); - - // TODO(rsc): Wrong interpretation for big-endian bitfields? - if(r->addr & 0x80000000) { - // scatterbrained relocation - r->scattered = 1; - v = r->addr >> 24; - r->addr &= 0xFFFFFF; - r->type = v & 0xF; - v >>= 4; - r->length = 1<<(v&3); - v >>= 2; - r->pcrel = v & 1; - r->value = m->e->e32(p+4); - } else { - v = m->e->e32(p+4); - r->symnum = v & 0xFFFFFF; - v >>= 24; - r->pcrel = v&1; - v >>= 1; - r->length = 1<<(v&3); - v >>= 2; - r->extrn = v&1; - v >>= 1; - r->type = v; - } - } - sect->rel = rel; - return 0; -} - -static int -macholoaddsym(MachoObj *m, MachoDysymtab *d) -{ - uchar *p; - int i, n; - - n = d->nindirectsyms; - - p = mal(n*4); - if(Bseek(m->f, m->base + d->indirectsymoff, 0) < 0 || Bread(m->f, p, n*4) != n*4) - return -1; - - d->indir = (uint32*)p; - for(i=0; i<n; i++) - d->indir[i] = m->e->e32(p+4*i); - return 0; -} - -static int -macholoadsym(MachoObj *m, MachoSymtab *symtab) -{ - char *strbuf; - uchar *symbuf, *p; - int i, n, symsize; - MachoSym *sym, *s; - uint32 v; - - if(symtab->sym != nil) - return 0; - - strbuf = mal(symtab->strsize); - if(Bseek(m->f, m->base + symtab->stroff, 0) < 0 || Bread(m->f, strbuf, symtab->strsize) != symtab->strsize) - return -1; - - symsize = 12; - if(m->is64) - symsize = 16; - n = symtab->nsym * symsize; - symbuf = mal(n); - if(Bseek(m->f, m->base + symtab->symoff, 0) < 0 || Bread(m->f, symbuf, n) != n) - return -1; - sym = mal(symtab->nsym * sizeof sym[0]); - p = symbuf; - for(i=0; i<symtab->nsym; i++) { - s = &sym[i]; - v = m->e->e32(p); - if(v >= symtab->strsize) - return -1; - s->name = strbuf + v; - s->type = p[4]; - s->sectnum = p[5]; - s->desc = m->e->e16(p+6); - if(m->is64) - s->value = m->e->e64(p+8); - else - s->value = m->e->e32(p+8); - p += symsize; - } - symtab->str = strbuf; - symtab->sym = sym; - return 0; -} - -void -ldmacho(Biobuf *f, char *pkg, int64 len, char *pn) -{ - int i, j, is64; - uint64 secaddr; - uchar hdr[7*4], *cmdp; - uchar tmp[4]; - uchar *dat; - ulong ncmd, cmdsz, ty, sz, off; - MachoObj *m; - Endian *e; - int64 base; - MachoSect *sect; - MachoRel *rel; - Sym *s, *outer; - MachoCmd *c; - MachoSymtab *symtab; - MachoDysymtab *dsymtab; - MachoSym *sym; - Reloc *r, *rp; - char *name; - - USED(pkg); - version++; - base = Boffset(f); - if(Bread(f, hdr, sizeof hdr) != sizeof hdr) - goto bad; - - if((be.e32(hdr)&~1) == 0xFEEDFACE){ - e = &be; - }else if((le.e32(hdr)&~1) == 0xFEEDFACE){ - e = ≤ - }else{ - werrstr("bad magic - not mach-o file"); - goto bad; - } - - is64 = e->e32(hdr) == 0xFEEDFACF; - ncmd = e->e32(hdr+4*4); - cmdsz = e->e32(hdr+5*4); - if(ncmd > 0x10000 || cmdsz >= 0x01000000){ - werrstr("implausible mach-o header ncmd=%lud cmdsz=%lud", ncmd, cmdsz); - goto bad; - } - if(is64) - Bread(f, tmp, 4); // skip reserved word in header - - m = mal(sizeof(*m)+ncmd*sizeof(MachoCmd)+cmdsz); - m->f = f; - m->e = e; - m->cputype = e->e32(hdr+1*4); - m->subcputype = e->e32(hdr+2*4); - m->filetype = e->e32(hdr+3*4); - m->ncmd = ncmd; - m->flags = e->e32(hdr+6*4); - m->is64 = is64; - m->base = base; - m->len = len; - m->name = pn; - - switch(thechar) { - default: - diag("%s: mach-o %s unimplemented", thestring); - return; - case '6': - if(e != &le || m->cputype != MachoCpuAmd64) { - diag("%s: mach-o object but not amd64", pn); - return; - } - break; - case '8': - if(e != &le || m->cputype != MachoCpu386) { - diag("%s: mach-o object but not 386", pn); - return; - } - break; - } - - m->cmd = (MachoCmd*)(m+1); - off = sizeof hdr; - cmdp = (uchar*)(m->cmd+ncmd); - if(Bread(f, cmdp, cmdsz) != cmdsz){ - werrstr("reading cmds: %r"); - goto bad; - } - - // read and parse load commands - c = nil; - symtab = nil; - dsymtab = nil; - for(i=0; i<ncmd; i++){ - ty = e->e32(cmdp); - sz = e->e32(cmdp+4); - m->cmd[i].off = off; - unpackcmd(cmdp, m, &m->cmd[i], ty, sz); - cmdp += sz; - off += sz; - if(ty == MachoCmdSymtab) { - if(symtab != nil) { - werrstr("multiple symbol tables"); - goto bad; - } - symtab = &m->cmd[i].sym; - macholoadsym(m, symtab); - } - if(ty == MachoCmdDysymtab) { - dsymtab = &m->cmd[i].dsym; - macholoaddsym(m, dsymtab); - } - if((is64 && ty == MachoCmdSegment64) || (!is64 && ty == MachoCmdSegment)) { - if(c != nil) { - werrstr("multiple load commands"); - goto bad; - } - c = &m->cmd[i]; - } - } - - // load text and data segments into memory. - // they are not as small as the load commands, but we'll need - // the memory anyway for the symbol images, so we might - // as well use one large chunk. - if(c == nil) { - werrstr("no load command"); - goto bad; - } - if(symtab == nil) { - // our work is done here - no symbols means nothing can refer to this file - return; - } - - if(c->seg.fileoff+c->seg.filesz >= len) { - werrstr("load segment out of range"); - goto bad; - } - - dat = mal(c->seg.filesz); - if(Bseek(f, m->base + c->seg.fileoff, 0) < 0 || Bread(f, dat, c->seg.filesz) != c->seg.filesz) { - werrstr("cannot load object data: %r"); - goto bad; - } - - for(i=0; i<c->seg.nsect; i++) { - sect = &c->seg.sect[i]; - if(strcmp(sect->segname, "__TEXT") != 0 && strcmp(sect->segname, "__DATA") != 0) - continue; - if(strcmp(sect->name, "__eh_frame") == 0) - continue; - name = smprint("%s(%s/%s)", pn, sect->segname, sect->name); - s = lookup(name, version); - if(s->type != 0) { - werrstr("duplicate %s/%s", sect->segname, sect->name); - goto bad; - } - free(name); - s->p = dat + sect->addr - c->seg.vmaddr; - s->np = sect->size; - s->size = s->np; - - if(strcmp(sect->segname, "__TEXT") == 0) { - if(strcmp(sect->name, "__text") == 0) - s->type = STEXT; - else - s->type = SRODATA; - } else { - if (strcmp(sect->name, "__bss") == 0) { - s->type = SBSS; - s->np = 0; - } else - s->type = SDATA; - } - if(s->type == STEXT) { - if(etextp) - etextp->next = s; - else - textp = s; - etextp = s; - } - sect->sym = s; - } - - // enter sub-symbols into symbol table. - // have to guess sizes from next symbol. - for(i=0; i<symtab->nsym; i++) { - int v; - sym = &symtab->sym[i]; - if(sym->type&N_STAB) - continue; - // TODO: check sym->type against outer->type. - name = sym->name; - if(name[0] == '_' && name[1] != '\0') - name++; - v = 0; - if(!(sym->type&N_EXT)) - v = version; - s = lookup(name, v); - sym->sym = s; - if(sym->sectnum == 0) // undefined - continue; - if(sym->sectnum > c->seg.nsect) { - werrstr("reference to invalid section %d", sym->sectnum); - goto bad; - } - sect = &c->seg.sect[sym->sectnum-1]; - outer = sect->sym; - if(outer == nil) { - werrstr("reference to invalid section %s/%s", sect->segname, sect->name); - continue; - } - s->type = outer->type | SSUB; - s->sub = outer->sub; - outer->sub = s; - s->outer = outer; - s->value = sym->value - sect->addr; - if(i+1 < symtab->nsym) - s->size = (sym+1)->value - sym->value; - else - s->size = sect->addr + sect->size - sym->value; - if(!s->dynexport) { - s->dynimplib = nil; // satisfy dynimport - s->dynimpname = nil; // satisfy dynimport - } - if(outer->type == STEXT) { - Prog *p; - - if(s->text != P) - diag("%s sym#%d: duplicate definition of %s", pn, i, s->name); - // build a TEXT instruction with a unique pc - // just to make the rest of the linker happy. - // TODO: this is too 6l-specific ? - 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; - } - sym->sym = s; - } - - // load relocations - for(i=0; i<c->seg.nsect; i++) { - sect = &c->seg.sect[i]; - if((s = sect->sym) == S) - continue; - macholoadrel(m, sect); - if(sect->rel == nil) - continue; - r = mal(sect->nreloc*sizeof r[0]); - rp = r; - rel = sect->rel; - for(j=0; j<sect->nreloc; j++, rel++) { - if(rel->scattered) { - int k; - MachoSect *ks; - - if(thechar != '8') - diag("unexpected scattered relocation"); - - // on 386, rewrite scattered 4/1 relocation into - // the pseudo-pc-relative reference that it is. - // assume that the second in the pair is in this section - // and use that as the pc-relative base. - if(thechar != '8' || rel->type != 4 || j+1 >= sect->nreloc || - !(rel+1)->scattered || (rel+1)->type != 1 || - (rel+1)->value < sect->addr || (rel+1)->value >= sect->addr+sect->size) { - werrstr("unsupported scattered relocation %d/%d", (int)rel->type, (int)(rel+1)->type); - goto bad; - } - rp->siz = rel->length; - rp->off = rel->addr; - - // NOTE(rsc): I haven't worked out why (really when) - // we should ignore the addend on a - // scattered relocation, but it seems that the - // common case is we ignore it. - // It's likely that this is not strictly correct - // and that the math should look something - // like the non-scattered case below. - rp->add = 0; - - // want to make it pc-relative aka relative to rp->off+4 - // but the scatter asks for relative to off = (rel+1)->value - sect->addr. - // adjust rp->add accordingly. - rp->type = D_PCREL; - rp->add += (rp->off+4) - ((rel+1)->value - sect->addr); - - // now consider the desired symbol. - // find the section where it lives. - for(k=0; k<c->seg.nsect; k++) { - ks = &c->seg.sect[k]; - if(ks->addr <= rel->value && rel->value < ks->addr+ks->size) - goto foundk; - } - werrstr("unsupported scattered relocation: invalid address %#ux", rel->addr); - goto bad; - foundk: - if(ks->sym != S) { - rp->sym = ks->sym; - rp->add += rel->value - ks->addr; - } else if(strcmp(ks->segname, "__IMPORT") == 0 && strcmp(ks->name, "__pointers") == 0) { - // handle reference to __IMPORT/__pointers. - // how much worse can this get? - // why are we supporting 386 on the mac anyway? - rp->type = 512 + MACHO_FAKE_GOTPCREL; - // figure out which pointer this is a reference to. - k = ks->res1 + (rel->value - ks->addr) / 4; - // load indirect table for __pointers - // fetch symbol number - if(dsymtab == nil || k < 0 || k >= dsymtab->nindirectsyms || dsymtab->indir == nil) { - werrstr("invalid scattered relocation: indirect symbol reference out of range"); - goto bad; - } - k = dsymtab->indir[k]; - if(k < 0 || k >= symtab->nsym) { - werrstr("invalid scattered relocation: symbol reference out of range"); - goto bad; - } - rp->sym = symtab->sym[k].sym; - } else { - werrstr("unsupported scattered relocation: reference to %s/%s", ks->segname, ks->name); - goto bad; - } - rp++; - // skip #1 of 2 rel; continue skips #2 of 2. - rel++; - j++; - continue; - } - - rp->siz = rel->length; - rp->type = 512 + (rel->type<<1) + rel->pcrel; - rp->off = rel->addr; - - // Handle X86_64_RELOC_SIGNED referencing a section (rel->extrn == 0). - if (thechar == '6' && rel->extrn == 0 && rel->type == 1) { - // Calculate the addend as the offset into the section. - // - // The rip-relative offset stored in the object file is encoded - // as follows: - // - // movsd 0x00000360(%rip),%xmm0 - // - // To get the absolute address of the value this rip-relative address is pointing - // to, we must add the address of the next instruction to it. This is done by - // taking the address of the relocation and adding 4 to it (since the rip-relative - // offset can at most be 32 bits long). To calculate the offset into the section the - // relocation is referencing, we subtract the vaddr of the start of the referenced - // section found in the original object file. - // - // [For future reference, see Darwin's /usr/include/mach-o/x86_64/reloc.h] - secaddr = c->seg.sect[rel->symnum-1].addr; - rp->add = e->e32(s->p+rp->off) + rp->off + 4 - secaddr; - } else - rp->add = e->e32(s->p+rp->off); - - // For i386 Mach-O PC-relative, the addend is written such that - // it *is* the PC being subtracted. Use that to make - // it match our version of PC-relative. - if(rel->pcrel && thechar == '8') - rp->add += rp->off+rp->siz; - if(!rel->extrn) { - if(rel->symnum < 1 || rel->symnum > c->seg.nsect) { - werrstr("invalid relocation: section reference out of range %d vs %d", rel->symnum, c->seg.nsect); - goto bad; - } - rp->sym = c->seg.sect[rel->symnum-1].sym; - if(rp->sym == nil) { - werrstr("invalid relocation: %s", c->seg.sect[rel->symnum-1].name); - goto bad; - } - // References to symbols in other sections - // include that information in the addend. - // We only care about the delta from the - // section base. - if(thechar == '8') - rp->add -= c->seg.sect[rel->symnum-1].addr; - } else { - if(rel->symnum >= symtab->nsym) { - werrstr("invalid relocation: symbol reference out of range"); - goto bad; - } - rp->sym = symtab->sym[rel->symnum].sym; - } - rp++; - } - qsort(r, rp - r, sizeof r[0], rbyoff); - s->r = r; - s->nr = rp - r; - } - return; - -bad: - diag("%s: malformed mach-o file: %r", pn); -} diff --git a/src/cmd/ld/ldpe.c b/src/cmd/ld/ldpe.c deleted file mode 100644 index 98c866fee..000000000 --- a/src/cmd/ld/ldpe.c +++ /dev/null @@ -1,415 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include "l.h" -#include "lib.h" -#include "../ld/pe.h" - -#define IMAGE_SCN_MEM_DISCARDABLE 0x2000000 - -#define IMAGE_SYM_UNDEFINED 0 -#define IMAGE_SYM_ABSOLUTE (-1) -#define IMAGE_SYM_DEBUG (-2) -#define IMAGE_SYM_TYPE_NULL 0 -#define IMAGE_SYM_TYPE_VOID 1 -#define IMAGE_SYM_TYPE_CHAR 2 -#define IMAGE_SYM_TYPE_SHORT 3 -#define IMAGE_SYM_TYPE_INT 4 -#define IMAGE_SYM_TYPE_LONG 5 -#define IMAGE_SYM_TYPE_FLOAT 6 -#define IMAGE_SYM_TYPE_DOUBLE 7 -#define IMAGE_SYM_TYPE_STRUCT 8 -#define IMAGE_SYM_TYPE_UNION 9 -#define IMAGE_SYM_TYPE_ENUM 10 -#define IMAGE_SYM_TYPE_MOE 11 -#define IMAGE_SYM_TYPE_BYTE 12 -#define IMAGE_SYM_TYPE_WORD 13 -#define IMAGE_SYM_TYPE_UINT 14 -#define IMAGE_SYM_TYPE_DWORD 15 -#define IMAGE_SYM_TYPE_PCODE 32768 -#define IMAGE_SYM_DTYPE_NULL 0 -#define IMAGE_SYM_DTYPE_POINTER 0x10 -#define IMAGE_SYM_DTYPE_FUNCTION 0x20 -#define IMAGE_SYM_DTYPE_ARRAY 0x30 -#define IMAGE_SYM_CLASS_END_OF_FUNCTION (-1) -#define IMAGE_SYM_CLASS_NULL 0 -#define IMAGE_SYM_CLASS_AUTOMATIC 1 -#define IMAGE_SYM_CLASS_EXTERNAL 2 -#define IMAGE_SYM_CLASS_STATIC 3 -#define IMAGE_SYM_CLASS_REGISTER 4 -#define IMAGE_SYM_CLASS_EXTERNAL_DEF 5 -#define IMAGE_SYM_CLASS_LABEL 6 -#define IMAGE_SYM_CLASS_UNDEFINED_LABEL 7 -#define IMAGE_SYM_CLASS_MEMBER_OF_STRUCT 8 -#define IMAGE_SYM_CLASS_ARGUMENT 9 -#define IMAGE_SYM_CLASS_STRUCT_TAG 10 -#define IMAGE_SYM_CLASS_MEMBER_OF_UNION 11 -#define IMAGE_SYM_CLASS_UNION_TAG 12 -#define IMAGE_SYM_CLASS_TYPE_DEFINITION 13 -#define IMAGE_SYM_CLASS_UNDEFINED_STATIC 14 -#define IMAGE_SYM_CLASS_ENUM_TAG 15 -#define IMAGE_SYM_CLASS_MEMBER_OF_ENUM 16 -#define IMAGE_SYM_CLASS_REGISTER_PARAM 17 -#define IMAGE_SYM_CLASS_BIT_FIELD 18 -#define IMAGE_SYM_CLASS_FAR_EXTERNAL 68 /* Not in PECOFF v8 spec */ -#define IMAGE_SYM_CLASS_BLOCK 100 -#define IMAGE_SYM_CLASS_FUNCTION 101 -#define IMAGE_SYM_CLASS_END_OF_STRUCT 102 -#define IMAGE_SYM_CLASS_FILE 103 -#define IMAGE_SYM_CLASS_SECTION 104 -#define IMAGE_SYM_CLASS_WEAK_EXTERNAL 105 -#define IMAGE_SYM_CLASS_CLR_TOKEN 107 - -#define IMAGE_REL_I386_ABSOLUTE 0x0000 -#define IMAGE_REL_I386_DIR16 0x0001 -#define IMAGE_REL_I386_REL16 0x0002 -#define IMAGE_REL_I386_DIR32 0x0006 -#define IMAGE_REL_I386_DIR32NB 0x0007 -#define IMAGE_REL_I386_SEG12 0x0009 -#define IMAGE_REL_I386_SECTION 0x000A -#define IMAGE_REL_I386_SECREL 0x000B -#define IMAGE_REL_I386_TOKEN 0x000C -#define IMAGE_REL_I386_SECREL7 0x000D -#define IMAGE_REL_I386_REL32 0x0014 - -typedef struct PeSym PeSym; -typedef struct PeSect PeSect; -typedef struct PeObj PeObj; - -struct PeSym { - char* name; - uint32 value; - uint16 sectnum; - uint16 type; - uint8 sclass; - uint8 aux; - Sym* sym; -}; - -struct PeSect { - char* name; - uchar* base; - uint64 size; - Sym* sym; - IMAGE_SECTION_HEADER sh; -}; - -struct PeObj { - Biobuf *f; - char *name; - uint32 base; - - PeSect *sect; - uint nsect; - PeSym *pesym; - uint npesym; - - IMAGE_FILE_HEADER fh; - char* snames; -}; - -static int map(PeObj *obj, PeSect *sect); -static int readsym(PeObj *obj, int i, PeSym **sym); - -void -ldpe(Biobuf *f, char *pkg, int64 len, char *pn) -{ - char *name; - int32 base; - int i, j, l, numaux; - PeObj *obj; - PeSect *sect, *rsect; - IMAGE_SECTION_HEADER sh; - uchar symbuf[18]; - Sym *s; - Reloc *r, *rp; - PeSym *sym; - - USED(len); - USED(pkg); - if(debug['v']) - Bprint(&bso, "%5.2f ldpe %s\n", cputime(), pn); - - sect = nil; - version++; - base = Boffset(f); - - obj = mal(sizeof *obj); - obj->f = f; - obj->base = base; - obj->name = pn; - // read header - if(Bread(f, &obj->fh, sizeof obj->fh) != sizeof obj->fh) - goto bad; - // load section list - obj->sect = mal(obj->fh.NumberOfSections*sizeof obj->sect[0]); - obj->nsect = obj->fh.NumberOfSections; - for(i=0; i < obj->fh.NumberOfSections; i++) { - if(Bread(f, &obj->sect[i].sh, sizeof sh) != sizeof sh) - goto bad; - obj->sect[i].size = obj->sect[i].sh.SizeOfRawData; - obj->sect[i].name = (char*)obj->sect[i].sh.Name; - // TODO return error if found .cormeta - } - // load string table - Bseek(f, base+obj->fh.PointerToSymbolTable+18*obj->fh.NumberOfSymbols, 0); - if(Bread(f, &l, sizeof l) != sizeof l) - goto bad; - obj->snames = mal(l); - Bseek(f, base+obj->fh.PointerToSymbolTable+18*obj->fh.NumberOfSymbols, 0); - if(Bread(f, obj->snames, l) != l) - goto bad; - // read symbols - obj->pesym = mal(obj->fh.NumberOfSymbols*sizeof obj->pesym[0]); - obj->npesym = obj->fh.NumberOfSymbols; - Bseek(f, base+obj->fh.PointerToSymbolTable, 0); - for(i=0; i<obj->fh.NumberOfSymbols; i+=numaux+1) { - Bseek(f, base+obj->fh.PointerToSymbolTable+sizeof(symbuf)*i, 0); - if(Bread(f, symbuf, sizeof symbuf) != sizeof symbuf) - goto bad; - - if((symbuf[0] == 0) && (symbuf[1] == 0) && - (symbuf[2] == 0) && (symbuf[3] == 0)) { - l = le32(&symbuf[4]); - obj->pesym[i].name = (char*)&obj->snames[l]; - } else { // sym name length <= 8 - obj->pesym[i].name = mal(9); - strncpy(obj->pesym[i].name, (char*)symbuf, 8); - obj->pesym[i].name[8] = 0; - } - obj->pesym[i].value = le32(&symbuf[8]); - obj->pesym[i].sectnum = le16(&symbuf[12]); - obj->pesym[i].sclass = symbuf[16]; - obj->pesym[i].aux = symbuf[17]; - obj->pesym[i].type = le16(&symbuf[14]); - numaux = obj->pesym[i].aux; - if (numaux < 0) - numaux = 0; - } - // create symbols for mapped sections - for(i=0; i<obj->nsect; i++) { - sect = &obj->sect[i]; - if(sect->sh.Characteristics&IMAGE_SCN_MEM_DISCARDABLE) - continue; - if(map(obj, sect) < 0) - goto bad; - - name = smprint("%s(%s)", pn, sect->name); - s = lookup(name, version); - free(name); - switch(sect->sh.Characteristics&(IMAGE_SCN_CNT_UNINITIALIZED_DATA|IMAGE_SCN_CNT_INITIALIZED_DATA| - IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE|IMAGE_SCN_CNT_CODE|IMAGE_SCN_MEM_EXECUTE)) { - case IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_MEM_READ: //.rdata - s->type = SRODATA; - break; - case IMAGE_SCN_CNT_UNINITIALIZED_DATA|IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE: //.bss - case IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE: //.data - s->type = SDATA; - break; - case IMAGE_SCN_CNT_CODE|IMAGE_SCN_MEM_EXECUTE|IMAGE_SCN_MEM_READ: //.text - s->type = STEXT; - break; - default: - werrstr("unexpected flags for PE section %s", sect->name); - goto bad; - } - s->p = sect->base; - s->np = sect->size; - s->size = sect->size; - if(s->type == STEXT) { - if(etextp) - etextp->next = s; - else - textp = s; - etextp = s; - } - sect->sym = s; - if(strcmp(sect->name, ".rsrc") == 0) - setpersrc(sect->sym); - } - - // load relocations - for(i=0; i<obj->nsect; i++) { - rsect = &obj->sect[i]; - if(rsect->sym == 0 || rsect->sh.NumberOfRelocations == 0) - continue; - if(rsect->sh.Characteristics&IMAGE_SCN_MEM_DISCARDABLE) - continue; - r = mal(rsect->sh.NumberOfRelocations*sizeof r[0]); - Bseek(f, obj->base+rsect->sh.PointerToRelocations, 0); - for(j=0; j<rsect->sh.NumberOfRelocations; j++) { - rp = &r[j]; - if(Bread(f, symbuf, 10) != 10) - goto bad; - - uint32 rva, symindex; - uint16 type; - rva = le32(&symbuf[0]); - symindex = le32(&symbuf[4]); - type = le16(&symbuf[8]); - if(readsym(obj, symindex, &sym) < 0) - goto bad; - if(sym->sym == nil) { - werrstr("reloc of invalid sym %s idx=%d type=%d", sym->name, symindex, sym->type); - goto bad; - } - rp->sym = sym->sym; - rp->siz = 4; - rp->off = rva; - switch(type) { - default: - diag("%s: unknown relocation type %d;", pn, type); - case IMAGE_REL_I386_REL32: - rp->type = D_PCREL; - rp->add = 0; - break; - case IMAGE_REL_I386_DIR32NB: - case IMAGE_REL_I386_DIR32: - rp->type = D_ADDR; - // load addend from image - rp->add = le32(rsect->base+rp->off); - break; - } - } - qsort(r, rsect->sh.NumberOfRelocations, sizeof r[0], rbyoff); - - s = rsect->sym; - s->r = r; - s->nr = rsect->sh.NumberOfRelocations; - } - - // enter sub-symbols into symbol table. - // frist 2 entry is file name. - for(i=2; i<obj->npesym; i++) { - if(obj->pesym[i].name == 0) - continue; - if(obj->pesym[i].name[0] == '.') //skip section - continue; - if(obj->pesym[i].sectnum > 0) { - sect = &obj->sect[obj->pesym[i].sectnum-1]; - if(sect->sym == 0) - continue; - } - if(readsym(obj, i, &sym) < 0) - goto bad; - - s = sym->sym; - if(sym->sectnum == 0) {// extern - if(s->type == SDYNIMPORT) - s->plt = -2; // flag for dynimport in PE object files. - continue; - } else if (sym->sectnum > 0) { - sect = &obj->sect[sym->sectnum-1]; - if(sect->sym == 0) - diag("%s: %s sym == 0!", pn, s->name); - } else { - diag("%s: %s sectnum <0!", pn, s->name, sym->sectnum); - } - - if(sect == nil) - return; - s->sub = sect->sym->sub; - sect->sym->sub = s; - s->type = sect->sym->type | SSUB; - s->value = sym->value; - s->size = 4; - 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 pe file: %r", pn); -} - -static int -map(PeObj *obj, PeSect *sect) -{ - if(sect->base != nil) - return 0; - - sect->base = mal(sect->sh.SizeOfRawData); - werrstr("short read"); - if(Bseek(obj->f, obj->base+sect->sh.PointerToRawData, 0) < 0 || - Bread(obj->f, sect->base, sect->sh.SizeOfRawData) != sect->sh.SizeOfRawData) - return -1; - - return 0; -} - -static int -readsym(PeObj *obj, int i, PeSym **y) -{ - Sym *s; - PeSym *sym; - char *name, *p; - - if(i >= obj->npesym || i < 0) { - werrstr("invalid pe symbol index"); - return -1; - } - - sym = &obj->pesym[i]; - *y = sym; - - name = sym->name; - if(sym->sclass == IMAGE_SYM_CLASS_STATIC && sym->value == 0) // section - name = obj->sect[sym->sectnum-1].sym->name; - if(strncmp(sym->name, "__imp__", 7) == 0) - name = &sym->name[7]; // __imp__Name => Name - else if(sym->name[0] == '_') - name = &sym->name[1]; // _Name => Name - // remove last @XXX - p = strchr(name, '@'); - if(p) - *p = 0; - - switch(sym->type) { - default: - werrstr("%s: invalid symbol type %d", sym->name, sym->type); - return -1; - case IMAGE_SYM_DTYPE_FUNCTION: - case IMAGE_SYM_DTYPE_NULL: - switch(sym->sclass) { - case IMAGE_SYM_CLASS_EXTERNAL: //global - s = lookup(name, 0); - break; - case IMAGE_SYM_CLASS_NULL: - case IMAGE_SYM_CLASS_STATIC: - s = lookup(name, version); - break; - default: - werrstr("%s: invalid symbol binding %d", sym->name, sym->sclass); - return -1; - } - break; - } - - if(s != nil && s->type == 0 && !(sym->sclass == IMAGE_SYM_CLASS_STATIC && sym->value == 0)) - s->type = SXREF; - if(strncmp(sym->name, "__imp__", 7) == 0) - s->got = -2; // flag for __imp__ - sym->sym = s; - - return 0; -} diff --git a/src/cmd/ld/lib.c b/src/cmd/ld/lib.c deleted file mode 100644 index 77a62f5de..000000000 --- a/src/cmd/ld/lib.c +++ /dev/null @@ -1,1361 +0,0 @@ -// Derived from Inferno utils/6l/obj.c and utils/6l/span.c -// http://code.google.com/p/inferno-os/source/browse/utils/6l/obj.c -// http://code.google.com/p/inferno-os/source/browse/utils/6l/span.c -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#include "l.h" -#include "lib.h" -#include "../../pkg/runtime/stack.h" - -#include <ar.h> - -int iconv(Fmt*); - -char symname[] = SYMDEF; -char pkgname[] = "__.PKGDEF"; -char* libdir[16]; -int nlibdir = 0; -int cout = -1; - -char* goroot; -char* goarch; -char* goos; - -void -Lflag(char *arg) -{ - if(nlibdir >= nelem(libdir)-1) { - print("too many -L's: %d\n", nlibdir); - usage(); - } - libdir[nlibdir++] = arg; -} - -void -libinit(void) -{ - fmtinstall('i', iconv); - fmtinstall('Y', Yconv); - mywhatsys(); // get goroot, goarch, goos - if(strcmp(goarch, thestring) != 0) - print("goarch is not known: %s\n", goarch); - - // add goroot to the end of the libdir list. - libdir[nlibdir++] = smprint("%s/pkg/%s_%s", goroot, goos, goarch); - - remove(outfile); - cout = create(outfile, 1, 0775); - if(cout < 0) { - diag("cannot create %s", outfile); - errorexit(); - } - - if(INITENTRY == nil) { - INITENTRY = mal(strlen(goarch)+strlen(goos)+10); - sprint(INITENTRY, "_rt0_%s_%s", goarch, goos); - } - lookup(INITENTRY, 0)->type = SXREF; -} - -void -errorexit(void) -{ - if(nerrors) { - if(cout >= 0) - remove(outfile); - exits("error"); - } - exits(0); -} - -void -addlib(char *src, char *obj) -{ - char name[1024], pname[1024], comp[256], *p; - int i, search; - - if(histfrogp <= 0) - return; - - search = 0; - if(histfrog[0]->name[1] == '/') { - sprint(name, ""); - i = 1; - } else - if(isalpha(histfrog[0]->name[1]) && histfrog[0]->name[2] == ':') { - strcpy(name, histfrog[0]->name+1); - i = 1; - } else - if(histfrog[0]->name[1] == '.') { - sprint(name, "."); - i = 0; - } else { - sprint(name, ""); - i = 0; - search = 1; - } - - for(; i<histfrogp; i++) { - snprint(comp, sizeof comp, "%s", histfrog[i]->name+1); - for(;;) { - p = strstr(comp, "$O"); - if(p == 0) - break; - memmove(p+1, p+2, strlen(p+2)+1); - p[0] = thechar; - } - for(;;) { - p = strstr(comp, "$M"); - if(p == 0) - break; - if(strlen(comp)+strlen(thestring)-2+1 >= sizeof comp) { - diag("library component too long"); - return; - } - memmove(p+strlen(thestring), p+2, strlen(p+2)+1); - memmove(p, thestring, strlen(thestring)); - } - if(strlen(name) + strlen(comp) + 3 >= sizeof(name)) { - diag("library component too long"); - return; - } - if(i > 0 || !search) - strcat(name, "/"); - strcat(name, comp); - } - cleanname(name); - - // runtime.a -> runtime - p = nil; - if(strlen(name) > 2 && name[strlen(name)-2] == '.') { - p = name+strlen(name)-2; - *p = '\0'; - } - - // already loaded? - for(i=0; i<libraryp; i++) - if(strcmp(library[i].pkg, name) == 0) - return; - - // runtime -> runtime.a for search - if(p != nil) - *p = '.'; - - if(search) { - // try dot, -L "libdir", and then goroot. - for(i=0; i<nlibdir; i++) { - snprint(pname, sizeof pname, "%s/%s", libdir[i], name); - if(access(pname, AEXIST) >= 0) - break; - } - }else - strcpy(pname, name); - cleanname(pname); - - /* runtime.a -> runtime */ - if(p != nil) - *p = '\0'; - - if(debug['v']) - Bprint(&bso, "%5.2f addlib: %s %s pulls in %s\n", cputime(), obj, src, pname); - - addlibpath(src, obj, pname, name); -} - -/* - * add library to library list. - * srcref: src file referring to package - * objref: object file referring to package - * file: object file, e.g., /home/rsc/go/pkg/container/vector.a - * pkg: package import path, e.g. container/vector - */ -void -addlibpath(char *srcref, char *objref, char *file, char *pkg) -{ - int i; - Library *l; - char *p; - - for(i=0; i<libraryp; i++) - if(strcmp(file, library[i].file) == 0) - return; - - if(debug['v'] > 1) - Bprint(&bso, "%5.2f addlibpath: srcref: %s objref: %s file: %s pkg: %s\n", - cputime(), srcref, objref, file, pkg); - - if(libraryp == nlibrary){ - nlibrary = 50 + 2*libraryp; - library = realloc(library, sizeof library[0] * nlibrary); - } - - l = &library[libraryp++]; - - p = mal(strlen(objref) + 1); - strcpy(p, objref); - l->objref = p; - - p = mal(strlen(srcref) + 1); - strcpy(p, srcref); - l->srcref = p; - - p = mal(strlen(file) + 1); - strcpy(p, file); - l->file = p; - - p = mal(strlen(pkg) + 1); - strcpy(p, pkg); - l->pkg = p; -} - -void -loadinternal(char *name) -{ - char pname[1024]; - int i, found; - - found = 0; - for(i=0; i<nlibdir; i++) { - snprint(pname, sizeof pname, "%s/%s.a", libdir[i], name); - if(debug['v']) - Bprint(&bso, "searching for %s.a in %s\n", name, pname); - if(access(pname, AEXIST) >= 0) { - addlibpath("internal", "internal", pname, name); - found = 1; - break; - } - } - if(!found) - Bprint(&bso, "warning: unable to find %s.a\n", name); -} - -void -loadlib(void) -{ - int i; - - loadinternal("runtime"); - if(thechar == '5') - loadinternal("math"); - - for(i=0; i<libraryp; i++) { - if(debug['v']) - Bprint(&bso, "%5.2f autolib: %s (from %s)\n", cputime(), library[i].file, library[i].objref); - objfile(library[i].file, library[i].pkg); - } - - // We've loaded all the code now. - // If there are no dynamic libraries needed, gcc disables dynamic linking. - // Because of this, glibc's dynamic ELF loader occasionally (like in version 2.13) - // assumes that a dynamic binary always refers to at least one dynamic library. - // Rather than be a source of test cases for glibc, disable dynamic linking - // the same way that gcc would. - // - // Exception: on OS X, programs such as Shark only work with dynamic - // binaries, so leave it enabled on OS X (Mach-O) binaries. - if(!havedynamic && HEADTYPE != Hdarwin) - debug['d'] = 1; -} - -/* - * look for the next file in an archive. - * adapted from libmach. - */ -int -nextar(Biobuf *bp, int off, struct ar_hdr *a) -{ - int r; - int32 arsize; - - if (off&01) - off++; - Bseek(bp, off, 0); - r = Bread(bp, a, SAR_HDR); - if(r != SAR_HDR) - return 0; - if(strncmp(a->fmag, ARFMAG, sizeof(a->fmag))) - return -1; - arsize = strtol(a->size, 0, 0); - if (arsize&1) - arsize++; - return arsize + SAR_HDR; -} - -void -objfile(char *file, char *pkg) -{ - int32 off, l; - Biobuf *f; - char magbuf[SARMAG]; - char pname[150]; - struct ar_hdr arhdr; - - pkg = smprint("%i", pkg); - - if(debug['v']) - Bprint(&bso, "%5.2f ldobj: %s (%s)\n", cputime(), file, pkg); - Bflush(&bso); - f = Bopen(file, 0); - if(f == nil) { - diag("cannot open file: %s", file); - errorexit(); - } - l = Bread(f, magbuf, SARMAG); - if(l != SARMAG || strncmp(magbuf, ARMAG, SARMAG)){ - /* load it as a regular file */ - l = Bseek(f, 0L, 2); - Bseek(f, 0L, 0); - ldobj(f, pkg, l, file, FileObj); - Bterm(f); - return; - } - - /* skip over __.SYMDEF */ - off = Boffset(f); - if((l = nextar(f, off, &arhdr)) <= 0) { - diag("%s: short read on archive file symbol header", file); - goto out; - } - if(strncmp(arhdr.name, symname, strlen(symname))) { - diag("%s: first entry not symbol header", file); - goto out; - } - off += l; - - /* skip over (or process) __.PKGDEF */ - if((l = nextar(f, off, &arhdr)) <= 0) { - diag("%s: short read on archive file symbol header", file); - goto out; - } - if(strncmp(arhdr.name, pkgname, strlen(pkgname))) { - diag("%s: second entry not package header", file); - goto out; - } - off += l; - - if(debug['u']) - ldpkg(f, pkg, atolwhex(arhdr.size), file, Pkgdef); - - /* - * load all the object files from the archive now. - * this gives us sequential file access and keeps us - * from needing to come back later to pick up more - * objects. it breaks the usual C archive model, but - * this is Go, not C. the common case in Go is that - * we need to load all the objects, and then we throw away - * the individual symbols that are unused. - * - * loading every object will also make it possible to - * load foreign objects not referenced by __.SYMDEF. - */ - for(;;) { - l = nextar(f, off, &arhdr); - if(l == 0) - break; - if(l < 0) { - diag("%s: malformed archive", file); - goto out; - } - off += l; - - l = SARNAME; - while(l > 0 && arhdr.name[l-1] == ' ') - l--; - snprint(pname, sizeof pname, "%s(%.*s)", file, utfnlen(arhdr.name, l), arhdr.name); - l = atolwhex(arhdr.size); - ldobj(f, pkg, l, pname, ArchiveObj); - } - -out: - Bterm(f); -} - -void -ldobj(Biobuf *f, char *pkg, int64 len, char *pn, int whence) -{ - char *line; - int n, c1, c2, c3, c4; - uint32 magic; - vlong import0, import1, eof; - char *t; - - eof = Boffset(f) + len; - - pn = strdup(pn); - - c1 = Bgetc(f); - c2 = Bgetc(f); - c3 = Bgetc(f); - c4 = Bgetc(f); - Bungetc(f); - Bungetc(f); - Bungetc(f); - Bungetc(f); - - magic = c1<<24 | c2<<16 | c3<<8 | c4; - if(magic == 0x7f454c46) { // \x7F E L F - ldelf(f, pkg, len, pn); - return; - } - if((magic&~1) == 0xfeedface || (magic&~0x01000000) == 0xcefaedfe) { - ldmacho(f, pkg, len, pn); - return; - } - if(c1 == 0x4c && c2 == 0x01 || c1 == 0x64 && c2 == 0x86) { - ldpe(f, pkg, len, pn); - return; - } - - /* check the header */ - line = Brdline(f, '\n'); - if(line == nil) { - if(Blinelen(f) > 0) { - diag("%s: not an object file", pn); - return; - } - goto eof; - } - n = Blinelen(f) - 1; - line[n] = '\0'; - if(strncmp(line, "go object ", 10) != 0) { - if(strlen(pn) > 3 && strcmp(pn+strlen(pn)-3, ".go") == 0) { - print("%cl: input %s is not .%c file (use %cg to compile .go files)\n", thechar, pn, thechar, thechar); - errorexit(); - } - if(strcmp(line, thestring) == 0) { - // old header format: just $GOOS - diag("%s: stale object file", pn); - return; - } - diag("%s: not an object file", pn); - return; - } - t = smprint("%s %s %s", getgoos(), thestring, getgoversion()); - if(strcmp(line+10, t) != 0 && !debug['f']) { - diag("%s: object is [%s] expected [%s]", pn, line+10, t); - free(t); - return; - } - free(t); - line[n] = '\n'; - - /* skip over exports and other info -- ends with \n!\n */ - import0 = Boffset(f); - c1 = '\n'; // the last line ended in \n - c2 = Bgetc(f); - c3 = Bgetc(f); - while(c1 != '\n' || c2 != '!' || c3 != '\n') { - c1 = c2; - c2 = c3; - c3 = Bgetc(f); - if(c3 == Beof) - goto eof; - } - import1 = Boffset(f); - - Bseek(f, import0, 0); - ldpkg(f, pkg, import1 - import0 - 2, pn, whence); // -2 for !\n - Bseek(f, import1, 0); - - ldobj1(f, pkg, eof - Boffset(f), pn); - return; - -eof: - diag("truncated object file: %s", pn); -} - -static Sym* -_lookup(char *symb, int v, int creat) -{ - Sym *s; - char *p; - int32 h; - int l, c; - - h = v; - for(p=symb; c = *p; p++) - h = h+h+h + c; - l = (p - symb) + 1; - // not if(h < 0) h = ~h, because gcc 4.3 -O2 miscompiles it. - h &= 0xffffff; - h %= NHASH; - for(s = hash[h]; s != S; s = s->hash) - if(memcmp(s->name, symb, l) == 0) - return s; - 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->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; -} - -Sym* -lookup(char *name, int v) -{ - return _lookup(name, v, 1); -} - -// read-only lookup -Sym* -rlookup(char *name, int v) -{ - return _lookup(name, v, 0); -} - -void -copyhistfrog(char *buf, int nbuf) -{ - char *p, *ep; - int i; - - p = buf; - ep = buf + nbuf; - for(i=0; i<histfrogp; i++) { - p = seprint(p, ep, "%s", histfrog[i]->name+1); - if(i+1<histfrogp && (p == buf || p[-1] != '/')) - p = seprint(p, ep, "/"); - } -} - -void -addhist(int32 line, int type) -{ - Auto *u; - Sym *s; - int i, j, k; - - u = mal(sizeof(Auto)); - s = mal(sizeof(Sym)); - s->name = mal(2*(histfrogp+1) + 1); - - u->asym = s; - u->type = type; - u->aoffset = line; - u->link = curhist; - curhist = u; - - s->name[0] = 0; - j = 1; - for(i=0; i<histfrogp; i++) { - k = histfrog[i]->value; - s->name[j+0] = k>>8; - s->name[j+1] = k; - j += 2; - } - s->name[j] = 0; - s->name[j+1] = 0; -} - -void -histtoauto(void) -{ - Auto *l; - - while(l = curhist) { - curhist = l->link; - l->link = curauto; - curauto = l; - } -} - -void -collapsefrog(Sym *s) -{ - int i; - - /* - * bad encoding of path components only allows - * MAXHIST components. if there is an overflow, - * first try to collapse xxx/.. - */ - for(i=1; i<histfrogp; i++) - if(strcmp(histfrog[i]->name+1, "..") == 0) { - memmove(histfrog+i-1, histfrog+i+1, - (histfrogp-i-1)*sizeof(histfrog[0])); - histfrogp--; - goto out; - } - - /* - * next try to collapse . - */ - for(i=0; i<histfrogp; i++) - if(strcmp(histfrog[i]->name+1, ".") == 0) { - memmove(histfrog+i, histfrog+i+1, - (histfrogp-i-1)*sizeof(histfrog[0])); - goto out; - } - - /* - * last chance, just truncate from front - */ - memmove(histfrog+0, histfrog+1, - (histfrogp-1)*sizeof(histfrog[0])); - -out: - histfrog[histfrogp-1] = s; -} - -void -nuxiinit(void) -{ - int i, c; - - for(i=0; i<4; i++) { - c = find1(0x04030201L, i+1); - if(i < 2) - inuxi2[i] = c; - if(i < 1) - inuxi1[i] = c; - inuxi4[i] = c; - if(c == i) { - inuxi8[i] = c; - inuxi8[i+4] = c+4; - } else { - inuxi8[i] = c+4; - inuxi8[i+4] = c; - } - fnuxi4[i] = c; - fnuxi8[i] = c; - fnuxi8[i+4] = c+4; - } - if(debug['v']) { - Bprint(&bso, "inuxi = "); - for(i=0; i<1; i++) - Bprint(&bso, "%d", inuxi1[i]); - Bprint(&bso, " "); - for(i=0; i<2; i++) - Bprint(&bso, "%d", inuxi2[i]); - Bprint(&bso, " "); - for(i=0; i<4; i++) - Bprint(&bso, "%d", inuxi4[i]); - Bprint(&bso, " "); - for(i=0; i<8; i++) - Bprint(&bso, "%d", inuxi8[i]); - Bprint(&bso, "\nfnuxi = "); - for(i=0; i<4; i++) - Bprint(&bso, "%d", fnuxi4[i]); - Bprint(&bso, " "); - for(i=0; i<8; i++) - Bprint(&bso, "%d", fnuxi8[i]); - Bprint(&bso, "\n"); - } - Bflush(&bso); -} - -int -find1(int32 l, int c) -{ - char *p; - int i; - - p = (char*)&l; - for(i=0; i<4; i++) - if(*p++ == c) - return i; - return 0; -} - -int -find2(int32 l, int c) -{ - union { - int32 l; - short p[2]; - } u; - short *p; - int i; - - u.l = l; - p = u.p; - for(i=0; i<4; i+=2) { - if(((*p >> 8) & 0xff) == c) - return i; - if((*p++ & 0xff) == c) - return i+1; - } - return 0; -} - -int32 -ieeedtof(Ieee *e) -{ - int exp; - int32 v; - - if(e->h == 0) - return 0; - exp = (e->h>>20) & ((1L<<11)-1L); - exp -= (1L<<10) - 2L; - v = (e->h & 0xfffffL) << 3; - v |= (e->l >> 29) & 0x7L; - if((e->l >> 28) & 1) { - v++; - if(v & 0x800000L) { - v = (v & 0x7fffffL) >> 1; - exp++; - } - } - if(-148 <= exp && exp <= -126) { - v |= 1<<23; - v >>= -125 - exp; - exp = -126; - } - else if(exp < -148 || exp >= 130) - diag("double fp to single fp overflow: %.17g", ieeedtod(e)); - v |= ((exp + 126) & 0xffL) << 23; - v |= e->h & 0x80000000L; - return v; -} - -double -ieeedtod(Ieee *ieeep) -{ - Ieee e; - double fr; - int exp; - - if(ieeep->h & (1L<<31)) { - e.h = ieeep->h & ~(1L<<31); - e.l = ieeep->l; - return -ieeedtod(&e); - } - if(ieeep->l == 0 && ieeep->h == 0) - return 0; - exp = (ieeep->h>>20) & ((1L<<11)-1L); - exp -= (1L<<10) - 2L; - fr = ieeep->l & ((1L<<16)-1L); - fr /= 1L<<16; - fr += (ieeep->l>>16) & ((1L<<16)-1L); - fr /= 1L<<16; - if(exp == -(1L<<10) - 2L) { - fr += (ieeep->h & (1L<<20)-1L); - exp++; - } else - fr += (ieeep->h & (1L<<20)-1L) | (1L<<20); - fr /= 1L<<21; - return ldexp(fr, exp); -} - -void -zerosig(char *sp) -{ - Sym *s; - - s = lookup(sp, 0); - s->sig = 0; -} - -int32 -Bget4(Biobuf *f) -{ - uchar p[4]; - - if(Bread(f, p, 4) != 4) - return 0; - return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24); -} - -void -mywhatsys(void) -{ - goroot = getgoroot(); - goos = getgoos(); - goarch = thestring; // ignore $GOARCH - we know who we are -} - -int -pathchar(void) -{ - return '/'; -} - -static uchar* hunk; -static uint32 nhunk; -#define NHUNK (10UL<<20) - -void* -mal(uint32 n) -{ - void *v; - - n = (n+7)&~7; - if(n > NHUNK) { - v = malloc(n); - if(v == nil) { - diag("out of memory"); - errorexit(); - } - memset(v, 0, n); - return v; - } - if(n > nhunk) { - hunk = malloc(NHUNK); - if(hunk == nil) { - diag("out of memory"); - errorexit(); - } - nhunk = NHUNK; - } - - v = hunk; - nhunk -= n; - hunk += n; - - memset(v, 0, n); - return v; -} - -void -unmal(void *v, uint32 n) -{ - n = (n+7)&~7; - if(hunk - n == v) { - hunk -= n; - nhunk += n; - } -} - -// Copied from ../gc/subr.c:/^pathtoprefix; must stay in sync. -/* - * Convert raw string to the prefix that will be used in the symbol table. - * Invalid bytes turn into %xx. Right now the only bytes that need - * escaping are %, ., and ", but we escape all control characters too. - */ -static char* -pathtoprefix(char *s) -{ - static char hex[] = "0123456789abcdef"; - char *p, *r, *w; - int n; - - // check for chars that need escaping - n = 0; - for(r=s; *r; r++) - if(*r <= ' ' || *r == '.' || *r == '%' || *r == '"') - n++; - - // quick exit - if(n == 0) - return s; - - // escape - p = mal((r-s)+1+2*n); - for(r=s, w=p; *r; r++) { - if(*r <= ' ' || *r == '.' || *r == '%' || *r == '"') { - *w++ = '%'; - *w++ = hex[(*r>>4)&0xF]; - *w++ = hex[*r&0xF]; - } else - *w++ = *r; - } - *w = '\0'; - return p; -} - -int -iconv(Fmt *fp) -{ - char *p; - - p = va_arg(fp->args, char*); - if(p == nil) { - fmtstrcpy(fp, "<nil>"); - return 0; - } - p = pathtoprefix(p); - fmtstrcpy(fp, p); - return 0; -} - -void -mangle(char *file) -{ - fprint(2, "%s: mangled input file\n", file); - errorexit(); -} - -Section* -addsection(Segment *seg, char *name, int rwx) -{ - Section **l; - Section *sect; - - for(l=&seg->sect; *l; l=&(*l)->next) - ; - sect = mal(sizeof *sect); - sect->rwx = rwx; - sect->name = name; - sect->seg = seg; - *l = sect; - return sect; -} - -void -ewrite(int fd, void *buf, int n) -{ - if(write(fd, buf, n) < 0) { - diag("write error: %r"); - errorexit(); - } -} - -void -pclntab(void) -{ - vlong oldpc; - Prog *p; - int32 oldlc, v, s; - Sym *sym; - uchar *bp; - - sym = lookup("pclntab", 0); - sym->type = SPCLNTAB; - sym->reachable = 1; - if(debug['s']) - return; - - oldpc = INITTEXT; - oldlc = 0; - for(cursym = textp; cursym != nil; cursym = cursym->next) { - for(p = cursym->text; p != P; p = p->link) { - if(p->line == oldlc || p->as == ATEXT || p->as == ANOP) { - if(debug['O']) - Bprint(&bso, "%6llux %P\n", - (vlong)p->pc, p); - continue; - } - if(debug['O']) - Bprint(&bso, "\t\t%6d", lcsize); - v = (p->pc - oldpc) / MINLC; - while(v) { - s = 127; - if(v < 127) - s = v; - symgrow(sym, lcsize+1); - bp = sym->p + lcsize; - *bp = s+128; /* 129-255 +pc */ - if(debug['O']) - Bprint(&bso, " pc+%d*%d(%d)", s, MINLC, s+128); - v -= s; - lcsize++; - } - s = p->line - oldlc; - oldlc = p->line; - oldpc = p->pc + MINLC; - if(s > 64 || s < -64) { - symgrow(sym, lcsize+5); - bp = sym->p + lcsize; - *bp++ = 0; /* 0 vv +lc */ - *bp++ = s>>24; - *bp++ = s>>16; - *bp++ = s>>8; - *bp = s; - if(debug['O']) { - if(s > 0) - Bprint(&bso, " lc+%d(%d,%d)\n", - s, 0, s); - else - Bprint(&bso, " lc%d(%d,%d)\n", - s, 0, s); - Bprint(&bso, "%6llux %P\n", - (vlong)p->pc, p); - } - lcsize += 5; - continue; - } - symgrow(sym, lcsize+1); - bp = sym->p + lcsize; - if(s > 0) { - *bp = 0+s; /* 1-64 +lc */ - if(debug['O']) { - Bprint(&bso, " lc+%d(%d)\n", s, 0+s); - Bprint(&bso, "%6llux %P\n", - (vlong)p->pc, p); - } - } else { - *bp = 64-s; /* 65-128 -lc */ - if(debug['O']) { - Bprint(&bso, " lc%d(%d)\n", s, 64-s); - Bprint(&bso, "%6llux %P\n", - (vlong)p->pc, p); - } - } - lcsize++; - } - } - if(lcsize & 1) { - symgrow(sym, lcsize+1); - sym->p[lcsize] = 129; - lcsize++; - } - sym->size = lcsize; - lcsize = 0; - - if(debug['v'] || debug['O']) - Bprint(&bso, "lcsize = %d\n", lcsize); - Bflush(&bso); -} - -#define LOG 5 -void -mkfwd(void) -{ - Prog *p; - int i; - int32 dwn[LOG], cnt[LOG]; - Prog *lst[LOG]; - - for(i=0; i<LOG; i++) { - if(i == 0) - cnt[i] = 1; - else - cnt[i] = LOG * cnt[i-1]; - dwn[i] = 1; - lst[i] = P; - } - i = 0; - for(cursym = textp; cursym != nil; cursym = cursym->next) { - for(p = cursym->text; p != P; p = p->link) { - if(p->link == P) { - if(cursym->next) - p->forwd = cursym->next->text; - break; - } - i--; - if(i < 0) - i = LOG-1; - p->forwd = P; - dwn[i]--; - if(dwn[i] <= 0) { - dwn[i] = cnt[i]; - if(lst[i] != P) - lst[i]->forwd = p; - lst[i] = p; - } - } - } -} - -uint16 -le16(uchar *b) -{ - return b[0] | b[1]<<8; -} - -uint32 -le32(uchar *b) -{ - return b[0] | b[1]<<8 | b[2]<<16 | b[3]<<24; -} - -uint64 -le64(uchar *b) -{ - return le32(b) | (uint64)le32(b+4)<<32; -} - -uint16 -be16(uchar *b) -{ - return b[0]<<8 | b[1]; -} - -uint32 -be32(uchar *b) -{ - return b[0]<<24 | b[1]<<16 | b[2]<<8 | b[3]; -} - -uint64 -be64(uchar *b) -{ - return (uvlong)be32(b)<<32 | be32(b+4); -} - -Endian be = { be16, be32, be64 }; -Endian le = { le16, le32, le64 }; - -typedef struct Chain Chain; -struct Chain -{ - Sym *sym; - Chain *up; - int limit; // limit on entry to sym -}; - -static int stkcheck(Chain*, int); -static void stkprint(Chain*, int); -static void stkbroke(Chain*, int); -static Sym *morestack; -static Sym *newstack; - -enum -{ - HasLinkRegister = (thechar == '5'), - CallSize = (!HasLinkRegister)*PtrSize, // bytes of stack required for a call -}; - -void -dostkcheck(void) -{ - Chain ch; - Sym *s; - - morestack = lookup("runtime.morestack", 0); - newstack = lookup("runtime.newstack", 0); - - // First the nosplits on their own. - for(s = textp; s != nil; s = s->next) { - if(s->text == nil || s->text->link == nil || (s->text->textflag & NOSPLIT) == 0) - continue; - cursym = s; - ch.up = nil; - ch.sym = s; - ch.limit = StackLimit - CallSize; - stkcheck(&ch, 0); - s->stkcheck = 1; - } - - // Check calling contexts. - // Some nosplits get called a little further down, - // like newproc and deferproc. We could hard-code - // that knowledge but it's more robust to look at - // the actual call sites. - for(s = textp; s != nil; s = s->next) { - if(s->text == nil || s->text->link == nil || (s->text->textflag & NOSPLIT) != 0) - continue; - cursym = s; - ch.up = nil; - ch.sym = s; - ch.limit = StackLimit - CallSize; - stkcheck(&ch, 0); - } -} - -static int -stkcheck(Chain *up, int depth) -{ - Chain ch, ch1; - Prog *p; - Sym *s; - int limit, prolog; - - limit = up->limit; - s = up->sym; - p = s->text; - - // Small optimization: don't repeat work at top. - if(s->stkcheck && limit == StackLimit-CallSize) - return 0; - - if(depth > 100) { - diag("nosplit stack check too deep"); - stkbroke(up, 0); - return -1; - } - - if(p == nil || p->link == nil) { - // external function. - // should never be called directly. - // only diagnose the direct caller. - if(depth == 1) - diag("call to external function %s", s->name); - return -1; - } - - if(limit < 0) { - stkbroke(up, limit); - return -1; - } - - // morestack looks like it calls functions, - // but it switches the stack pointer first. - if(s == morestack) - return 0; - - ch.up = up; - prolog = (s->text->textflag & NOSPLIT) == 0; - for(p = s->text; p != P; p = p->link) { - limit -= p->spadj; - if(prolog && p->spadj != 0) { - // The first stack adjustment in a function with a - // split-checking prologue marks the end of the - // prologue. Assuming the split check is correct, - // after the adjustment there should still be at least - // StackLimit bytes available below the stack pointer. - // If this is not the top call in the chain, no need - // to duplicate effort, so just stop. - if(depth > 0) - return 0; - prolog = 0; - limit = StackLimit; - } - if(limit < 0) { - stkbroke(up, limit); - return -1; - } - if(iscall(p)) { - limit -= CallSize; - ch.limit = limit; - if(p->to.type == D_BRANCH) { - // Direct call. - ch.sym = p->to.sym; - if(stkcheck(&ch, depth+1) < 0) - return -1; - } else { - // Indirect call. Assume it is a splitting function, - // so we have to make sure it can call morestack. - limit -= CallSize; - ch.sym = nil; - ch1.limit = limit; - ch1.up = &ch; - ch1.sym = morestack; - if(stkcheck(&ch1, depth+2) < 0) - return -1; - limit += CallSize; - } - limit += CallSize; - } - - } - return 0; -} - -static void -stkbroke(Chain *ch, int limit) -{ - diag("nosplit stack overflow"); - stkprint(ch, limit); -} - -static void -stkprint(Chain *ch, int limit) -{ - char *name; - - if(ch->sym) - name = ch->sym->name; - else - name = "function pointer"; - - if(ch->up == nil) { - // top of chain. ch->sym != nil. - if(ch->sym->text->textflag & NOSPLIT) - print("\t%d\tassumed on entry to %s\n", ch->limit, name); - else - print("\t%d\tguaranteed after split check in %s\n", ch->limit, name); - } else { - stkprint(ch->up, ch->limit + (!HasLinkRegister)*PtrSize); - if(!HasLinkRegister) - print("\t%d\ton entry to %s\n", ch->limit, name); - } - if(ch->limit != limit) - print("\t%d\tafter %s uses %d\n", limit, name, ch->limit - limit); -} - -int -headtype(char *name) -{ - int i; - - for(i=0; headers[i].name; i++) - if(strcmp(name, headers[i].name) == 0) { - headstring = headers[i].name; - return headers[i].val; - } - fprint(2, "unknown header type -H %s\n", name); - errorexit(); - return -1; // not reached -} - -void -undef(void) -{ - Sym *s; - - for(s = allsym; s != S; s = s->allsym) - if(s->type == SXREF) - diag("%s(%d): not defined", s->name, s->version); -} - -int -Yconv(Fmt *fp) -{ - Sym *s; - Fmt fmt; - int i; - char *str; - - s = va_arg(fp->args, Sym*); - if (s == S) { - fmtprint(fp, "<nil>"); - } else { - fmtstrinit(&fmt); - fmtprint(&fmt, "%s @0x%08x [%d]", s->name, s->value, s->size); - for (i = 0; i < s->size; i++) { - if (!(i%8)) fmtprint(&fmt, "\n\t0x%04x ", i); - fmtprint(&fmt, "%02x ", s->p[i]); - } - fmtprint(&fmt, "\n"); - for (i = 0; i < s->nr; i++) { - fmtprint(&fmt, "\t0x%04x[%x] %d %s[%llx]\n", - s->r[i].off, - s->r[i].siz, - s->r[i].type, - s->r[i].sym->name, - (vlong)s->r[i].add); - } - str = fmtstrflush(&fmt); - fmtstrcpy(fp, str); - free(str); - } - - return 0; -} diff --git a/src/cmd/ld/lib.h b/src/cmd/ld/lib.h deleted file mode 100644 index 347987195..000000000 --- a/src/cmd/ld/lib.h +++ /dev/null @@ -1,281 +0,0 @@ -// Derived from Inferno utils/6l/l.h -// http://code.google.com/p/inferno-os/source/browse/utils/6l/l.h -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -enum -{ - Sxxx, - - /* order here is order in output file */ - STEXT, - SELFDATA, - SMACHOPLT, - STYPE, - SSTRING, - SGOSTRING, - SRODATA, - SSYMTAB, - SPCLNTAB, - SDATA, - SMACHO, /* Mach-O __nl_symbol_ptr */ - SMACHOGOT, - SWINDOWS, - SBSS, - - SXREF, - SMACHODYNSTR, - SMACHODYNSYM, - SMACHOINDIRECTPLT, - SMACHOINDIRECTGOT, - SFILE, - SCONST, - SDYNIMPORT, - - SSUB = 1<<8, /* sub-symbol, linked from parent via ->sub list */ - - NHASH = 100003, -}; - -typedef struct Library Library; -struct Library -{ - char *objref; // object where we found the reference - char *srcref; // src file where we found the reference - char *file; // object file - char *pkg; // import path -}; - -// Terrible but standard terminology. -// A segment describes a block of file to load into memory. -// A section further describes the pieces of that block for -// use in debuggers and such. - -typedef struct Segment Segment; -typedef struct Section Section; - -struct Segment -{ - uchar rwx; // permission as usual unix bits (5 = r-x etc) - uvlong vaddr; // virtual address - uvlong len; // length in memory - uvlong fileoff; // file offset - uvlong filelen; // length on disk - Section* sect; -}; - -struct Section -{ - uchar rwx; - char *name; - uvlong vaddr; - uvlong len; - Section *next; // in segment list - Segment *seg; -}; - -extern char symname[]; -extern char *libdir[]; -extern int nlibdir; -extern int cout; - -EXTERN char* INITENTRY; -EXTERN char* thestring; -EXTERN Library* library; -EXTERN int libraryp; -EXTERN int nlibrary; -EXTERN Sym* hash[NHASH]; -EXTERN Sym* allsym; -EXTERN Sym* histfrog[MAXHIST]; -EXTERN uchar fnuxi8[8]; -EXTERN uchar fnuxi4[4]; -EXTERN int histfrogp; -EXTERN int histgen; -EXTERN uchar inuxi1[1]; -EXTERN uchar inuxi2[2]; -EXTERN uchar inuxi4[4]; -EXTERN uchar inuxi8[8]; -EXTERN char* outfile; -EXTERN int32 nsymbol; -EXTERN char* thestring; -EXTERN int ndynexp; -EXTERN int havedynamic; - -EXTERN Segment segtext; -EXTERN Segment segdata; -EXTERN Segment segsym; - -void addlib(char *src, char *obj); -void addlibpath(char *srcref, char *objref, char *file, char *pkg); -Section* addsection(Segment*, char*, int); -void copyhistfrog(char *buf, int nbuf); -void addhist(int32 line, int type); -void asmlc(void); -void histtoauto(void); -void collapsefrog(Sym *s); -Sym* lookup(char *symb, int v); -Sym* rlookup(char *symb, int v); -void nuxiinit(void); -int find1(int32 l, int c); -int find2(int32 l, int c); -int32 ieeedtof(Ieee *e); -double ieeedtod(Ieee *e); -void undefsym(Sym *s); -void zerosig(char *sp); -void readundefs(char *f, int t); -int32 Bget4(Biobuf *f); -void loadlib(void); -void errorexit(void); -void mangle(char*); -void objfile(char *file, char *pkg); -void libinit(void); -void pclntab(void); -void symtab(void); -void Lflag(char *arg); -void usage(void); -void adddynrel(Sym*, Reloc*); -void ldobj1(Biobuf *f, char*, int64 len, char *pn); -void ldobj(Biobuf*, char*, int64, char*, int); -void ldelf(Biobuf*, char*, int64, char*); -void ldmacho(Biobuf*, char*, int64, char*); -void ldpe(Biobuf*, char*, int64, char*); -void ldpkg(Biobuf*, char*, int64, char*, int); -void mark(Sym *s); -void mkfwd(void); -char* expandpkg(char*, char*); -void deadcode(void); -void ewrite(int, void*, int); -Reloc* addrel(Sym*); -void codeblk(int32, int32); -void datblk(int32, int32); -Sym* datsort(Sym*); -void reloc(void); -void relocsym(Sym*); -void savedata(Sym*, Prog*, char*); -void symgrow(Sym*, int32); -vlong addstring(Sym*, char*); -vlong adduint32(Sym*, uint32); -vlong adduint64(Sym*, uint64); -vlong addaddr(Sym*, Sym*); -vlong addaddrplus(Sym*, Sym*, int32); -vlong addpcrelplus(Sym*, Sym*, int32); -vlong addsize(Sym*, Sym*); -vlong adduint8(Sym*, uint8); -vlong adduint16(Sym*, uint16); -void asmsym(void); -void asmelfsym(void); -void asmplan9sym(void); -void strnput(char*, int); -void dodata(void); -void address(void); -void textaddress(void); -void genasmsym(void (*put)(Sym*, char*, int, vlong, vlong, int, Sym*)); -vlong datoff(vlong); -void adddynlib(char*); -int archreloc(Reloc*, Sym*, vlong*); -void adddynsym(Sym*); -void addexport(void); -void dostkcheck(void); -void undef(void); -void doweak(void); -void setpersrc(Sym*); - -int pathchar(void); -void* mal(uint32); -void unmal(void*, uint32); -void mywhatsys(void); -int rbyoff(const void*, const void*); - -uint16 le16(uchar*); -uint32 le32(uchar*); -uint64 le64(uchar*); -uint16 be16(uchar*); -uint32 be32(uchar*); -uint64 be64(uchar*); - -typedef struct Endian Endian; -struct Endian -{ - uint16 (*e16)(uchar*); - uint32 (*e32)(uchar*); - uint64 (*e64)(uchar*); -}; - -extern Endian be, le; - -// relocation size bits -enum { - Rbig = 128, - Rlittle = 64, -}; - -/* set by call to mywhatsys() */ -extern char* goroot; -extern char* goarch; -extern char* goos; - -/* whence for ldpkg */ -enum { - FileObj = 0, - ArchiveObj, - Pkgdef -}; - -/* executable header types */ -enum { - Hgarbunix = 0, // garbage unix - Hnoheader, // no header - Hunixcoff, // unix coff - Hrisc, // aif for risc os - Hplan9x32, // plan 9 32-bit format - Hplan9x64, // plan 9 64-bit format - Hmsdoscom, // MS-DOS .COM - Hnetbsd, // NetBSD - Hmsdosexe, // fake MS-DOS .EXE - Hixp1200, // IXP1200 (raw) - Helf, // ELF32 - Hipaq, // ipaq - Hdarwin, // Apple Mach-O - Hlinux, // Linux ELF - Hfreebsd, // FreeBSD ELF - Hwindows, // MS Windows PE -}; - -typedef struct Header Header; -struct Header { - char *name; - int val; -}; - -EXTERN char* headstring; -extern Header headers[]; - -int headtype(char*); - -int Yconv(Fmt*); -#pragma varargck type "Y" Sym* diff --git a/src/cmd/ld/macho.c b/src/cmd/ld/macho.c deleted file mode 100644 index 0b12ac17b..000000000 --- a/src/cmd/ld/macho.c +++ /dev/null @@ -1,518 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Mach-O file writing -// http://developer.apple.com/mac/library/DOCUMENTATION/DeveloperTools/Conceptual/MachORuntime/Reference/reference.html - -#include "l.h" -#include "../ld/dwarf.h" -#include "../ld/lib.h" -#include "../ld/macho.h" - -static int macho64; -static MachoHdr hdr; -static MachoLoad *load; -static MachoSeg seg[16]; -static MachoDebug xdebug[16]; -static int nload, mload, nseg, ndebug, nsect; - -// Amount of space left for adding load commands -// that refer to dynamic libraries. Because these have -// to go in the Mach-O header, we can't just pick a -// "big enough" header size. The initial header is -// one page, the non-dynamic library stuff takes -// up about 1300 bytes; we overestimate that as 2k. -static int load_budget = INITIAL_MACHO_HEADR - 2*1024; - -void -machoinit(void) -{ - switch(thechar) { - // 64-bit architectures - case '6': - macho64 = 1; - break; - - // 32-bit architectures - default: - break; - } -} - -MachoHdr* -getMachoHdr(void) -{ - return &hdr; -} - -MachoLoad* -newMachoLoad(uint32 type, uint32 ndata) -{ - MachoLoad *l; - - if(nload >= mload) { - if(mload == 0) - mload = 1; - else - mload *= 2; - load = realloc(load, mload*sizeof load[0]); - if(load == nil) { - diag("out of memory"); - errorexit(); - } - } - - if(macho64 && (ndata & 1)) - ndata++; - - l = &load[nload++]; - l->type = type; - l->ndata = ndata; - l->data = mal(ndata*4); - return l; -} - -MachoSeg* -newMachoSeg(char *name, int msect) -{ - MachoSeg *s; - - if(nseg >= nelem(seg)) { - diag("too many segs"); - errorexit(); - } - s = &seg[nseg++]; - s->name = name; - s->msect = msect; - s->sect = mal(msect*sizeof s->sect[0]); - return s; -} - -MachoSect* -newMachoSect(MachoSeg *seg, char *name) -{ - MachoSect *s; - - if(seg->nsect >= seg->msect) { - diag("too many sects in segment %s", seg->name); - errorexit(); - } - s = &seg->sect[seg->nsect++]; - s->name = name; - nsect++; - return s; -} - -MachoDebug* -newMachoDebug(void) -{ - if(ndebug >= nelem(xdebug)) { - diag("too many debugs"); - errorexit(); - } - return &xdebug[ndebug++]; -} - - -// Generic linking code. - -static char **dylib; -static int ndylib; - -static vlong linkoff; - -int -machowrite(void) -{ - vlong o1; - int loadsize; - int i, j; - MachoSeg *s; - MachoSect *t; - MachoDebug *d; - MachoLoad *l; - - o1 = cpos(); - - loadsize = 4*4*ndebug; - for(i=0; i<nload; i++) - loadsize += 4*(load[i].ndata+2); - if(macho64) { - loadsize += 18*4*nseg; - loadsize += 20*4*nsect; - } else { - loadsize += 14*4*nseg; - loadsize += 17*4*nsect; - } - - if(macho64) - LPUT(0xfeedfacf); - else - LPUT(0xfeedface); - LPUT(hdr.cpu); - LPUT(hdr.subcpu); - LPUT(2); /* file type - mach executable */ - LPUT(nload+nseg+ndebug); - LPUT(loadsize); - LPUT(1); /* flags - no undefines */ - if(macho64) - LPUT(0); /* reserved */ - - for(i=0; i<nseg; i++) { - s = &seg[i]; - if(macho64) { - LPUT(25); /* segment 64 */ - LPUT(72+80*s->nsect); - strnput(s->name, 16); - VPUT(s->vaddr); - VPUT(s->vsize); - VPUT(s->fileoffset); - VPUT(s->filesize); - LPUT(s->prot1); - LPUT(s->prot2); - LPUT(s->nsect); - LPUT(s->flag); - } else { - LPUT(1); /* segment 32 */ - LPUT(56+68*s->nsect); - strnput(s->name, 16); - LPUT(s->vaddr); - LPUT(s->vsize); - LPUT(s->fileoffset); - LPUT(s->filesize); - LPUT(s->prot1); - LPUT(s->prot2); - LPUT(s->nsect); - LPUT(s->flag); - } - for(j=0; j<s->nsect; j++) { - t = &s->sect[j]; - if(macho64) { - strnput(t->name, 16); - strnput(s->name, 16); - VPUT(t->addr); - VPUT(t->size); - LPUT(t->off); - LPUT(t->align); - LPUT(t->reloc); - LPUT(t->nreloc); - LPUT(t->flag); - LPUT(t->res1); /* reserved */ - LPUT(t->res2); /* reserved */ - LPUT(0); /* reserved */ - } else { - strnput(t->name, 16); - strnput(s->name, 16); - LPUT(t->addr); - LPUT(t->size); - LPUT(t->off); - LPUT(t->align); - LPUT(t->reloc); - LPUT(t->nreloc); - LPUT(t->flag); - LPUT(t->res1); /* reserved */ - LPUT(t->res2); /* reserved */ - } - } - } - - for(i=0; i<nload; i++) { - l = &load[i]; - LPUT(l->type); - LPUT(4*(l->ndata+2)); - for(j=0; j<l->ndata; j++) - LPUT(l->data[j]); - } - - for(i=0; i<ndebug; i++) { - d = &xdebug[i]; - LPUT(3); /* obsolete gdb debug info */ - LPUT(16); /* size of symseg command */ - LPUT(d->fileoffset); - LPUT(d->filesize); - } - - return cpos() - o1; -} - -void -domacho(void) -{ - Sym *s; - - if(debug['d']) - return; - - // empirically, string table must begin with " \x00". - s = lookup(".dynstr", 0); - s->type = SMACHODYNSTR; - s->reachable = 1; - adduint8(s, ' '); - adduint8(s, '\0'); - - s = lookup(".dynsym", 0); - s->type = SMACHODYNSYM; - s->reachable = 1; - - s = lookup(".plt", 0); // will be __symbol_stub - s->type = SMACHOPLT; - s->reachable = 1; - - s = lookup(".got", 0); // will be __nl_symbol_ptr - s->type = SMACHOGOT; - s->reachable = 1; - - s = lookup(".linkedit.plt", 0); // indirect table for .plt - s->type = SMACHOINDIRECTPLT; - s->reachable = 1; - - s = lookup(".linkedit.got", 0); // indirect table for .got - s->type = SMACHOINDIRECTGOT; - s->reachable = 1; -} - -void -machoadddynlib(char *lib) -{ - // Will need to store the library name rounded up - // and 24 bytes of header metadata. If not enough - // space, grab another page of initial space at the - // beginning of the output file. - load_budget -= (strlen(lib)+7)/8*8 + 24; - if(load_budget < 0) { - HEADR += 4096; - INITTEXT += 4096; - load_budget += 4096; - } - - if(ndylib%32 == 0) { - dylib = realloc(dylib, (ndylib+32)*sizeof dylib[0]); - if(dylib == nil) { - diag("out of memory"); - errorexit(); - } - } - dylib[ndylib++] = lib; -} - -void -asmbmacho(void) -{ - vlong v, w; - vlong va; - int a, i; - MachoHdr *mh; - MachoSect *msect; - MachoSeg *ms; - MachoDebug *md; - MachoLoad *ml; - Sym *s; - - /* apple MACH */ - va = INITTEXT - HEADR; - mh = getMachoHdr(); - switch(thechar){ - default: - diag("unknown mach architecture"); - errorexit(); - case '6': - mh->cpu = MACHO_CPU_AMD64; - mh->subcpu = MACHO_SUBCPU_X86; - break; - case '8': - mh->cpu = MACHO_CPU_386; - mh->subcpu = MACHO_SUBCPU_X86; - break; - } - - /* segment for zero page */ - ms = newMachoSeg("__PAGEZERO", 0); - ms->vsize = va; - - /* text */ - v = rnd(HEADR+segtext.len, INITRND); - ms = newMachoSeg("__TEXT", 2); - ms->vaddr = va; - ms->vsize = v; - ms->filesize = v; - ms->prot1 = 7; - ms->prot2 = 5; - - msect = newMachoSect(ms, "__text"); - msect->addr = INITTEXT; - msect->size = segtext.sect->len; - msect->off = INITTEXT - va; - msect->flag = 0x400; /* flag - some instructions */ - - s = lookup(".plt", 0); - if(s->size > 0) { - msect = newMachoSect(ms, "__symbol_stub1"); - msect->addr = symaddr(s); - msect->size = s->size; - msect->off = ms->fileoffset + msect->addr - ms->vaddr; - msect->flag = 0x80000408; /* flag */ - msect->res1 = 0; /* index into indirect symbol table */ - msect->res2 = 6; /* size of stubs */ - } - - /* data */ - w = segdata.len; - ms = newMachoSeg("__DATA", 3); - ms->vaddr = va+v; - ms->vsize = w; - ms->fileoffset = v; - ms->filesize = segdata.filelen; - ms->prot1 = 7; - ms->prot2 = 3; - - msect = newMachoSect(ms, "__data"); - msect->addr = va+v; - msect->off = v; - msect->size = segdata.filelen; - - s = lookup(".got", 0); - if(s->size > 0) { - msect->size = symaddr(s) - msect->addr; - - msect = newMachoSect(ms, "__nl_symbol_ptr"); - msect->addr = symaddr(s); - msect->size = s->size; - msect->off = datoff(msect->addr); - msect->align = 2; - msect->flag = 6; /* section with nonlazy symbol pointers */ - msect->res1 = lookup(".linkedit.plt", 0)->size / 4; /* offset into indirect symbol table */ - } - - msect = newMachoSect(ms, "__bss"); - msect->addr = va+v+segdata.filelen; - msect->size = segdata.len - segdata.filelen; - msect->flag = 1; /* flag - zero fill */ - - switch(thechar) { - default: - diag("unknown macho architecture"); - errorexit(); - case '6': - ml = newMachoLoad(5, 42+2); /* unix thread */ - ml->data[0] = 4; /* thread type */ - ml->data[1] = 42; /* word count */ - ml->data[2+32] = entryvalue(); /* start pc */ - ml->data[2+32+1] = entryvalue()>>16>>16; // hide >>32 for 8l - break; - case '8': - ml = newMachoLoad(5, 16+2); /* unix thread */ - ml->data[0] = 1; /* thread type */ - ml->data[1] = 16; /* word count */ - ml->data[2+10] = entryvalue(); /* start pc */ - break; - } - - if(!debug['d']) { - Sym *s1, *s2, *s3, *s4; - - // must match domacholink below - s1 = lookup(".dynsym", 0); - s2 = lookup(".dynstr", 0); - s3 = lookup(".linkedit.plt", 0); - s4 = lookup(".linkedit.got", 0); - - ms = newMachoSeg("__LINKEDIT", 0); - ms->vaddr = va+v+rnd(segdata.len, INITRND); - ms->vsize = s1->size + s2->size + s3->size + s4->size; - ms->fileoffset = linkoff; - ms->filesize = ms->vsize; - ms->prot1 = 7; - ms->prot2 = 3; - - ml = newMachoLoad(2, 4); /* LC_SYMTAB */ - ml->data[0] = linkoff; /* symoff */ - ml->data[1] = s1->size / (macho64 ? 16 : 12); /* nsyms */ - ml->data[2] = linkoff + s1->size; /* stroff */ - ml->data[3] = s2->size; /* strsize */ - - ml = newMachoLoad(11, 18); /* LC_DYSYMTAB */ - ml->data[0] = 0; /* ilocalsym */ - ml->data[1] = 0; /* nlocalsym */ - ml->data[2] = 0; /* iextdefsym */ - ml->data[3] = ndynexp; /* nextdefsym */ - ml->data[4] = ndynexp; /* iundefsym */ - ml->data[5] = (s1->size / (macho64 ? 16 : 12)) - ndynexp; /* nundefsym */ - ml->data[6] = 0; /* tocoffset */ - ml->data[7] = 0; /* ntoc */ - ml->data[8] = 0; /* modtaboff */ - ml->data[9] = 0; /* nmodtab */ - ml->data[10] = 0; /* extrefsymoff */ - ml->data[11] = 0; /* nextrefsyms */ - ml->data[12] = linkoff + s1->size + s2->size; /* indirectsymoff */ - ml->data[13] = (s3->size + s4->size) / 4; /* nindirectsyms */ - ml->data[14] = 0; /* extreloff */ - ml->data[15] = 0; /* nextrel */ - ml->data[16] = 0; /* locreloff */ - ml->data[17] = 0; /* nlocrel */ - - ml = newMachoLoad(14, 6); /* LC_LOAD_DYLINKER */ - ml->data[0] = 12; /* offset to string */ - strcpy((char*)&ml->data[1], "/usr/lib/dyld"); - - for(i=0; i<ndylib; i++) { - ml = newMachoLoad(12, 4+(strlen(dylib[i])+1+7)/8*2); /* LC_LOAD_DYLIB */ - ml->data[0] = 24; /* offset of string from beginning of load */ - ml->data[1] = 0; /* time stamp */ - ml->data[2] = 0; /* version */ - ml->data[3] = 0; /* compatibility version */ - strcpy((char*)&ml->data[4], dylib[i]); - } - } - - if(!debug['s']) { - Sym *s; - - md = newMachoDebug(); - s = lookup("symtab", 0); - md->fileoffset = datoff(s->value); - md->filesize = s->size; - - md = newMachoDebug(); - s = lookup("pclntab", 0); - md->fileoffset = datoff(s->value); - md->filesize = s->size; - - dwarfaddmachoheaders(); - } - - a = machowrite(); - if(a > HEADR) - diag("HEADR too small: %d > %d", a, HEADR); -} - -vlong -domacholink(void) -{ - int size; - Sym *s1, *s2, *s3, *s4; - - // write data that will be linkedit section - s1 = lookup(".dynsym", 0); - relocsym(s1); - s2 = lookup(".dynstr", 0); - s3 = lookup(".linkedit.plt", 0); - s4 = lookup(".linkedit.got", 0); - - while(s2->size%4) - adduint8(s2, 0); - - size = s1->size + s2->size + s3->size + s4->size; - - if(size > 0) { - linkoff = rnd(HEADR+segtext.len, INITRND) + rnd(segdata.filelen, INITRND); - seek(cout, linkoff, 0); - - ewrite(cout, s1->p, s1->size); - ewrite(cout, s2->p, s2->size); - ewrite(cout, s3->p, s3->size); - ewrite(cout, s4->p, s4->size); - } - - return rnd(size, INITRND); -} diff --git a/src/cmd/ld/macho.h b/src/cmd/ld/macho.h deleted file mode 100644 index f55104150..000000000 --- a/src/cmd/ld/macho.h +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -typedef struct MachoHdr MachoHdr; -struct MachoHdr { - uint32 cpu; - uint32 subcpu; -}; - -typedef struct MachoSect MachoSect; -struct MachoSect { - char* name; - uint64 addr; - uint64 size; - uint32 off; - uint32 align; - uint32 reloc; - uint32 nreloc; - uint32 flag; - uint32 res1; - uint32 res2; -}; - -typedef struct MachoSeg MachoSeg; -struct MachoSeg { - char* name; - uint64 vsize; - uint64 vaddr; - uint64 fileoffset; - uint64 filesize; - uint32 prot1; - uint32 prot2; - uint32 nsect; - uint32 msect; - MachoSect *sect; - uint32 flag; -}; - -typedef struct MachoLoad MachoLoad; -struct MachoLoad { - uint32 type; - uint32 ndata; - uint32 *data; -}; - -typedef struct MachoDebug MachoDebug; -struct MachoDebug { - uint32 fileoffset; - uint32 filesize; -}; - -MachoHdr* getMachoHdr(); -MachoSeg* newMachoSeg(char*, int); -MachoSect* newMachoSect(MachoSeg*, char*); -MachoLoad* newMachoLoad(uint32, uint32); -MachoDebug* newMachoDebug(void); -int machowrite(void); -void machoinit(void); - -/* - * Total amount of space to reserve at the start of the file - * for Header, PHeaders, and SHeaders. - * May waste some. - */ -#define INITIAL_MACHO_HEADR 4*1024 - -enum { - MACHO_CPU_AMD64 = (1<<24)|7, - MACHO_CPU_386 = 7, - MACHO_SUBCPU_X86 = 3, - - MACHO32SYMSIZE = 12, - MACHO64SYMSIZE = 16, - - MACHO_X86_64_RELOC_UNSIGNED = 0, - MACHO_X86_64_RELOC_SIGNED = 1, - MACHO_X86_64_RELOC_BRANCH = 2, - MACHO_X86_64_RELOC_GOT_LOAD = 3, - MACHO_X86_64_RELOC_GOT = 4, - MACHO_X86_64_RELOC_SUBTRACTOR = 5, - MACHO_X86_64_RELOC_SIGNED_1 = 6, - MACHO_X86_64_RELOC_SIGNED_2 = 7, - MACHO_X86_64_RELOC_SIGNED_4 = 8, - - MACHO_GENERIC_RELOC_VANILLA = 0, - - MACHO_FAKE_GOTPCREL = 100, -}; - -void domacho(void); -vlong domacholink(void); -void asmbmacho(void); -void machoadddynlib(char*); diff --git a/src/cmd/ld/pe.c b/src/cmd/ld/pe.c deleted file mode 100644 index 9ac0a50d8..000000000 --- a/src/cmd/ld/pe.c +++ /dev/null @@ -1,583 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// PE (Portable Executable) file writing -// http://www.microsoft.com/whdc/system/platform/firmware/PECOFF.mspx - -#include "l.h" -#include "../ld/lib.h" -#include "../ld/pe.h" -#include "../ld/dwarf.h" - -// DOS stub that prints out -// "This program cannot be run in DOS mode." -static char dosstub[] = -{ - 0x4d, 0x5a, 0x90, 0x00, 0x03, 0x00, 0x04, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, - 0x8b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, - 0x0e, 0x1f, 0xba, 0x0e, 0x00, 0xb4, 0x09, 0xcd, - 0x21, 0xb8, 0x01, 0x4c, 0xcd, 0x21, 0x54, 0x68, - 0x69, 0x73, 0x20, 0x70, 0x72, 0x6f, 0x67, 0x72, - 0x61, 0x6d, 0x20, 0x63, 0x61, 0x6e, 0x6e, 0x6f, - 0x74, 0x20, 0x62, 0x65, 0x20, 0x72, 0x75, 0x6e, - 0x20, 0x69, 0x6e, 0x20, 0x44, 0x4f, 0x53, 0x20, - 0x6d, 0x6f, 0x64, 0x65, 0x2e, 0x0d, 0x0d, 0x0a, - 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -}; - -static Sym *rsrcsym; - -static char symnames[256]; -static int nextsymoff; - -int32 PESECTHEADR; -int32 PEFILEHEADR; - -static int pe64; -static int nsect; -static int nextsectoff; -static int nextfileoff; - -static IMAGE_FILE_HEADER fh; -static IMAGE_OPTIONAL_HEADER oh; -static PE64_IMAGE_OPTIONAL_HEADER oh64; -static IMAGE_SECTION_HEADER sh[16]; -static IMAGE_DATA_DIRECTORY* dd; - -#define set(n, v) (pe64 ? (oh64.n = v) : (oh.n = v)) -#define put(v) (pe64 ? vputl(v) : lputl(v)) - -typedef struct Imp Imp; -struct Imp { - Sym* s; - uvlong off; - Imp* next; -}; - -typedef struct Dll Dll; -struct Dll { - char* name; - uvlong nameoff; - uvlong thunkoff; - Imp* ms; - Dll* next; -}; - -static Dll* dr; - -static Sym *dexport[1024]; -static int nexport; - -static IMAGE_SECTION_HEADER* -addpesection(char *name, int sectsize, int filesize, Segment *s) -{ - IMAGE_SECTION_HEADER *h; - - if(nsect == 16) { - diag("too many sections"); - errorexit(); - } - h = &sh[nsect++]; - strncpy((char*)h->Name, name, sizeof(h->Name)); - h->VirtualSize = sectsize; - h->VirtualAddress = nextsectoff; - nextsectoff = rnd(nextsectoff+sectsize, PESECTALIGN); - h->PointerToRawData = nextfileoff; - if(filesize > 0) { - h->SizeOfRawData = rnd(filesize, PEFILEALIGN); - nextfileoff += h->SizeOfRawData; - } - if(s) { - if(s->vaddr-PEBASE != h->VirtualAddress) { - diag("%s.VirtualAddress = %#llux, want %#llux", name, (vlong)h->VirtualAddress, (vlong)(s->vaddr-PEBASE)); - errorexit(); - } - if(s->fileoff != h->PointerToRawData) { - diag("%s.PointerToRawData = %#llux, want %#llux", name, (vlong)h->PointerToRawData, (vlong)(s->fileoff)); - errorexit(); - } - } - return h; -} - -void -peinit(void) -{ - int32 l; - - switch(thechar) { - // 64-bit architectures - case '6': - pe64 = 1; - l = sizeof(oh64); - dd = oh64.DataDirectory; - break; - // 32-bit architectures - default: - l = sizeof(oh); - dd = oh.DataDirectory; - break; - } - - PEFILEHEADR = rnd(sizeof(dosstub)+sizeof(fh)+l+sizeof(sh), PEFILEALIGN); - PESECTHEADR = rnd(PEFILEHEADR, PESECTALIGN); - nextsectoff = PESECTHEADR; - nextfileoff = PEFILEHEADR; -} - -static void -pewrite(void) -{ - seek(cout, 0, 0); - ewrite(cout, dosstub, sizeof dosstub); - strnput("PE", 4); - cflush(); - // TODO: This code should not assume that the - // memory representation is little-endian or - // that the structs are packed identically to - // their file representation. - ewrite(cout, &fh, sizeof fh); - if(pe64) - ewrite(cout, &oh64, sizeof oh64); - else - ewrite(cout, &oh, sizeof oh); - ewrite(cout, sh, nsect * sizeof sh[0]); -} - -static void -strput(char *s) -{ - int n; - - for(n=0; *s; n++) - cput(*s++); - cput('\0'); - n++; - // string must be padded to even size - if(n%2) - cput('\0'); -} - -static Dll* -initdynimport(void) -{ - Imp *m; - Dll *d; - Sym *s, *dynamic; - - dr = nil; - m = nil; - for(s = allsym; s != S; s = s->allsym) { - if(!s->reachable || !s->dynimpname || s->dynexport) - continue; - for(d = dr; d != nil; d = d->next) { - if(strcmp(d->name,s->dynimplib) == 0) { - m = mal(sizeof *m); - break; - } - } - if(d == nil) { - d = mal(sizeof *d); - d->name = s->dynimplib; - d->next = dr; - dr = d; - m = mal(sizeof *m); - } - m->s = s; - m->next = d->ms; - d->ms = m; - } - - dynamic = lookup(".windynamic", 0); - dynamic->reachable = 1; - dynamic->type = SWINDOWS; - for(d = dr; d != nil; d = d->next) { - for(m = d->ms; m != nil; m = m->next) { - m->s->type = SWINDOWS | SSUB; - m->s->sub = dynamic->sub; - dynamic->sub = m->s; - m->s->value = dynamic->size; - dynamic->size += PtrSize; - } - dynamic->size += PtrSize; - } - - return dr; -} - -static void -addimports(vlong fileoff, IMAGE_SECTION_HEADER *datsect) -{ - IMAGE_SECTION_HEADER *isect; - uvlong n, oftbase, ftbase; - Imp *m; - Dll *d; - Sym* dynamic; - - dynamic = lookup(".windynamic", 0); - - // skip import descriptor table (will write it later) - n = 0; - for(d = dr; d != nil; d = d->next) - n++; - seek(cout, fileoff + sizeof(IMAGE_IMPORT_DESCRIPTOR) * (n + 1), 0); - - // write dll names - for(d = dr; d != nil; d = d->next) { - d->nameoff = cpos() - fileoff; - strput(d->name); - } - - // write function names - for(d = dr; d != nil; d = d->next) { - for(m = d->ms; m != nil; m = m->next) { - m->off = nextsectoff + cpos() - fileoff; - wputl(0); // hint - strput(m->s->dynimpname); - } - } - - // write OriginalFirstThunks - oftbase = cpos() - fileoff; - n = cpos(); - for(d = dr; d != nil; d = d->next) { - d->thunkoff = cpos() - n; - for(m = d->ms; m != nil; m = m->next) - put(m->off); - put(0); - } - - // add pe section and pad it at the end - n = cpos() - fileoff; - isect = addpesection(".idata", n, n, 0); - isect->Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA| - IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE; - strnput("", isect->SizeOfRawData - n); - cflush(); - - // write FirstThunks (allocated in .data section) - ftbase = dynamic->value - datsect->VirtualAddress - PEBASE; - seek(cout, datsect->PointerToRawData + ftbase, 0); - for(d = dr; d != nil; d = d->next) { - for(m = d->ms; m != nil; m = m->next) - put(m->off); - put(0); - } - cflush(); - - // finally write import descriptor table - seek(cout, fileoff, 0); - for(d = dr; d != nil; d = d->next) { - lputl(isect->VirtualAddress + oftbase + d->thunkoff); - lputl(0); - lputl(0); - lputl(isect->VirtualAddress + d->nameoff); - lputl(datsect->VirtualAddress + ftbase + d->thunkoff); - } - lputl(0); //end - lputl(0); - lputl(0); - lputl(0); - lputl(0); - cflush(); - - // update data directory - dd[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = isect->VirtualAddress; - dd[IMAGE_DIRECTORY_ENTRY_IMPORT].Size = isect->VirtualSize; - dd[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress = dynamic->value - PEBASE; - dd[IMAGE_DIRECTORY_ENTRY_IAT].Size = dynamic->size; - - seek(cout, 0, 2); -} - -static int -scmp(const void *p1, const void *p2) -{ - Sym *s1, *s2; - - s1 = *(Sym**)p1; - s2 = *(Sym**)p2; - return strcmp(s1->dynimpname, s2->dynimpname); -} - -static void -initdynexport(void) -{ - Sym *s; - - nexport = 0; - for(s = allsym; s != S; s = s->allsym) { - if(!s->reachable || !s->dynimpname || !s->dynexport) - continue; - if(nexport+1 > sizeof(dexport)/sizeof(dexport[0])) { - diag("pe dynexport table is full"); - errorexit(); - } - - dexport[nexport] = s; - nexport++; - } - - qsort(dexport, nexport, sizeof dexport[0], scmp); -} - -void -addexports(vlong fileoff) -{ - IMAGE_SECTION_HEADER *sect; - IMAGE_EXPORT_DIRECTORY e; - int size, i, va, va_name, va_addr, va_na, v; - - size = sizeof e + 10*nexport + strlen(outfile) + 1; - for(i=0; i<nexport; i++) - size += strlen(dexport[i]->dynimpname) + 1; - - if (nexport == 0) - return; - - sect = addpesection(".edata", size, size, 0); - sect->Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_MEM_READ; - va = sect->VirtualAddress; - dd[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress = va; - dd[IMAGE_DIRECTORY_ENTRY_EXPORT].Size = sect->VirtualSize; - - seek(cout, fileoff, 0); - va_name = va + sizeof e + nexport*4; - va_addr = va + sizeof e; - va_na = va + sizeof e + nexport*8; - - e.Characteristics = 0; - e.MajorVersion = 0; - e.MinorVersion = 0; - e.NumberOfFunctions = nexport; - e.NumberOfNames = nexport; - e.Name = va + sizeof e + nexport*10; // Program names. - e.Base = 1; - e.AddressOfFunctions = va_addr; - e.AddressOfNames = va_name; - e.AddressOfNameOrdinals = va_na; - // put IMAGE_EXPORT_DIRECTORY - for (i=0; i<sizeof(e); i++) - cput(((char*)&e)[i]); - // put EXPORT Address Table - for(i=0; i<nexport; i++) - lputl(dexport[i]->value - PEBASE); - // put EXPORT Name Pointer Table - v = e.Name + strlen(outfile)+1; - for(i=0; i<nexport; i++) { - lputl(v); - v += strlen(dexport[i]->dynimpname)+1; - } - // put EXPORT Ordinal Table - for(i=0; i<nexport; i++) - wputl(i); - // put Names - strnput(outfile, strlen(outfile)+1); - for(i=0; i<nexport; i++) - strnput(dexport[i]->dynimpname, strlen(dexport[i]->dynimpname)+1); - strnput("", sect->SizeOfRawData - size); - cflush(); - - seek(cout, 0, 2); -} - -void -dope(void) -{ - Sym *rel; - - /* relocation table */ - rel = lookup(".rel", 0); - rel->reachable = 1; - rel->type = SELFDATA; - - initdynimport(); - initdynexport(); -} - -/* - * For more than 8 characters section names, name contains a slash (/) that is - * followed by an ASCII representation of a decimal number that is an offset into - * the string table. - * reference: pecoff_v8.docx Page 24. - * <http://www.microsoft.com/whdc/system/platform/firmware/PECOFFdwn.mspx> - */ -IMAGE_SECTION_HEADER* -newPEDWARFSection(char *name, vlong size) -{ - IMAGE_SECTION_HEADER *h; - char s[8]; - - if(size == 0) - return nil; - - if(nextsymoff+strlen(name)+1 > sizeof(symnames)) { - diag("pe string table is full"); - errorexit(); - } - - strcpy(&symnames[nextsymoff], name); - sprint(s, "/%d\0", nextsymoff+4); - nextsymoff += strlen(name); - symnames[nextsymoff] = 0; - nextsymoff ++; - h = addpesection(s, size, size, 0); - h->Characteristics = IMAGE_SCN_MEM_READ| - IMAGE_SCN_MEM_DISCARDABLE; - - return h; -} - -static void -addsymtable(void) -{ - IMAGE_SECTION_HEADER *h; - int i, size; - - if(nextsymoff == 0) - return; - - size = nextsymoff + 4; - h = addpesection(".symtab", size, size, 0); - h->Characteristics = IMAGE_SCN_MEM_READ| - IMAGE_SCN_MEM_DISCARDABLE; - fh.PointerToSymbolTable = cpos(); - fh.NumberOfSymbols = 0; - // put symbol string table - lputl(size); - for (i=0; i<nextsymoff; i++) - cput(symnames[i]); - strnput("", h->SizeOfRawData - size); - cflush(); -} - -void -setpersrc(Sym *sym) -{ - if(rsrcsym != nil) - diag("too many .rsrc sections"); - - rsrcsym = sym; -} - -void -addpersrc(void) -{ - IMAGE_SECTION_HEADER *h; - uchar *p; - uint32 val; - Reloc *r; - - if(rsrcsym == nil) - return; - - h = addpesection(".rsrc", rsrcsym->size, rsrcsym->size, 0); - h->Characteristics = IMAGE_SCN_MEM_READ| - IMAGE_SCN_MEM_WRITE | IMAGE_SCN_CNT_INITIALIZED_DATA; - // relocation - for(r=rsrcsym->r; r<rsrcsym->r+rsrcsym->nr; r++) { - p = rsrcsym->p + r->off; - val = h->VirtualAddress + r->add; - // 32-bit little-endian - p[0] = val; - p[1] = val>>8; - p[2] = val>>16; - p[3] = val>>24; - } - ewrite(cout, rsrcsym->p, rsrcsym->size); - strnput("", h->SizeOfRawData - rsrcsym->size); - cflush(); - - // update data directory - dd[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress = h->VirtualAddress; - dd[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size = h->VirtualSize; -} - -void -asmbpe(void) -{ - IMAGE_SECTION_HEADER *t, *d; - - switch(thechar) { - default: - diag("unknown PE architecture"); - errorexit(); - case '6': - fh.Machine = IMAGE_FILE_MACHINE_AMD64; - break; - case '8': - fh.Machine = IMAGE_FILE_MACHINE_I386; - break; - } - - t = addpesection(".text", segtext.len, segtext.len, &segtext); - t->Characteristics = IMAGE_SCN_CNT_CODE| - IMAGE_SCN_CNT_INITIALIZED_DATA| - IMAGE_SCN_MEM_EXECUTE|IMAGE_SCN_MEM_READ; - - d = addpesection(".data", segdata.len, segdata.filelen, &segdata); - d->Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA| - IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE; - - if(!debug['s']) - dwarfaddpeheaders(); - - addimports(nextfileoff, d); - - addexports(nextfileoff); - - addsymtable(); - - addpersrc(); - - fh.NumberOfSections = nsect; - fh.TimeDateStamp = time(0); - fh.Characteristics = IMAGE_FILE_RELOCS_STRIPPED| - IMAGE_FILE_EXECUTABLE_IMAGE|IMAGE_FILE_DEBUG_STRIPPED; - if (pe64) { - fh.SizeOfOptionalHeader = sizeof(oh64); - fh.Characteristics |= IMAGE_FILE_LARGE_ADDRESS_AWARE; - set(Magic, 0x20b); // PE32+ - } else { - fh.SizeOfOptionalHeader = sizeof(oh); - fh.Characteristics |= IMAGE_FILE_32BIT_MACHINE; - set(Magic, 0x10b); // PE32 - oh.BaseOfData = d->VirtualAddress; - } - set(MajorLinkerVersion, 1); - set(MinorLinkerVersion, 0); - set(SizeOfCode, t->SizeOfRawData); - set(SizeOfInitializedData, d->SizeOfRawData); - set(SizeOfUninitializedData, 0); - set(AddressOfEntryPoint, entryvalue()-PEBASE); - set(BaseOfCode, t->VirtualAddress); - set(ImageBase, PEBASE); - set(SectionAlignment, PESECTALIGN); - set(FileAlignment, PEFILEALIGN); - set(MajorOperatingSystemVersion, 4); - set(MinorOperatingSystemVersion, 0); - set(MajorImageVersion, 1); - set(MinorImageVersion, 0); - set(MajorSubsystemVersion, 4); - set(MinorSubsystemVersion, 0); - set(SizeOfImage, nextsectoff); - set(SizeOfHeaders, PEFILEHEADR); - if(strcmp(headstring, "windowsgui") == 0) - set(Subsystem, IMAGE_SUBSYSTEM_WINDOWS_GUI); - else - set(Subsystem, IMAGE_SUBSYSTEM_WINDOWS_CUI); - set(SizeOfStackReserve, 0x0040000); - set(SizeOfStackCommit, 0x00001000); - set(SizeOfHeapReserve, 0x00100000); - set(SizeOfHeapCommit, 0x00001000); - set(NumberOfRvaAndSizes, 16); - - pewrite(); -} diff --git a/src/cmd/ld/pe.h b/src/cmd/ld/pe.h deleted file mode 100644 index 7aa938829..000000000 --- a/src/cmd/ld/pe.h +++ /dev/null @@ -1,179 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -typedef struct { - uint16 Machine; - uint16 NumberOfSections; - uint32 TimeDateStamp; - uint32 PointerToSymbolTable; - uint32 NumberOfSymbols; - uint16 SizeOfOptionalHeader; - uint16 Characteristics; -} IMAGE_FILE_HEADER; - -typedef struct { - uint32 VirtualAddress; - uint32 Size; -} IMAGE_DATA_DIRECTORY; - -typedef struct { - uint16 Magic; - uint8 MajorLinkerVersion; - uint8 MinorLinkerVersion; - uint32 SizeOfCode; - uint32 SizeOfInitializedData; - uint32 SizeOfUninitializedData; - uint32 AddressOfEntryPoint; - uint32 BaseOfCode; - uint32 BaseOfData; - uint32 ImageBase; - uint32 SectionAlignment; - uint32 FileAlignment; - uint16 MajorOperatingSystemVersion; - uint16 MinorOperatingSystemVersion; - uint16 MajorImageVersion; - uint16 MinorImageVersion; - uint16 MajorSubsystemVersion; - uint16 MinorSubsystemVersion; - uint32 Win32VersionValue; - uint32 SizeOfImage; - uint32 SizeOfHeaders; - uint32 CheckSum; - uint16 Subsystem; - uint16 DllCharacteristics; - uint32 SizeOfStackReserve; - uint32 SizeOfStackCommit; - uint32 SizeOfHeapReserve; - uint32 SizeOfHeapCommit; - uint32 LoaderFlags; - uint32 NumberOfRvaAndSizes; - IMAGE_DATA_DIRECTORY DataDirectory[16]; -} IMAGE_OPTIONAL_HEADER; - -typedef struct { - uint8 Name[8]; - uint32 VirtualSize; - uint32 VirtualAddress; - uint32 SizeOfRawData; - uint32 PointerToRawData; - uint32 PointerToRelocations; - uint32 PointerToLineNumbers; - uint16 NumberOfRelocations; - uint16 NumberOfLineNumbers; - uint32 Characteristics; -} IMAGE_SECTION_HEADER; - -typedef struct { - uint32 OriginalFirstThunk; - uint32 TimeDateStamp; - uint32 ForwarderChain; - uint32 Name; - uint32 FirstThunk; -} IMAGE_IMPORT_DESCRIPTOR; - -typedef struct _IMAGE_EXPORT_DIRECTORY { - uint32 Characteristics; - uint32 TimeDateStamp; - uint16 MajorVersion; - uint16 MinorVersion; - uint32 Name; - uint32 Base; - uint32 NumberOfFunctions; - uint32 NumberOfNames; - uint32 AddressOfFunctions; - uint32 AddressOfNames; - uint32 AddressOfNameOrdinals; -} IMAGE_EXPORT_DIRECTORY; - -#define PEBASE 0x00400000 -// SectionAlignment must be greater than or equal to FileAlignment. -// The default is the page size for the architecture. -#define PESECTALIGN 0x1000 -// FileAlignment should be a power of 2 between 512 and 64 K, inclusive. -// The default is 512. If the SectionAlignment is less than -// the architecture's page size, then FileAlignment must match SectionAlignment. -#define PEFILEALIGN (2<<8) -extern int32 PESECTHEADR; -extern int32 PEFILEHEADR; - -enum { - IMAGE_FILE_MACHINE_I386 = 0x14c, - IMAGE_FILE_MACHINE_AMD64 = 0x8664, - - IMAGE_FILE_RELOCS_STRIPPED = 0x0001, - IMAGE_FILE_EXECUTABLE_IMAGE = 0x0002, - IMAGE_FILE_LARGE_ADDRESS_AWARE = 0x0020, - IMAGE_FILE_32BIT_MACHINE = 0x0100, - IMAGE_FILE_DEBUG_STRIPPED = 0x0200, - - IMAGE_SCN_CNT_CODE = 0x00000020, - IMAGE_SCN_CNT_INITIALIZED_DATA = 0x00000040, - IMAGE_SCN_CNT_UNINITIALIZED_DATA = 0x00000080, - IMAGE_SCN_MEM_EXECUTE = 0x20000000, - IMAGE_SCN_MEM_READ = 0x40000000, - IMAGE_SCN_MEM_WRITE = 0x80000000, - IMAGE_SCN_MEM_DISCARDABLE = 0x2000000, - - IMAGE_DIRECTORY_ENTRY_EXPORT = 0, - IMAGE_DIRECTORY_ENTRY_IMPORT = 1, - IMAGE_DIRECTORY_ENTRY_RESOURCE = 2, - IMAGE_DIRECTORY_ENTRY_EXCEPTION = 3, - IMAGE_DIRECTORY_ENTRY_SECURITY = 4, - IMAGE_DIRECTORY_ENTRY_BASERELOC = 5, - IMAGE_DIRECTORY_ENTRY_DEBUG = 6, - IMAGE_DIRECTORY_ENTRY_COPYRIGHT = 7, - IMAGE_DIRECTORY_ENTRY_ARCHITECTURE = 7, - IMAGE_DIRECTORY_ENTRY_GLOBALPTR = 8, - IMAGE_DIRECTORY_ENTRY_TLS = 9, - IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG = 10, - IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT = 11, - IMAGE_DIRECTORY_ENTRY_IAT = 12, - IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT = 13, - IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR = 14, - - IMAGE_SUBSYSTEM_WINDOWS_GUI = 2, - IMAGE_SUBSYSTEM_WINDOWS_CUI = 3, -}; - -void peinit(void); -void asmbpe(void); -void dope(void); - -IMAGE_SECTION_HEADER* newPEDWARFSection(char *name, vlong size); - -// X64 -typedef struct { - uint16 Magic; - uint8 MajorLinkerVersion; - uint8 MinorLinkerVersion; - uint32 SizeOfCode; - uint32 SizeOfInitializedData; - uint32 SizeOfUninitializedData; - uint32 AddressOfEntryPoint; - uint32 BaseOfCode; - uint64 ImageBase; - uint32 SectionAlignment; - uint32 FileAlignment; - uint16 MajorOperatingSystemVersion; - uint16 MinorOperatingSystemVersion; - uint16 MajorImageVersion; - uint16 MinorImageVersion; - uint16 MajorSubsystemVersion; - uint16 MinorSubsystemVersion; - uint32 Win32VersionValue; - uint32 SizeOfImage; - uint32 SizeOfHeaders; - uint32 CheckSum; - uint16 Subsystem; - uint16 DllCharacteristics; - uint64 SizeOfStackReserve; - uint64 SizeOfStackCommit; - uint64 SizeOfHeapReserve; - uint64 SizeOfHeapCommit; - uint32 LoaderFlags; - uint32 NumberOfRvaAndSizes; - IMAGE_DATA_DIRECTORY DataDirectory[16]; -} PE64_IMAGE_OPTIONAL_HEADER; - -void setpersrc(Sym *sym); diff --git a/src/cmd/ld/symtab.c b/src/cmd/ld/symtab.c deleted file mode 100644 index 60e146b35..000000000 --- a/src/cmd/ld/symtab.c +++ /dev/null @@ -1,378 +0,0 @@ -// Inferno utils/6l/span.c -// http://code.google.com/p/inferno-os/source/browse/utils/6l/span.c -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -// Symbol table. - -#include "l.h" -#include "../ld/lib.h" -#include "../ld/elf.h" - -char *elfstrdat; -int elfstrsize; -int maxelfstr; -int elftextsh; - -int -putelfstr(char *s) -{ - int off, n; - - if(elfstrsize == 0 && s[0] != 0) { - // first entry must be empty string - putelfstr(""); - } - - n = strlen(s)+1; - if(elfstrsize+n > maxelfstr) { - maxelfstr = 2*(elfstrsize+n+(1<<20)); - elfstrdat = realloc(elfstrdat, maxelfstr); - } - off = elfstrsize; - elfstrsize += n; - memmove(elfstrdat+off, s, n); - return off; -} - -void -putelfsyment(int off, vlong addr, vlong size, int info, int shndx) -{ - switch(thechar) { - case '6': - LPUT(off); - cput(info); - cput(0); - WPUT(shndx); - VPUT(addr); - VPUT(size); - symsize += ELF64SYMSIZE; - break; - default: - LPUT(off); - LPUT(addr); - LPUT(size); - cput(info); - cput(0); - WPUT(shndx); - symsize += ELF32SYMSIZE; - break; - } -} - -void -putelfsym(Sym *x, char *s, int t, vlong addr, vlong size, int ver, Sym *go) -{ - int bind, type, shndx, off; - - USED(go); - switch(t) { - default: - return; - case 'T': - type = STT_FUNC; - shndx = elftextsh + 0; - break; - case 'D': - type = STT_OBJECT; - if((x->type&~SSUB) == SRODATA) - shndx = elftextsh + 1; - else - shndx = elftextsh + 2; - break; - case 'B': - type = STT_OBJECT; - shndx = elftextsh + 3; - break; - } - bind = ver ? STB_LOCAL : STB_GLOBAL; - off = putelfstr(s); - putelfsyment(off, addr, size, (bind<<4)|(type&0xf), shndx); -} - -void -asmelfsym(void) -{ - // the first symbol entry is reserved - putelfsyment(0, 0, 0, (STB_LOCAL<<4)|STT_NOTYPE, 0); - genasmsym(putelfsym); -} - -void -putplan9sym(Sym *x, char *s, int t, vlong addr, vlong size, int ver, Sym *go) -{ - int i; - - USED(go); - USED(ver); - USED(size); - USED(x); - switch(t) { - case 'T': - case 'L': - case 'D': - case 'B': - if(ver) - t += 'a' - 'A'; - case 'a': - case 'p': - case 'f': - case 'z': - case 'Z': - case 'm': - lputb(addr); - cput(t+0x80); /* 0x80 is variable length */ - - if(t == 'z' || t == 'Z') { - cput(s[0]); - for(i=1; s[i] != 0 || s[i+1] != 0; i += 2) { - cput(s[i]); - cput(s[i+1]); - } - cput(0); - cput(0); - i++; - } else { - /* skip the '<' in filenames */ - if(t == 'f') - s++; - for(i=0; s[i]; i++) - cput(s[i]); - cput(0); - } - symsize += 4 + 1 + i + 1; - break; - default: - return; - }; -} - -void -asmplan9sym(void) -{ - genasmsym(putplan9sym); -} - -static Sym *symt; - -static void -scput(int b) -{ - uchar *p; - - symgrow(symt, symt->size+1); - p = symt->p + symt->size; - *p = b; - symt->size++; -} - -static void -slputb(int32 v) -{ - uchar *p; - - symgrow(symt, symt->size+4); - p = symt->p + symt->size; - *p++ = v>>24; - *p++ = v>>16; - *p++ = v>>8; - *p = v; - symt->size += 4; -} - -void -wputl(ushort w) -{ - cput(w); - cput(w>>8); -} - -void -wputb(ushort w) -{ - cput(w>>8); - cput(w); -} - -void -lputb(int32 l) -{ - cput(l>>24); - cput(l>>16); - cput(l>>8); - cput(l); -} - -void -lputl(int32 l) -{ - cput(l); - cput(l>>8); - cput(l>>16); - cput(l>>24); -} - -void -vputb(uint64 v) -{ - lputb(v>>32); - lputb(v); -} - -void -vputl(uint64 v) -{ - lputl(v); - lputl(v >> 32); -} - -void -putsymb(Sym *s, char *name, int t, vlong v, vlong size, int ver, Sym *typ) -{ - int i, f, l; - Reloc *rel; - - USED(size); - if(t == 'f') - name++; - l = 4; -// if(!debug['8']) -// l = 8; - if(s != nil) { - rel = addrel(symt); - rel->siz = l + Rbig; - rel->sym = s; - rel->type = D_ADDR; - rel->off = symt->size; - v = 0; - } - if(l == 8) - slputb(v>>32); - slputb(v); - if(ver) - t += 'a' - 'A'; - scput(t+0x80); /* 0x80 is variable length */ - - if(t == 'Z' || t == 'z') { - scput(name[0]); - for(i=1; name[i] != 0 || name[i+1] != 0; i += 2) { - scput(name[i]); - scput(name[i+1]); - } - scput(0); - scput(0); - } - else { - for(i=0; name[i]; i++) - scput(name[i]); - scput(0); - } - if(typ) { - if(!typ->reachable) - diag("unreachable type %s", typ->name); - rel = addrel(symt); - rel->siz = l; - rel->sym = typ; - rel->type = D_ADDR; - rel->off = symt->size; - } - if(l == 8) - slputb(0); - slputb(0); - - if(debug['n']) { - if(t == 'z' || t == 'Z') { - Bprint(&bso, "%c %.8llux ", t, v); - for(i=1; name[i] != 0 || name[i+1] != 0; i+=2) { - f = ((name[i]&0xff) << 8) | (name[i+1]&0xff); - Bprint(&bso, "/%x", f); - } - Bprint(&bso, "\n"); - return; - } - if(ver) - Bprint(&bso, "%c %.8llux %s<%d> %s\n", t, v, s->name, ver, typ ? typ->name : ""); - else - Bprint(&bso, "%c %.8llux %s %s\n", t, v, s->name, typ ? typ->name : ""); - } -} - -void -symtab(void) -{ - Sym *s; - - // Define these so that they'll get put into the symbol table. - // data.c:/^address will provide the actual values. - xdefine("text", STEXT, 0); - xdefine("etext", STEXT, 0); - xdefine("rodata", SRODATA, 0); - xdefine("erodata", SRODATA, 0); - xdefine("data", SBSS, 0); - xdefine("edata", SBSS, 0); - xdefine("end", SBSS, 0); - xdefine("epclntab", SRODATA, 0); - xdefine("esymtab", SRODATA, 0); - - // pseudo-symbols to mark locations of type, string, and go string data. - s = lookup("type.*", 0); - s->type = STYPE; - s->size = 0; - s->reachable = 1; - - s = lookup("go.string.*", 0); - s->type = SGOSTRING; - s->size = 0; - s->reachable = 1; - - symt = lookup("symtab", 0); - symt->type = SSYMTAB; - symt->size = 0; - symt->reachable = 1; - - // assign specific types so that they sort together. - // within a type they sort by size, so the .* symbols - // just defined above will be first. - // hide the specific symbols. - for(s = allsym; s != S; s = s->allsym) { - if(!s->reachable || s->special || s->type != SRODATA) - continue; - if(strncmp(s->name, "type.", 5) == 0) { - s->type = STYPE; - s->hide = 1; - } - if(strncmp(s->name, "go.string.", 10) == 0) { - s->type = SGOSTRING; - s->hide = 1; - } - } - - if(debug['s']) - return; - genasmsym(putsymb); -} |