D_FILE,
D_FILE1,
- D_SBIG, /* internal use by 6l only */
-
D_INDIR, /* additive */
+ D_SBIG = D_INDIR + D_INDIR,
+
T_TYPE = 1<<0,
T_INDEX = 1<<1,
T_OFFSET = 1<<2,
install: $(TARG)
cp $(TARG) $(BIN)/$(TARG)
+
+go.o: ../ld/go.c
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// go-specific
-
-// accumulate all type information from .6 files.
-// check for inconsistencies.
-// define gotypestrings variable if needed.
-// define gotypesigs variable if needed.
-
-// TODO:
-// include type info for non-exported types.
-// generate debugging section in binary.
-// once the dust settles, try to move some code to
-// libmach, so that other linkers and ar can share.
-// try to make this completely portable and shared
-// across linkers
-
#include "l.h"
-
-/*
- * package import data
- */
-typedef struct Import Import;
-struct Import
-{
- Import *hash; // next in hash table
- int export; // marked as export?
- 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;
- if(h < 0)
- h = ~h;
- 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 = name;
- x->hash = ihash[h];
- ihash[h] = x;
- nimport++;
- return x;
-}
-
-char*
-gotypefor(char *name)
-{
- Import *x;
- char *s, *p;
-
- s = strdup(name);
- p = utfrune(s, 0xB7); // center dot
- if(p == nil)
- return nil;
- *p++ = '.';
- memmove(p, p+1, strlen(p));
- x = ilookup(s);
- free(s);
- if(x == nil || x->prefix == nil)
- return nil;
- if(strcmp(x->prefix, "var") != 0 && strcmp(x->prefix, "func") != 0)
- return nil;
- return x->def;
-}
-
-static void loadpkgdata(char*, char*, int);
-static int parsemethod(char**, char*, char**);
-static int parsepkgdata(char*, char**, char*, int*, char**, char**, char**);
-
-void
-ldpkg(Biobuf *f, int64 len, char *filename)
-{
- char *data, *p0, *p1;
-
- if(debug['g'])
- return;
-
- if((int)len != len) {
- fprint(2, "6l: too much pkg data in %s\n", filename);
- return;
- }
- data = mal(len);
- if(Bread(f, data, len) != len) {
- fprint(2, "6l: short pkg read %s\n", filename);
- return;
- }
-
- // first \n$$ marks beginning of exports - skip rest of line
- p0 = strstr(data, "\n$$");
- if(p0 == nil)
- 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, "6l: cannot find end of exports in %s\n", filename);
- return;
- }
- while(*p0 == ' ' || *p0 == '\t' || *p0 == '\n')
- p0++;
- if(strncmp(p0, "package ", 8) != 0) {
- fprint(2, "6l: bad package section in %s\n", filename);
- return;
- }
- p0 += 8;
- while(*p0 == ' ' || *p0 == '\t' || *p0 == '\n')
- p0++;
- while(*p0 != ' ' && *p0 != '\t' && *p0 != '\n')
- p0++;
-
- loadpkgdata(filename, p0, p1 - p0);
-
- // 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, "6l: cannot find end of local types in %s\n", filename);
- return;
- }
-
- loadpkgdata(filename, p0, p1 - p0);
-}
-
-static void
-loadpkgdata(char *file, char *data, int len)
-{
- int export;
- char *p, *ep, *prefix, *name, *def;
- Import *x;
-
- file = strdup(file);
- p = data;
- ep = data + len;
- while(parsepkgdata(file, &p, ep, &export, &prefix, &name, &def) > 0) {
- x = ilookup(name);
- if(x->prefix == nil) {
- x->prefix = prefix;
- x->def = def;
- x->file = file;
- x->export = export;
- } else {
- if(strcmp(x->prefix, prefix) != 0) {
- fprint(2, "6l: conflicting definitions for %s\n", 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, "6l: conflicting definitions for %s\n", 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++;
- }
-
- // okay if some .6 say export and others don't.
- // all it takes is one.
- if(export)
- x->export = 1;
- }
- }
-}
-
-static int
-parsepkgdata(char *file, char **pp, char *ep, int *exportp, char **prefixp, char **namep, char **defp)
-{
- char *p, *prefix, *name, *def, *edef, *meth;
- int n;
-
- // skip white space
- p = *pp;
- while(p < ep && (*p == ' ' || *p == '\t' || *p == '\n'))
- p++;
- if(p == ep || strncmp(p, "$$\n", 3) == 0)
- return 0;
-
- // [export|package ]
- *exportp = 0;
- if(p + 7 <= ep && strncmp(p, "export ", 7) == 0) {
- *exportp = 1;
- p += 7;
- }
- else if(p + 8 <= ep && strncmp(p, "package ", 8) == 0) {
- *exportp = 2;
- p += 8;
- }
-
- // prefix: (var|type|func|const)
- prefix = p;
-
- prefix = p;
- if(p + 6 > 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{
- fprint(2, "6l: confused in pkg data near <<%.20s>>\n", p);
- nerrors++;
- return -1;
- }
- p[-1] = '\0';
-
- // name: a.b followed by space
- name = p;
- while(p < ep && *p != ' ')
- 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, "6l: %s: expected methods to be indented %p %p %.10s\n",
- file, edef, meth, meth);
- nerrors++;
- return -1;
- }
- *edef++ = '\t';
- n = strlen(meth);
- memmove(edef, meth, n);
- edef += n;
- }
-
- // 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, "6l: lost end of line in method definition\n");
- *pp = ep;
- return -1;
- }
- *p++ = '\0';
- *pp = p;
- return 1;
-}
-
-static int
-importcmp(const void *va, const void *vb)
-{
- Import *a, *b;
-
- a = *(Import**)va;
- b = *(Import**)vb;
- return strcmp(a->name, b->name);
-}
-
-static int
-symcmp(const void *va, const void *vb)
-{
- Sym *a, *b;
-
- a = *(Sym**)va;
- b = *(Sym**)vb;
- return strcmp(a->name, b->name);
-}
-
-// if there is an undefined reference to gotypestrings,
-// create it. c declaration is
-// extern char gotypestrings[];
-// ironically, gotypestrings is a c variable, because there
-// is no way to forward declare a string in go.
-void
-definetypestrings(void)
-{
- int i, j, len, n, w;
- char *p;
- Import **all, *x;
- Fmt f;
- Prog *prog;
- Sym *s;
-
- if(debug['g'])
- return;
-
- if(debug['v'])
- Bprint(&bso, "%5.2f definetypestrings\n", cputime());
-
- s = lookup("gotypestrings", 0);
- if(s->type == 0)
- return;
- if(s->type != SXREF) {
- diag("gotypestrings already defined");
- return;
- }
- s->type = SDATA;
-
- // make a list of all the type exports
- n = 0;
- for(i=0; i<NIHASH; i++)
- for(x=ihash[i]; x; x=x->hash)
- if(strcmp(x->prefix, "type") == 0)
- n++;
- all = mal(n*sizeof all[0]);
- j = 0;
- for(i=0; i<NIHASH; i++)
- for(x=ihash[i]; x; x=x->hash)
- if(strcmp(x->prefix, "type") == 0)
- all[j++] = x;
-
- // sort them by name
- qsort(all, n, sizeof all[0], importcmp);
-
- // make a big go string containing all the types
- fmtstrinit(&f);
- fmtprint(&f, "xxxx"); // 4-byte length
- for(i=0; i<n; i++) {
- p = strchr(all[i]->def, '\n');
- if(p)
- len = p - all[i]->def;
- else
- len = strlen(all[i]->def);
- fmtprint(&f, "%s %.*s\n", all[i]->name, utfnlen(all[i]->def, len), all[i]->def);
- }
- p = fmtstrflush(&f);
- n = strlen(p);
- s->value = n;
-
- // go strings begin with 4-byte length.
- // amd64 is little-endian.
- len = n - 4;
- p[0] = len;
- p[1] = len >> 8;
- p[2] = len >> 16;
- p[3] = len >> 24;
-
- // have data, need to create linker representation.
- // linker stores big data as sequence of pieces
- // with int8 length, so break p into 100-byte chunks.
- // (had to add D_SBIG even to do that; the compiler
- // would have generated 8-byte chunks.)
- for(i=0; i<n; i+=100) {
- w = 100;
- if(w > n - i)
- w = n - i;
- prog = newdata(s, i, w, D_EXTERN);
- prog->to.type = D_SBIG;
- prog->to.sbig = p + i;
- }
-
- if(debug['v'])
- Bprint(&bso, "%5.2f typestrings %d\n", cputime(), n);
-}
-
-// if there is an undefined reference to gotypesigs, create it.
-// c declaration is
-// extern Sigt *gotypesigs[];
-// extern int ngotypesigs;
-// used by sys.unreflect runtime.
-void
-definetypesigs(void)
-{
- int i, j, n;
- Sym **all, *s, *x;
- Prog *prog;
-
- if(debug['g'])
- return;
-
- if(debug['v'])
- Bprint(&bso, "%5.2f definetypesigs\n", cputime());
-
- s = lookup("gotypesigs", 0);
- if(s->type == 0)
- return;
- if(s->type != SXREF) {
- diag("gotypesigs already defined");
- return;
- }
- s->type = SDATA;
-
- // make a list of all the sigt symbols.
- n = 0;
- for(i=0; i<NHASH; i++)
- for(x = hash[i]; x; x=x->link)
- if(memcmp(x->name, "sigt·", 6) == 0 && x->type != Sxxx)
- n++;
- all = mal(n*sizeof all[0]);
- j = 0;
- for(i=0; i<NHASH; i++)
- for(x = hash[i]; x; x=x->link)
- if(memcmp(x->name, "sigt·", 6) == 0 && x->type != Sxxx)
- all[j++] = x;
-
- // sort them by name
- qsort(all, n, sizeof all[0], symcmp);
-
- // emit array as sequence of references.
- enum { PtrSize = 8 };
- for(i=0; i<n; i++) {
- prog = newdata(s, PtrSize*i, PtrSize, D_EXTERN);
- prog->to.type = D_ADDR;
- prog->to.index = D_EXTERN;
- prog->to.sym = all[i];
- }
- s->value = PtrSize*n;
- if(n == 0)
- s->value = 1; // must have non-zero size or 6l complains
-
- // emit count
- s = lookup("ngotypesigs", 0);
- s->type = SDATA;
- s->value = sizeof(int32);
- prog = newdata(s, 0, sizeof(int32), D_EXTERN);
- prog->to.offset = n;
-
- if(debug['v'])
- Bprint(&bso, "%5.2f typesigs %d\n", cputime(), n);
-}
-
-int
-isinitfunc(Sym *s)
-{
- char *p;
-
- p = utfrune(s->name, 0xb7); // 0xb7 = '·'
- if(p == nil)
- return 0;
- if(memcmp(p, "·Init·", 8) == 0 || memcmp(p, "·init·", 8) == 0)
- return 1;
- return 0;
-}
-
-static void mark(Sym*);
-static int markdepth;
-
-static void
-markdata(Prog *p, Sym *s)
-{
- markdepth++;
- if(p != P && debug['v'] > 1)
- Bprint(&bso, "%d markdata %s\n", markdepth, s->name);
- for(; p != P; p=p->dlink)
- if(p->to.sym)
- mark(p->to.sym);
- markdepth--;
-}
-
-static void
-marktext(Prog *p)
-{
- if(p == P)
- return;
- if(p->as != ATEXT) {
- diag("marktext: %P", p);
- return;
- }
- markdepth++;
- if(debug['v'] > 1)
- Bprint(&bso, "%d marktext %s\n", markdepth, p->from.sym->name);
- for(p=p->link; p != P; p=p->link) {
- if(p->as == ATEXT || p->as == ADATA || p->as == AGLOBL)
- break;
- if(p->from.sym)
- mark(p->from.sym);
- if(p->to.sym)
- mark(p->to.sym);
- }
- markdepth--;
-}
-
-static void
-mark(Sym *s)
-{
- if(s == S || s->reachable)
- return;
- s->reachable = 1;
- if(s->text)
- marktext(s->text);
- if(s->data)
- markdata(s->data, s);
-}
-
-static void
-sweeplist(Prog **first, Prog **last)
-{
- int reachable;
- Prog *p, *q;
-
- reachable = 1;
- q = P;
- for(p=*first; p != P; p=p->link) {
- switch(p->as) {
- case ATEXT:
- case ADATA:
- case AGLOBL:
- reachable = p->from.sym->reachable;
- if(!reachable) {
- if(debug['v'] > 1)
- Bprint(&bso, "discard %s\n", p->from.sym->name);
- p->from.sym->type = Sxxx;
- }
- break;
- }
- if(reachable) {
- if(q == P)
- *first = p;
- else
- q->link = p;
- q = p;
- }
- }
- if(q == P)
- *first = P;
- else
- q->link = P;
- *last = q;
-}
-
-void
-deadcode(void)
-{
- if(debug['v'])
- Bprint(&bso, "%5.2f deadcode\n", cputime());
-
- mark(lookup(INITENTRY, 0));
- mark(lookup("sys·morestack", 0));
-
- sweeplist(&firstp, &lastp);
- sweeplist(&datap, &edatap);
-}
-
+#include "../ld/go.c"
void xfol(Prog*);
void zaddr(Biobuf*, Adr*, Sym*[]);
void zerosig(char*);
-int isinitfunc(Sym*);
void machseg(char*, vlong, vlong, vlong, vlong, uint32, uint32, uint32, uint32);
void machsymseg(uint32, uint32);
ACMPSB,
ACMPSL,
ACMPSW,
- ACMPXCHGB,
- ACMPXCHGL,
- ACMPXCHGW,
ADAA,
ADAS,
ADATA,
ASIGNAME,
+ ACMPXCHGB,
+ ACMPXCHGL,
+ ACMPXCHGW,
+
ALAST
};
D_FCONST = 66,
D_SCONST = 67,
D_ADDR = 68,
- D_CONST2 = 69,
D_FILE,
D_FILE1,
D_INDIR, /* additive */
+ D_SBIG = D_INDIR + D_INDIR,
+ D_CONST2,
+
T_TYPE = 1<<0,
T_INDEX = 1<<1,
T_OFFSET = 1<<2,
optab.$O\
pass.$O\
span.$O\
+ go.$O\
HFILES=\
l.h\
install: $(TARG)
cp $(TARG) $(BIN)/$(TARG)
+
+go.o: ../ld/go.c
+
char u0scon[8];
Prog *u0cond; /* not used, but should be D_BRANCH */
Ieee u0ieee;
+ char *u0sbig;
} u0;
union
{
#define scon u0.u0scon
#define cond u0.u0cond
#define ieee u0.u0ieee
+#define sbig u0.u0sbig
#define autom u1.u1autom
#define sym u1.u1sym
Adr to;
Prog *forwd;
Prog* link;
+ Prog* dlink;
Prog* pcond; /* work on this */
int32 pc;
int32 line;
short become;
short frame;
uchar subtype;
+ uchar dupok;
+ uchar reachable;
ushort file;
int32 value;
int32 sig;
Sym* link;
+ Prog* text;
+ Prog* data;
};
struct Optab
{
enum
{
- STEXT = 1,
+ Sxxx,
+
+ STEXT,
SDATA,
SBSS,
SDATA1,
void main(int, char*[]);
void mkfwd(void);
void* mal(uint32);
+Prog* newdata(Sym*, int, int, int);
+Prog* newtext(Prog*, Sym*);
void nuxiinit(void);
void objfile(char*);
int opsize(Prog*);
uint32 elfheadr(void);
void whatsys(void);
+/*
+ * go.c
+ */
+void deadcode(void);
+void definetypestrings(void);
+void definetypesigs(void);
+char* gotypefor(char *name);
+void ldpkg(Biobuf *f, int64 len, char *filename);
+
+
/* set by call to whatsys() */
extern char* goroot;
extern char* goarch;
a = va_arg(fp->args, Adr*);
i = a->type;
- if(i >= D_INDIR) {
+ if(i >= D_INDIR && i < 2*D_INDIR) {
if(a->offset)
sprint(str, "%ld(%R)", a->offset, i-D_INDIR);
else
sprint(a, "%s/lib/lib_%s_%s.a", goroot, goarch, goos);
objfile(a);
}
+ definetypestrings();
+ definetypesigs();
+ deadcode();
+
firstp = firstp->link;
if(firstp == P)
errorexit();
import1 = Boffset(f);
Bseek(f, import0, 0);
-// ldpkg(f, import1 - import0 - 2, pn); // -2 for !\n
+ ldpkg(f, import1 - import0 - 2, pn); // -2 for !\n
Bseek(f, import1, 0);
newloop:
case ADATA:
data:
+ // Assume that AGLOBL comes after ADATA.
+ // If we've seen an AGLOBL that said this sym was DUPOK,
+ // ignore any more ADATA we see, which must be
+ // redefinitions.
+ s = p->from.sym;
+ if(s != S && s->dupok) {
+ if(debug['v'])
+ Bprint(&bso, "skipping %s in %s: dupok", s->name, pn);
+ goto loop;
+ }
+ if(s != S) {
+ p->dlink = s->data;
+ s->data = p;
+ }
if(edatap == P)
datap = p;
else
}
diag("%s: redefinition: %s\n%P", pn, s->name, p);
}
- s->type = STEXT;
- s->value = pc;
- lastp->link = p;
- lastp = p;
- p->pc = pc;
- pc++;
- if(textp == P) {
- textp = p;
- etextp = p;
- goto loop;
- }
- etextp->pcond = p;
- etextp = p;
+ newtext(p, s);
goto loop;
case AFMOVF:
{ ACMPSB, ynone, Pb, 0xa6 },
{ ACMPSL, ynone, Px, 0xa7 },
{ ACMPSW, ynone, Pe, 0xa7 },
- { ACMPXCHGB, yrb_mb, Pm, 0xb0 },
- { ACMPXCHGL, yrl_ml, Pm, 0xb1 },
- { ACMPXCHGW, yrl_ml, Pm, 0xb1 },
{ ADAA, ynone, Px, 0x27 },
{ ADAS, ynone, Px, 0x2f },
{ ADATA },
{ AFYL2X, ynone, Px, 0xd9, 0xf1 },
{ AFYL2XP1, ynone, Px, 0xd9, 0xf9 },
{ AEND },
+ { ADYNT },
+ { AINIT },
+ { ASIGNAME },
+ { ACMPXCHGB, yrb_mb, Pm, 0xb0 },
+ { ACMPXCHGL, yrl_ml, Pm, 0xb1 },
+ { ACMPXCHGW, yrl_ml, Pm, 0xb1 },
0
};
diag("relocation offset %ld for %s out of range", v, s->name);
}
-static Prog*
+Prog*
newdata(Sym *s, int o, int w, int t)
{
Prog *p;
p->from.sym = s;
p->from.offset = o;
p->to.type = D_CONST;
+ p->dlink = s->data;
+ s->data = p;
+ return p;
+}
+
+Prog*
+newtext(Prog *p, Sym *s)
+{
+ if(p == P) {
+ p = prg();
+ p->as = ATEXT;
+ p->from.sym = s;
+ }
+ s->type = STEXT;
+ s->text = p;
+ s->value = pc;
+ lastp->link = p;
+ lastp = p;
+ p->pc = pc++;
+ if(textp == P)
+ textp = p;
+ else
+ etextp->pcond = p;
+ etextp = p;
return p;
}
}
void
-putsymb(char *s, int t, int32 v, int ver)
+putsymb(char *s, int t, int32 v, int ver, char *go)
{
int i, j, f;
- char *go;
-
- go = nil; // TODO
if(t == 'f')
s++;
s = lookup("etext", 0);
if(s->type == STEXT)
- putsymb(s->name, 'T', s->value, s->version);
+ putsymb(s->name, 'T', s->value, s->version, nil);
for(h=0; h<NHASH; h++)
for(s=hash[h]; s!=S; s=s->link)
switch(s->type) {
case SCONST:
- putsymb(s->name, 'D', s->value, s->version);
+ putsymb(s->name, 'D', s->value, s->version, gotypefor(s->name));
continue;
case SDATA:
- putsymb(s->name, 'D', s->value+INITDAT, s->version);
+ putsymb(s->name, 'D', s->value+INITDAT, s->version, gotypefor(s->name));
continue;
case SBSS:
- putsymb(s->name, 'B', s->value+INITDAT, s->version);
+ putsymb(s->name, 'B', s->value+INITDAT, s->version, gotypefor(s->name));
continue;
case SFILE:
- putsymb(s->name, 'f', s->value, s->version);
+ putsymb(s->name, 'f', s->value, s->version, nil);
continue;
}
/* filenames first */
for(a=p->to.autom; a; a=a->link)
if(a->type == D_FILE)
- putsymb(a->asym->name, 'z', a->aoffset, 0);
+ putsymb(a->asym->name, 'z', a->aoffset, 0, nil);
else
if(a->type == D_FILE1)
- putsymb(a->asym->name, 'Z', a->aoffset, 0);
+ putsymb(a->asym->name, 'Z', a->aoffset, 0, nil);
- putsymb(s->name, 'T', s->value, s->version);
+ putsymb(s->name, 'T', s->value, s->version, gotypefor(s->name));
/* frame, auto and param after */
- putsymb(".frame", 'm', p->to.offset+4, 0);
+ putsymb(".frame", 'm', p->to.offset+4, 0, nil);
for(a=p->to.autom; a; a=a->link)
if(a->type == D_AUTO)
- putsymb(a->asym->name, 'a', -a->aoffset, 0);
+ putsymb(a->asym->name, 'a', -a->aoffset, 0, nil);
else
if(a->type == D_PARAM)
- putsymb(a->asym->name, 'p', a->aoffset, 0);
+ putsymb(a->asym->name, 'p', a->aoffset, 0, nil);
}
if(debug['v'] || debug['n'])
Bprint(&bso, "symsize = %lud\n", symsize);
{
int32 v;
- if(a->type >= D_INDIR || a->index != D_NONE) {
+ if((a->type >= D_INDIR && a->type < 2*D_INDIR) || a->index != D_NONE) {
if(a->index != D_NONE && a->scale == 0) {
if(a->type == D_ADDR) {
switch(a->index) {
v = a->offset;
t = a->type;
if(a->index != D_NONE) {
- if(t >= D_INDIR) {
+ if(t >= D_INDIR && t < 2*D_INDIR) {
t -= D_INDIR;
if(t == D_NONE) {
*andptr++ = (0 << 6) | (4 << 0) | (r << 3);
*andptr++ = (3 << 6) | (reg[t] << 0) | (r << 3);
return;
}
- if(t >= D_INDIR) {
+ if(t >= D_INDIR && t < 2*D_INDIR) {
t -= D_INDIR;
if(t == D_NONE || (D_CS <= t && t <= D_GS)) {
*andptr++ = (0 << 6) | (5 << 0) | (r << 3);
--- /dev/null
+// 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).
+
+// accumulate all type information from .6 files.
+// check for inconsistencies.
+// define gotypestrings variable if needed.
+// define gotypesigs variable if needed.
+
+// TODO:
+// include type info for non-exported types.
+// 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
+ int export; // marked as export?
+ 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;
+ if(h < 0)
+ h = ~h;
+ 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 = name;
+ x->hash = ihash[h];
+ ihash[h] = x;
+ nimport++;
+ return x;
+}
+
+char*
+gotypefor(char *name)
+{
+ Import *x;
+ char *s, *p;
+
+ s = strdup(name);
+ p = utfrune(s, 0xB7); // center dot
+ if(p == nil)
+ return nil;
+ *p++ = '.';
+ memmove(p, p+1, strlen(p));
+ x = ilookup(s);
+ free(s);
+ if(x == nil || x->prefix == nil)
+ return nil;
+ if(strcmp(x->prefix, "var") != 0 && strcmp(x->prefix, "func") != 0)
+ return nil;
+ return x->def;
+}
+
+static void loadpkgdata(char*, char*, int);
+static int parsemethod(char**, char*, char**);
+static int parsepkgdata(char*, char**, char*, int*, char**, char**, char**);
+
+void
+ldpkg(Biobuf *f, int64 len, char *filename)
+{
+ char *data, *p0, *p1;
+
+ if(debug['g'])
+ return;
+
+ if((int)len != len) {
+ fprint(2, "6l: too much pkg data in %s\n", filename);
+ return;
+ }
+ data = mal(len);
+ if(Bread(f, data, len) != len) {
+ fprint(2, "6l: short pkg read %s\n", filename);
+ return;
+ }
+
+ // first \n$$ marks beginning of exports - skip rest of line
+ p0 = strstr(data, "\n$$");
+ if(p0 == nil)
+ 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, "6l: cannot find end of exports in %s\n", filename);
+ return;
+ }
+ while(*p0 == ' ' || *p0 == '\t' || *p0 == '\n')
+ p0++;
+ if(strncmp(p0, "package ", 8) != 0) {
+ fprint(2, "6l: bad package section in %s\n", filename);
+ return;
+ }
+ p0 += 8;
+ while(*p0 == ' ' || *p0 == '\t' || *p0 == '\n')
+ p0++;
+ while(*p0 != ' ' && *p0 != '\t' && *p0 != '\n')
+ p0++;
+
+ loadpkgdata(filename, p0, p1 - p0);
+
+ // 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, "6l: cannot find end of local types in %s\n", filename);
+ return;
+ }
+
+ loadpkgdata(filename, p0, p1 - p0);
+}
+
+static void
+loadpkgdata(char *file, char *data, int len)
+{
+ int export;
+ char *p, *ep, *prefix, *name, *def;
+ Import *x;
+
+ file = strdup(file);
+ p = data;
+ ep = data + len;
+ while(parsepkgdata(file, &p, ep, &export, &prefix, &name, &def) > 0) {
+ x = ilookup(name);
+ if(x->prefix == nil) {
+ x->prefix = prefix;
+ x->def = def;
+ x->file = file;
+ x->export = export;
+ } else {
+ if(strcmp(x->prefix, prefix) != 0) {
+ fprint(2, "6l: conflicting definitions for %s\n", 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, "6l: conflicting definitions for %s\n", 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++;
+ }
+
+ // okay if some .6 say export and others don't.
+ // all it takes is one.
+ if(export)
+ x->export = 1;
+ }
+ }
+}
+
+static int
+parsepkgdata(char *file, char **pp, char *ep, int *exportp, char **prefixp, char **namep, char **defp)
+{
+ char *p, *prefix, *name, *def, *edef, *meth;
+ int n;
+
+ // skip white space
+ p = *pp;
+ while(p < ep && (*p == ' ' || *p == '\t' || *p == '\n'))
+ p++;
+ if(p == ep || strncmp(p, "$$\n", 3) == 0)
+ return 0;
+
+ // [export|package ]
+ *exportp = 0;
+ if(p + 7 <= ep && strncmp(p, "export ", 7) == 0) {
+ *exportp = 1;
+ p += 7;
+ }
+ else if(p + 8 <= ep && strncmp(p, "package ", 8) == 0) {
+ *exportp = 2;
+ p += 8;
+ }
+
+ // prefix: (var|type|func|const)
+ prefix = p;
+
+ prefix = p;
+ if(p + 6 > 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{
+ fprint(2, "6l: confused in pkg data near <<%.20s>>\n", p);
+ nerrors++;
+ return -1;
+ }
+ p[-1] = '\0';
+
+ // name: a.b followed by space
+ name = p;
+ while(p < ep && *p != ' ')
+ 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, "6l: %s: expected methods to be indented %p %p %.10s\n",
+ file, edef, meth, meth);
+ nerrors++;
+ return -1;
+ }
+ *edef++ = '\t';
+ n = strlen(meth);
+ memmove(edef, meth, n);
+ edef += n;
+ }
+
+ // 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, "6l: lost end of line in method definition\n");
+ *pp = ep;
+ return -1;
+ }
+ *p++ = '\0';
+ *pp = p;
+ return 1;
+}
+
+static int
+importcmp(const void *va, const void *vb)
+{
+ Import *a, *b;
+
+ a = *(Import**)va;
+ b = *(Import**)vb;
+ return strcmp(a->name, b->name);
+}
+
+static int
+symcmp(const void *va, const void *vb)
+{
+ Sym *a, *b;
+
+ a = *(Sym**)va;
+ b = *(Sym**)vb;
+ return strcmp(a->name, b->name);
+}
+
+// if there is an undefined reference to gotypestrings,
+// create it. c declaration is
+// extern char gotypestrings[];
+// ironically, gotypestrings is a c variable, because there
+// is no way to forward declare a string in go.
+void
+definetypestrings(void)
+{
+ int i, j, len, n, w;
+ char *p;
+ Import **all, *x;
+ Fmt f;
+ Prog *prog;
+ Sym *s;
+
+ if(debug['g'])
+ return;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f definetypestrings\n", cputime());
+
+ s = lookup("gotypestrings", 0);
+ if(s->type == 0)
+ return;
+ if(s->type != SXREF) {
+ diag("gotypestrings already defined");
+ return;
+ }
+ s->type = SDATA;
+
+ // make a list of all the type exports
+ n = 0;
+ for(i=0; i<NIHASH; i++)
+ for(x=ihash[i]; x; x=x->hash)
+ if(strcmp(x->prefix, "type") == 0)
+ n++;
+ all = mal(n*sizeof all[0]);
+ j = 0;
+ for(i=0; i<NIHASH; i++)
+ for(x=ihash[i]; x; x=x->hash)
+ if(strcmp(x->prefix, "type") == 0)
+ all[j++] = x;
+
+ // sort them by name
+ qsort(all, n, sizeof all[0], importcmp);
+
+ // make a big go string containing all the types
+ fmtstrinit(&f);
+ fmtprint(&f, "xxxx"); // 4-byte length
+ for(i=0; i<n; i++) {
+ p = strchr(all[i]->def, '\n');
+ if(p)
+ len = p - all[i]->def;
+ else
+ len = strlen(all[i]->def);
+ fmtprint(&f, "%s %.*s\n", all[i]->name, utfnlen(all[i]->def, len), all[i]->def);
+ }
+ p = fmtstrflush(&f);
+ n = strlen(p);
+ s->value = n;
+
+ // go strings begin with 4-byte length.
+ // amd64 is little-endian.
+ len = n - 4;
+ p[0] = len;
+ p[1] = len >> 8;
+ p[2] = len >> 16;
+ p[3] = len >> 24;
+
+ // have data, need to create linker representation.
+ // linker stores big data as sequence of pieces
+ // with int8 length, so break p into 100-byte chunks.
+ // (had to add D_SBIG even to do that; the compiler
+ // would have generated 8-byte chunks.)
+ for(i=0; i<n; i+=100) {
+ w = 100;
+ if(w > n - i)
+ w = n - i;
+ prog = newdata(s, i, w, D_EXTERN);
+ prog->to.type = D_SBIG;
+ prog->to.sbig = p + i;
+ }
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f typestrings %d\n", cputime(), n);
+}
+
+// if there is an undefined reference to gotypesigs, create it.
+// c declaration is
+// extern Sigt *gotypesigs[];
+// extern int ngotypesigs;
+// used by sys.unreflect runtime.
+void
+definetypesigs(void)
+{
+ int i, j, n;
+ Sym **all, *s, *x;
+ Prog *prog;
+
+ if(debug['g'])
+ return;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f definetypesigs\n", cputime());
+
+ s = lookup("gotypesigs", 0);
+ if(s->type == 0)
+ return;
+ if(s->type != SXREF) {
+ diag("gotypesigs already defined");
+ return;
+ }
+ s->type = SDATA;
+
+ // make a list of all the sigt symbols.
+ n = 0;
+ for(i=0; i<NHASH; i++)
+ for(x = hash[i]; x; x=x->link)
+ if(memcmp(x->name, "sigt·", 6) == 0 && x->type != Sxxx)
+ n++;
+ all = mal(n*sizeof all[0]);
+ j = 0;
+ for(i=0; i<NHASH; i++)
+ for(x = hash[i]; x; x=x->link)
+ if(memcmp(x->name, "sigt·", 6) == 0 && x->type != Sxxx)
+ all[j++] = x;
+
+ // sort them by name
+ qsort(all, n, sizeof all[0], symcmp);
+
+ // emit array as sequence of references.
+ enum { PtrSize = 8 };
+ for(i=0; i<n; i++) {
+ prog = newdata(s, PtrSize*i, PtrSize, D_EXTERN);
+ prog->to.type = D_ADDR;
+ prog->to.index = D_EXTERN;
+ prog->to.sym = all[i];
+ }
+ s->value = PtrSize*n;
+ if(n == 0)
+ s->value = 1; // must have non-zero size or 6l complains
+
+ // emit count
+ s = lookup("ngotypesigs", 0);
+ s->type = SDATA;
+ s->value = sizeof(int32);
+ prog = newdata(s, 0, sizeof(int32), D_EXTERN);
+ prog->to.offset = n;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f typesigs %d\n", cputime(), n);
+}
+
+static void mark(Sym*);
+static int markdepth;
+
+static void
+markdata(Prog *p, Sym *s)
+{
+ markdepth++;
+ if(p != P && debug['v'] > 1)
+ Bprint(&bso, "%d markdata %s\n", markdepth, s->name);
+ for(; p != P; p=p->dlink)
+ if(p->to.sym)
+ mark(p->to.sym);
+ markdepth--;
+}
+
+static void
+marktext(Prog *p)
+{
+ if(p == P)
+ return;
+ if(p->as != ATEXT) {
+ diag("marktext: %P", p);
+ return;
+ }
+ markdepth++;
+ if(debug['v'] > 1)
+ Bprint(&bso, "%d marktext %s\n", markdepth, p->from.sym->name);
+ for(p=p->link; p != P; p=p->link) {
+ if(p->as == ATEXT || p->as == ADATA || p->as == AGLOBL)
+ break;
+ if(p->from.sym)
+ mark(p->from.sym);
+ if(p->to.sym)
+ mark(p->to.sym);
+ }
+ markdepth--;
+}
+
+static void
+mark(Sym *s)
+{
+ if(s == S || s->reachable)
+ return;
+ s->reachable = 1;
+ if(s->text)
+ marktext(s->text);
+ if(s->data)
+ markdata(s->data, s);
+}
+
+static void
+sweeplist(Prog **first, Prog **last)
+{
+ int reachable;
+ Prog *p, *q;
+
+ reachable = 1;
+ q = P;
+ for(p=*first; p != P; p=p->link) {
+ switch(p->as) {
+ case ATEXT:
+ case ADATA:
+ case AGLOBL:
+ reachable = p->from.sym->reachable;
+ if(!reachable) {
+ if(debug['v'] > 1)
+ Bprint(&bso, "discard %s\n", p->from.sym->name);
+ p->from.sym->type = Sxxx;
+ }
+ break;
+ }
+ if(reachable) {
+ if(q == P)
+ *first = p;
+ else
+ q->link = p;
+ q = p;
+ }
+ }
+ if(q == P)
+ *first = P;
+ else
+ q->link = P;
+ *last = q;
+}
+
+void
+deadcode(void)
+{
+ if(debug['v'])
+ Bprint(&bso, "%5.2f deadcode\n", cputime());
+
+ mark(lookup(INITENTRY, 0));
+ mark(lookup("sys·morestack", 0));
+
+// sweeplist(&firstp, &lastp);
+// sweeplist(&datap, &edatap);
+}
+