// 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 #include #include "go.h" /* * architecture-independent object file output */ 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) { flusherrors(); print("can't create %s: %r\n", outfile); errorexit(); } startobj = 0; if(writearchive) { Bwrite(bout, "!\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(); 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()); } Bprint(bout, "\n!\n"); externs = nil; if(externdcl != nil) externs = externdcl->end; dumpglobls(); dumptypestructs(); // Dump extra globals. tmp = externdcl; if(externs != nil) externdcl = externs->next; dumpglobls(); externdcl = tmp; 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); } static void dumpglobls(void) { Node *n; NodeList *l; // add globals for(l=externdcl; l; l=l->next) { n = l->n; if(n->op != ONAME) continue; if(n->type == T) fatal("external %N nil type\n", n); if(n->class == PFUNC) continue; if(n->sym->pkg != localpkg) continue; dowidth(n->type); 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, LSym *s) { Bwrite(b, s->name, strlen(s->name)+1); } LSym* linksym(Sym *s) { 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; } int duintxx(Sym *s, int off, uint64 v, int wid) { // 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 duint8(Sym *s, int off, uint8 v) { return duintxx(s, off, v, 1); } int duint16(Sym *s, int off, uint16 v) { return duintxx(s, off, v, 2); } int duint32(Sym *s, int off, uint32 v) { return duintxx(s, off, v, 4); } int duint64(Sym *s, int off, uint64 v) { return duintxx(s, off, v, 8); } int duintptr(Sym *s, int off, uint64 v) { return duintxx(s, off, v, widthptr); } Sym* stringsym(char *s, int len) { static int gen; Sym *sym; int off, n, m; struct { Strlit lit; char buf[110]; } tmp; Pkg *pkg; if(len > 100) { // huge strings are made static to avoid long names snprint(namebuf, sizeof(namebuf), ".gostring.%d", ++gen); pkg = localpkg; } else { // small strings get named by their contents, // so that multiple modules using the same string // can share it. tmp.lit.len = len; memmove(tmp.lit.s, s, len); tmp.lit.s[len] = '\0'; snprint(namebuf, sizeof(namebuf), "\"%Z\"", &tmp.lit); pkg = gostringpkg; } sym = pkglookup(namebuf, pkg); // SymUniq flag indicates that data is generated already if(sym->flags & SymUniq) return sym; sym->flags |= SymUniq; sym->def = newname(sym); off = 0; // string header off = dsymptr(sym, off, sym, widthptr+widthint); off = duintxx(sym, off, len, widthint); // string data for(n=0; n len-n) m = len-n; off = dsname(sym, off, s+n, m); } off = duint8(sym, off, 0); // terminating NUL for runtime off = (off+widthptr-1)&~(widthptr-1); // round to pointer alignment ggloblsym(sym, off, 1, 1); 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 = 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); }