mirror of
https://github.com/golang/go.git
synced 2025-05-15 12:24:37 +00:00
* move go-specific loader code
into gc directory, where it gets included as ../gc/ldbody this is similar to the assemblers including ../cc/lexbody and ../cc/macbody. * hook go-specific loader code into 8l. * make current 8.out.h and 6.out.h backward compatible with plan 9's versions. i had added some constants in the middle of enums and have now moved them to the end. this keeps us from invalidating old .8 and .6 files. not sure how much it really matters, but easy to do. R=r DELTA=1314 (667 added, 623 deleted, 24 changed) OCL=26938 CL=26941
This commit is contained in:
parent
b199035ba8
commit
b87e3e8b7f
@ -820,10 +820,10 @@ enum
|
||||
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,
|
||||
|
@ -36,3 +36,5 @@ clean:
|
||||
|
||||
install: $(TARG)
|
||||
cp $(TARG) $(BIN)/$(TARG)
|
||||
|
||||
go.o: ../ld/go.c
|
||||
|
600
src/cmd/6l/go.c
600
src/cmd/6l/go.c
@ -2,603 +2,5 @@
|
||||
// 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"
|
||||
|
@ -441,7 +441,6 @@ void xdefine(char*, int, vlong);
|
||||
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);
|
||||
|
@ -79,9 +79,6 @@ enum as
|
||||
ACMPSB,
|
||||
ACMPSL,
|
||||
ACMPSW,
|
||||
ACMPXCHGB,
|
||||
ACMPXCHGL,
|
||||
ACMPXCHGW,
|
||||
ADAA,
|
||||
ADAS,
|
||||
ADATA,
|
||||
@ -387,6 +384,10 @@ enum as
|
||||
|
||||
ASIGNAME,
|
||||
|
||||
ACMPXCHGB,
|
||||
ACMPXCHGL,
|
||||
ACMPXCHGW,
|
||||
|
||||
ALAST
|
||||
};
|
||||
|
||||
@ -441,13 +442,15 @@ enum
|
||||
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,
|
||||
|
@ -16,6 +16,7 @@ OFILES=\
|
||||
optab.$O\
|
||||
pass.$O\
|
||||
span.$O\
|
||||
go.$O\
|
||||
|
||||
HFILES=\
|
||||
l.h\
|
||||
@ -35,3 +36,6 @@ clean:
|
||||
|
||||
install: $(TARG)
|
||||
cp $(TARG) $(BIN)/$(TARG)
|
||||
|
||||
go.o: ../ld/go.c
|
||||
|
||||
|
@ -58,6 +58,7 @@ struct Adr
|
||||
char u0scon[8];
|
||||
Prog *u0cond; /* not used, but should be D_BRANCH */
|
||||
Ieee u0ieee;
|
||||
char *u0sbig;
|
||||
} u0;
|
||||
union
|
||||
{
|
||||
@ -74,6 +75,7 @@ struct Adr
|
||||
#define scon u0.u0scon
|
||||
#define cond u0.u0cond
|
||||
#define ieee u0.u0ieee
|
||||
#define sbig u0.u0sbig
|
||||
|
||||
#define autom u1.u1autom
|
||||
#define sym u1.u1sym
|
||||
@ -84,6 +86,7 @@ struct Prog
|
||||
Adr to;
|
||||
Prog *forwd;
|
||||
Prog* link;
|
||||
Prog* dlink;
|
||||
Prog* pcond; /* work on this */
|
||||
int32 pc;
|
||||
int32 line;
|
||||
@ -108,10 +111,14 @@ struct Sym
|
||||
short become;
|
||||
short frame;
|
||||
uchar subtype;
|
||||
uchar dupok;
|
||||
uchar reachable;
|
||||
ushort file;
|
||||
int32 value;
|
||||
int32 sig;
|
||||
Sym* link;
|
||||
Prog* text;
|
||||
Prog* data;
|
||||
};
|
||||
struct Optab
|
||||
{
|
||||
@ -123,7 +130,9 @@ struct Optab
|
||||
|
||||
enum
|
||||
{
|
||||
STEXT = 1,
|
||||
Sxxx,
|
||||
|
||||
STEXT,
|
||||
SDATA,
|
||||
SBSS,
|
||||
SDATA1,
|
||||
@ -352,6 +361,8 @@ void lputl(int32);
|
||||
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*);
|
||||
@ -375,6 +386,16 @@ uint32 machheadr(void);
|
||||
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;
|
||||
|
@ -99,7 +99,7 @@ Dconv(Fmt *fp)
|
||||
|
||||
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
|
||||
|
@ -333,6 +333,10 @@ main(int argc, char *argv[])
|
||||
sprint(a, "%s/lib/lib_%s_%s.a", goroot, goarch, goos);
|
||||
objfile(a);
|
||||
}
|
||||
definetypestrings();
|
||||
definetypesigs();
|
||||
deadcode();
|
||||
|
||||
firstp = firstp->link;
|
||||
if(firstp == P)
|
||||
errorexit();
|
||||
@ -848,7 +852,7 @@ ldobj(Biobuf *f, int32 len, char *pn)
|
||||
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:
|
||||
@ -1017,6 +1021,20 @@ loop:
|
||||
|
||||
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
|
||||
@ -1056,19 +1074,7 @@ loop:
|
||||
}
|
||||
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:
|
||||
|
@ -388,9 +388,6 @@ Optab optab[] =
|
||||
{ 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 },
|
||||
@ -688,5 +685,11 @@ Optab optab[] =
|
||||
{ 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
|
||||
};
|
||||
|
@ -802,7 +802,7 @@ ckoff(Sym *s, int32 v)
|
||||
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;
|
||||
@ -820,6 +820,30 @@ newdata(Sym *s, int o, int w, int t)
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -146,12 +146,9 @@ xdefine(char *p, int t, int32 v)
|
||||
}
|
||||
|
||||
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++;
|
||||
@ -211,25 +208,25 @@ asmsym(void)
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@ -241,22 +238,22 @@ asmsym(void)
|
||||
/* 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);
|
||||
@ -366,7 +363,7 @@ oclass(Adr *a)
|
||||
{
|
||||
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) {
|
||||
@ -615,7 +612,7 @@ asmand(Adr *a, int r)
|
||||
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);
|
||||
@ -663,7 +660,7 @@ asmand(Adr *a, int r)
|
||||
*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);
|
||||
|
587
src/cmd/ld/go.c
Normal file
587
src/cmd/ld/go.c
Normal file
@ -0,0 +1,587 @@
|
||||
// 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);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user