diff options
Diffstat (limited to 'src/cmd/gc/obj.c')
-rw-r--r-- | src/cmd/gc/obj.c | 281 |
1 files changed, 112 insertions, 169 deletions
diff --git a/src/cmd/gc/obj.c b/src/cmd/gc/obj.c index 4cad08924..4eeb03aa8 100644 --- a/src/cmd/gc/obj.c +++ b/src/cmd/gc/obj.c @@ -10,13 +10,28 @@ * architecture-independent object file output */ -static void outhist(Biobuf *b); static void dumpglobls(void); +enum +{ + ArhdrSize = 60 +}; + +static void +formathdr(char *arhdr, char *name, vlong size) +{ + snprint(arhdr, ArhdrSize, "%-16s%-12d%-6d%-6d%-8o%-10lld`", + name, 0, 0, 0, 0644, size); + arhdr[ArhdrSize-1] = '\n'; // overwrite \0 written by snprint +} + void dumpobj(void) { NodeList *externs, *tmp; + char arhdr[ArhdrSize]; + vlong startobj, size; + Sym *zero; bout = Bopen(outfile, OWRITE); if(bout == nil) { @@ -25,13 +40,34 @@ dumpobj(void) errorexit(); } - Bprint(bout, "go object %s %s %s %s\n", getgoos(), thestring, getgoversion(), expstring()); - Bprint(bout, " exports automatically generated from\n"); - Bprint(bout, " %s in package \"%s\"\n", curio.infile, localpkg->name); + startobj = 0; + if(writearchive) { + Bwrite(bout, "!<arch>\n", 8); + memset(arhdr, 0, sizeof arhdr); + Bwrite(bout, arhdr, sizeof arhdr); + startobj = Boffset(bout); + } + Bprint(bout, "go object %s %s %s %s\n", getgoos(), getgoarch(), getgoversion(), expstring()); dumpexport(); - Bprint(bout, "\n!\n"); + + if(writearchive) { + Bflush(bout); + size = Boffset(bout) - startobj; + if(size&1) + Bputc(bout, 0); + Bseek(bout, startobj - ArhdrSize, 0); + formathdr(arhdr, "__.PKGDEF", size); + Bwrite(bout, arhdr, ArhdrSize); + Bflush(bout); + + Bseek(bout, startobj + size + (size&1), 0); + memset(arhdr, 0, ArhdrSize); + Bwrite(bout, arhdr, ArhdrSize); + startobj = Boffset(bout); + Bprint(bout, "go object %s %s %s %s\n", getgoos(), getgoarch(), getgoversion(), expstring()); + } - outhist(bout); + Bprint(bout, "\n!\n"); externs = nil; if(externdcl != nil) @@ -47,9 +83,22 @@ dumpobj(void) dumpglobls(); externdcl = tmp; - dumpdata(); - dumpfuncs(); + zero = pkglookup("zerovalue", runtimepkg); + ggloblsym(zero, zerosize, 1, 1); + dumpdata(); + writeobj(ctxt, bout); + + if(writearchive) { + Bflush(bout); + size = Boffset(bout) - startobj; + if(size&1) + Bputc(bout, 0); + Bseek(bout, startobj - ArhdrSize, 0); + snprint(namebuf, sizeof namebuf, "_go_.%c", thechar); + formathdr(arhdr, namebuf, size); + Bwrite(bout, arhdr, ArhdrSize); + } Bterm(bout); } @@ -75,184 +124,50 @@ dumpglobls(void) ggloblnod(n); } - + for(l=funcsyms; l; l=l->next) { n = l->n; dsymptr(n->sym, 0, n->sym->def->shortname->sym, 0); ggloblsym(n->sym, widthptr, 1, 1); } + + // Do not reprocess funcsyms on next dumpglobls call. + funcsyms = nil; } void -Bputname(Biobuf *b, Sym *s) +Bputname(Biobuf *b, LSym *s) { - Bprint(b, "%s", s->pkg->prefix); - BPUTC(b, '.'); Bwrite(b, s->name, strlen(s->name)+1); } -static void -outzfile(Biobuf *b, char *p) -{ - char *q, *q2; - - while(p) { - q = utfrune(p, '/'); - if(windows) { - q2 = utfrune(p, '\\'); - if(q2 && (!q || q2 < q)) - q = q2; - } - if(!q) { - zfile(b, p, strlen(p)); - return; - } - if(q > p) - zfile(b, p, q-p); - p = q + 1; - } -} - -#define isdelim(c) (c == '/' || c == '\\') - -static void -outwinname(Biobuf *b, Hist *h, char *ds, char *p) +LSym* +linksym(Sym *s) { - if(isdelim(p[0])) { - // full rooted name - zfile(b, ds, 3); // leading "c:/" - outzfile(b, p+1); - } else { - // relative name - if(h->offset >= 0 && pathname && pathname[1] == ':') { - if(tolowerrune(ds[0]) == tolowerrune(pathname[0])) { - // using current drive - zfile(b, pathname, 3); // leading "c:/" - outzfile(b, pathname+3); - } else { - // using drive other then current, - // we don't have any simple way to - // determine current working directory - // there, therefore will output name as is - zfile(b, ds, 2); // leading "c:" - } - } - outzfile(b, p); + char *p; + + if(s == nil) + return nil; + if(s->lsym != nil) + return s->lsym; + if(isblanksym(s)) + s->lsym = linklookup(ctxt, "_", 0); + else { + p = smprint("%s.%s", s->pkg->prefix, s->name); + s->lsym = linklookup(ctxt, p, 0); + free(p); } + return s->lsym; } -static void -outhist(Biobuf *b) -{ - Hist *h; - char *p, ds[] = {'c', ':', '/', 0}; - char *tofree; - int n; - static int first = 1; - static char *goroot, *goroot_final; - - if(first) { - // Decide whether we need to rewrite paths from $GOROOT to $GOROOT_FINAL. - first = 0; - goroot = getenv("GOROOT"); - goroot_final = getenv("GOROOT_FINAL"); - if(goroot == nil) - goroot = ""; - if(goroot_final == nil) - goroot_final = goroot; - if(strcmp(goroot, goroot_final) == 0) { - goroot = nil; - goroot_final = nil; - } - } - - tofree = nil; - for(h = hist; h != H; h = h->link) { - p = h->name; - if(p) { - if(goroot != nil) { - n = strlen(goroot); - if(strncmp(p, goroot, strlen(goroot)) == 0 && p[n] == '/') { - tofree = smprint("%s%s", goroot_final, p+n); - p = tofree; - } - } - if(windows) { - // if windows variable is set, then, we know already, - // pathname is started with windows drive specifier - // and all '\' were replaced with '/' (see lex.c) - if(isdelim(p[0]) && isdelim(p[1])) { - // file name has network name in it, - // like \\server\share\dir\file.go - zfile(b, "//", 2); // leading "//" - outzfile(b, p+2); - } else if(p[1] == ':') { - // file name has drive letter in it - ds[0] = p[0]; - outwinname(b, h, ds, p+2); - } else { - // no drive letter in file name - outwinname(b, h, pathname, p); - } - } else { - if(p[0] == '/') { - // full rooted name, like /home/rsc/dir/file.go - zfile(b, "/", 1); // leading "/" - outzfile(b, p+1); - } else { - // relative name, like dir/file.go - if(h->offset >= 0 && pathname && pathname[0] == '/') { - zfile(b, "/", 1); // leading "/" - outzfile(b, pathname+1); - } - outzfile(b, p); - } - } - } - zhist(b, h->line, h->offset); - if(tofree) { - free(tofree); - tofree = nil; - } - } -} - -void -ieeedtod(uint64 *ieee, double native) +int +duintxx(Sym *s, int off, uint64 v, int wid) { - double fr, ho, f; - int exp; - uint32 h, l; - uint64 bits; - - if(native < 0) { - ieeedtod(ieee, -native); - *ieee |= 1ULL<<63; - return; - } - if(native == 0) { - *ieee = 0; - return; - } - fr = frexp(native, &exp); - f = 2097152L; /* shouldn't use fp constants here */ - fr = modf(fr*f, &ho); - h = ho; - h &= 0xfffffL; - f = 65536L; - fr = modf(fr*f, &ho); - l = ho; - l <<= 16; - l |= (int32)(fr*f); - bits = ((uint64)h<<32) | l; - if(exp < -1021) { - // gradual underflow - bits |= 1LL<<52; - bits >>= -1021 - exp; - exp = -1022; - } - bits |= (uint64)(exp+1022L) << 52; - *ieee = bits; + // Update symbol data directly instead of generating a + // DATA instruction that liblink will have to interpret later. + // This reduces compilation time and memory usage. + off = rnd(off, wid); + return setuintxx(ctxt, linksym(s), off, v, wid); } int @@ -338,3 +253,31 @@ stringsym(char *s, int len) return sym; } + +void +slicebytes(Node *nam, char *s, int len) +{ + int off, n, m; + static int gen; + Sym *sym; + + snprint(namebuf, sizeof(namebuf), ".gobytes.%d", ++gen); + sym = pkglookup(namebuf, localpkg); + sym->def = newname(sym); + + off = 0; + for(n=0; n<len; n+=m) { + m = 8; + if(m > len-n) + m = len-n; + off = dsname(sym, off, s+n, m); + } + ggloblsym(sym, off, 0, 0); + + if(nam->op != ONAME) + fatal("slicebytes %N", nam); + off = nam->xoffset; + off = dsymptr(nam->sym, off, sym, 0); + off = duintxx(nam->sym, off, len, widthint); + duintxx(nam->sym, off, len, widthint); +} |