aboutsummaryrefslogtreecommitdiff
path: root/src/liblink
diff options
context:
space:
mode:
authorRuss Cox <rsc@golang.org>2015-01-19 13:24:43 -0500
committerRuss Cox <rsc@golang.org>2015-01-21 03:15:04 +0000
commitbe818361b9a5e73ade75fa1999ed0dec81de7cb6 (patch)
tree34b62d0de1c4998e5ae4a6f8af2999c4a5d2d8c6 /src/liblink
parent35d3987dbc49d0e2cae4e0cf70dabb62e62cbc50 (diff)
downloadgo-be818361b9a5e73ade75fa1999ed0dec81de7cb6.tar.xz
[dev.cc] liblink: invoke 'go tool objwriter' to implement writeobj, if directed
This CL enables moving the bulk of the object writing code out of liblink and into translated Go libraries in cmd/internal/obj, but it does not do the move. This CL introduces two new environment variables, $GOOBJ and $GOOBJWRITER, but both will be deleted along with the rest of the liblink C code. The default behavior of a build is unchanged by this CL: the C version of liblink uses the C object layout and writing code. If $GOOBJ=1, liblink invokes go tool objwriter instead. If $GOOBJ=2, liblink does its own layout and then invokes go tool objwriter, which checks that it gets the same answer. That is, in $GOOBJ=2 mode, both the C and the Go version of the code run, and the operation fails if the two produce different answers. This provides a very strong check that the translation is working correctly. Change-Id: I56ab49b07ccb2c7b81085f1d6950131047c6aa3c Reviewed-on: https://go-review.googlesource.com/3048 Reviewed-by: Ian Lance Taylor <iant@golang.org>
Diffstat (limited to 'src/liblink')
-rw-r--r--src/liblink/objfile.c52
-rw-r--r--src/liblink/objfilego.c337
2 files changed, 371 insertions, 18 deletions
diff --git a/src/liblink/objfile.c b/src/liblink/objfile.c
index 6711aaf776..8c2257de8a 100644
--- a/src/liblink/objfile.c
+++ b/src/liblink/objfile.c
@@ -119,29 +119,45 @@ static char *rdstring(Biobuf*);
static void rddata(Biobuf*, uchar**, int*);
static LSym *rdsym(Link*, Biobuf*, char*);
-void writeobjdirect(Link*, Biobuf*);
+void writeobjdirect(Link *ctxt, Biobuf *b);
+
+void writeobjgo1(Link*, char*);
+void writeobjgo2(Link*, char*, int64);
+
+extern char *outfile;
void
writeobj(Link *ctxt, Biobuf *b)
{
- char *cmd[3];
-
- // TODO(rsc): Use 'go tool objwriter' to write object file,
- // allowing the bulk of liblink to be moved into Go.
- // As a first step, we check that we can invoke objwriter at all
- // (it is an empty program for now).
- // This tests the cmd/dist bootstrap process, making sure
- // that objwriter is available when it needs to be.
- // Once the support mechanisms are there, we can put the
- // real code in.
-
- cmd[0] = smprint("%s/pkg/tool/%s_%s/objwriter", getgoroot(), getgohostos(), getgohostarch());
- cmd[1] = "ping";
- cmd[2] = nil;
- if(runcmd(cmd) < 0)
- sysfatal("cannot run objwriter: %r");
+ vlong start;
+ char *env;
- writeobjdirect(ctxt, b);
+ // If $GOOBJ > 0, invoke the Go version of the liblink
+ // output routines via a subprocess.
+ // If $GOOBJ == 1, copy that subprocess's output to
+ // the actual output file.
+ // If $GOOBJ >= 2, generate output using the usual C version
+ // but then check that the subprocess wrote the same bytes.
+ // $GOOBJ is a temporary setting for the transition to a
+ // Go liblink back end. Once the C liblink back ends are deleted,
+ // we will hard code the GOOBJ=1 behavior.
+ env = getenv("GOOBJ");
+ if(env == nil)
+ env = "2";
+ if(atoi(env) == 0) {
+ writeobjdirect(ctxt, b);
+ return;
+ }
+
+ Bflush(b);
+ start = Boffset(b);
+ writeobjgo1(ctxt, outfile);
+ if(atoi(env) > 1) {
+ writeobjdirect(ctxt, b);
+ Bflush(b);
+ }
+ writeobjgo2(ctxt, outfile, start);
+ Bseek(b, 0, 2);
}
// The Go and C compilers, and the assembler, call writeobj to write
diff --git a/src/liblink/objfilego.c b/src/liblink/objfilego.c
new file mode 100644
index 0000000000..4d0336e912
--- /dev/null
+++ b/src/liblink/objfilego.c
@@ -0,0 +1,337 @@
+// Copyright 2015 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.
+
+// Writing of internal program representation to a serialized form
+// so that the Go translation of these routines can do the actual
+// program layout.
+// The serialized form and this code support the piecewise transition
+// from C to Go and will be removed along with the rest of the C code
+// when it is no longer needed.
+// There has been no attempt to make it particularly efficient, nor will there be.
+
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <link.h>
+
+/*c2go
+
+char *mktempdir(void);
+int runcmd(char**);
+void removeall(char*);
+*/
+
+static void printtype(Link*, Biobuf*, int);
+static void printsym(Link*, Biobuf*, LSym*);
+static void printprog(Link*, Biobuf*, Prog*);
+static void printaddr(Link*, Biobuf*, Addr*);
+static void printhist(Link*, Biobuf*, Hist*);
+static void printint(Link*, Biobuf*, int64);
+static void printstr(Link*, Biobuf*, char*);
+static void printptr(Link*, Biobuf*, void*);
+
+#undef waitpid
+
+enum
+{
+ TypeEnd = 0,
+ TypeCtxt,
+ TypePlist,
+ TypeSym,
+ TypeProg,
+ TypeAddr,
+ TypeHist,
+};
+
+void
+writeobjgo1(Link *ctxt, char *outfile)
+{
+ int i;
+ char *p;
+ Biobuf *bw;
+ Plist *pl;
+
+ p = smprint("%s.goliblink.in", outfile);
+ bw = Bopen(p, OWRITE);
+ if(bw == nil)
+ sysfatal("writing liblinktest input: %r");
+
+ printtype(ctxt, bw, TypeCtxt);
+ printstr(ctxt, bw, ctxt->arch->name);
+ printint(ctxt, bw, ctxt->goarm);
+ printint(ctxt, bw, ctxt->debugasm);
+ printstr(ctxt, bw, ctxt->trimpath);
+ printptr(ctxt, bw, ctxt->plist);
+ printptr(ctxt, bw, ctxt->plast);
+ printptr(ctxt, bw, ctxt->hist);
+ printptr(ctxt, bw, ctxt->ehist);
+ for(i = 0; i < LINKHASH; i++) {
+ if(ctxt->hash[i] != nil) {
+ printint(ctxt, bw, i);
+ printptr(ctxt, bw, ctxt->hash[i]);
+ }
+ }
+ printint(ctxt, bw, -1);
+
+ printhist(ctxt, bw, ctxt->hist);
+ printhist(ctxt, bw, ctxt->ehist);
+
+ for(pl=ctxt->plist; pl != nil; pl = pl->link) {
+ printtype(ctxt, bw, TypePlist);
+ printptr(ctxt, bw, pl);
+ printint(ctxt, bw, pl->recur);
+ printptr(ctxt, bw, pl->name);
+ printptr(ctxt, bw, pl->firstpc);
+ printptr(ctxt, bw, pl->link);
+ printsym(ctxt, bw, pl->name);
+ printprog(ctxt, bw, pl->firstpc);
+ }
+
+ for(i = 0; i < LINKHASH; i++)
+ printsym(ctxt, bw, ctxt->hash[i]);
+
+ printtype(ctxt, bw, TypeEnd);
+ Bterm(bw);
+}
+
+void
+writeobjgo2(Link *ctxt, char *outfile, int64 offset)
+{
+ char *p, *env, *prog, *cmd[10];
+ char offsetbuf[20];
+
+ USED(ctxt);
+
+ env = getenv("GOOBJWRITER");
+ if(env != nil && env[0] != '\0')
+ prog = env;
+ else
+ prog = smprint("%s/pkg/tool/%s_%s/objwriter", getgoroot(), getgohostos(), getgohostarch());
+
+ p = smprint("%s.goliblink.in", outfile);
+
+ snprint(offsetbuf, sizeof offsetbuf, "%lld", offset);
+
+ cmd[0] = prog;
+ cmd[1] = p;
+ cmd[2] = outfile;
+ cmd[3] = offsetbuf;
+ cmd[4] = ctxt->arch->name;
+ cmd[5] = nil;
+ if(runcmd(cmd) < 0)
+ sysfatal("running %s: %r", prog);
+
+ env = getenv("GOOBJ");
+ if(env == nil || atoi(env) <= 2)
+ remove(p);
+}
+
+static void
+printtype(Link *ctxt, Biobuf *bw, int t)
+{
+ printint(ctxt, bw, t);
+}
+
+static void
+printint(Link *ctxt, Biobuf *bw, int64 v)
+{
+ uint64 u;
+
+ USED(ctxt);
+
+ u = (uint64)(v<<1) ^ (uint64)(v>>63);
+ while(u >= 0x80) {
+ Bputc(bw, u&0x7F | 0x80);
+ u >>= 7;
+ }
+ Bputc(bw, u);
+}
+
+static void
+printstr(Link *ctxt, Biobuf *bw, char *s)
+{
+ if(s == nil)
+ s = "";
+ printint(ctxt, bw, strlen(s));
+ Bwrite(bw, s, strlen(s));
+}
+
+static void
+printptr(Link *ctxt, Biobuf *bw, void *v)
+{
+ printint(ctxt, bw, (int64)(uintptr)v);
+}
+
+static void
+printsym(Link *ctxt, Biobuf *bw, LSym *s)
+{
+ int i;
+ Reloc *r;
+
+ if(s == nil || s->printed)
+ return;
+ s->printed = 1;
+ printtype(ctxt, bw, TypeSym);
+ printptr(ctxt, bw, s);
+ printstr(ctxt, bw, s->name);
+ printstr(ctxt, bw, s->extname);
+ printint(ctxt, bw, s->type);
+ printint(ctxt, bw, s->version);
+ printint(ctxt, bw, s->dupok);
+ printint(ctxt, bw, s->external);
+ printint(ctxt, bw, s->nosplit);
+ printint(ctxt, bw, s->reachable);
+ printint(ctxt, bw, s->cgoexport);
+ printint(ctxt, bw, s->special);
+ printint(ctxt, bw, s->stkcheck);
+ printint(ctxt, bw, s->hide);
+ printint(ctxt, bw, s->leaf);
+ printint(ctxt, bw, s->fnptr);
+ printint(ctxt, bw, s->seenglobl);
+ printint(ctxt, bw, s->onlist);
+ printint(ctxt, bw, s->symid);
+ printint(ctxt, bw, s->dynid);
+ printint(ctxt, bw, s->sig);
+ printint(ctxt, bw, s->plt);
+ printint(ctxt, bw, s->got);
+ printint(ctxt, bw, s->align);
+ printint(ctxt, bw, s->elfsym);
+ printint(ctxt, bw, s->args);
+ printint(ctxt, bw, s->locals);
+ printint(ctxt, bw, s->value);
+ printint(ctxt, bw, s->size);
+ printptr(ctxt, bw, s->hash);
+ printptr(ctxt, bw, s->allsym);
+ printptr(ctxt, bw, s->next);
+ printptr(ctxt, bw, s->sub);
+ printptr(ctxt, bw, s->outer);
+ printptr(ctxt, bw, s->gotype);
+ printptr(ctxt, bw, s->reachparent);
+ printptr(ctxt, bw, s->queue);
+ printstr(ctxt, bw, s->file);
+ printstr(ctxt, bw, s->dynimplib);
+ printstr(ctxt, bw, s->dynimpvers);
+ printptr(ctxt, bw, s->text);
+ printptr(ctxt, bw, s->etext);
+ printint(ctxt, bw, s->np);
+ Bwrite(bw, s->p, s->np);
+ printint(ctxt, bw, s->nr);
+ for(i=0; i<s->nr; i++) {
+ r = s->r+i;
+ printint(ctxt, bw, r->off);
+ printint(ctxt, bw, r->siz);
+ printint(ctxt, bw, r->done);
+ printint(ctxt, bw, r->type);
+ printint(ctxt, bw, r->add);
+ printint(ctxt, bw, r->xadd);
+ printptr(ctxt, bw, r->sym);
+ printptr(ctxt, bw, r->xsym);
+ }
+
+ printsym(ctxt, bw, s->hash);
+ printsym(ctxt, bw, s->allsym);
+ printsym(ctxt, bw, s->next);
+ printsym(ctxt, bw, s->sub);
+ printsym(ctxt, bw, s->outer);
+ printsym(ctxt, bw, s->gotype);
+ printsym(ctxt, bw, s->reachparent);
+ printsym(ctxt, bw, s->queue);
+ printprog(ctxt, bw, s->text);
+ printprog(ctxt, bw, s->etext);
+ for(i=0; i<s->nr; i++) {
+ r = s->r+i;
+ printsym(ctxt, bw, r->sym);
+ printsym(ctxt, bw, r->xsym);
+ }
+}
+
+static void
+printprog(Link *ctxt, Biobuf *bw, Prog *p0)
+{
+ Prog *p, *q;
+
+ for(p = p0; p != nil && !p->printed; p=p->link) {
+ p->printed = 1;
+
+ printtype(ctxt, bw, TypeProg);
+ printptr(ctxt, bw, p);
+ printint(ctxt, bw, p->pc);
+ printint(ctxt, bw, p->lineno);
+ printptr(ctxt, bw, p->link);
+ printint(ctxt, bw, p->as);
+ printint(ctxt, bw, p->reg);
+ printint(ctxt, bw, p->scond);
+ printint(ctxt, bw, p->width);
+ printaddr(ctxt, bw, &p->from);
+ printaddr(ctxt, bw, &p->from3);
+ printaddr(ctxt, bw, &p->to);
+ printsym(ctxt, bw, p->from.sym);
+ printsym(ctxt, bw, p->from.gotype);
+ printsym(ctxt, bw, p->to.sym);
+ printsym(ctxt, bw, p->to.gotype);
+ }
+
+ q = p;
+ for(p=p0; p!=q; p=p->link) {
+ if(p->from.type == ctxt->arch->D_BRANCH)
+ printprog(ctxt, bw, p->from.u.branch);
+ if(p->to.type == ctxt->arch->D_BRANCH)
+ printprog(ctxt, bw, p->to.u.branch);
+ }
+}
+
+static void
+printaddr(Link *ctxt, Biobuf *bw, Addr *a)
+{
+ static char zero[8];
+
+ printtype(ctxt, bw, TypeAddr);
+ printint(ctxt, bw, a->offset);
+ if(a->type == ctxt->arch->D_FCONST) {
+ uint64 u;
+ float64 f;
+ f = a->u.dval;
+ memmove(&u, &f, 8);
+ printint(ctxt, bw, u);
+ } else
+ printint(ctxt, bw, 0);
+ if(a->type == ctxt->arch->D_SCONST)
+ Bwrite(bw, a->u.sval, 8);
+ else
+ Bwrite(bw, zero, 8);
+ if(a->type == ctxt->arch->D_BRANCH)
+ printptr(ctxt, bw, a->u.branch);
+ else
+ printptr(ctxt, bw, nil);
+ printptr(ctxt, bw, a->sym);
+ printptr(ctxt, bw, a->gotype);
+ printint(ctxt, bw, a->type);
+ printint(ctxt, bw, a->index);
+ printint(ctxt, bw, a->scale);
+ printint(ctxt, bw, a->reg);
+ printint(ctxt, bw, a->name);
+ printint(ctxt, bw, a->class);
+ printint(ctxt, bw, a->etype);
+ printint(ctxt, bw, a->offset2);
+ printint(ctxt, bw, a->width);
+}
+
+static void
+printhist(Link *ctxt, Biobuf *bw, Hist *h)
+{
+ if(h == nil || h->printed)
+ return;
+ h->printed = 1;
+
+ printtype(ctxt, bw, TypeHist);
+ printptr(ctxt, bw, h);
+ printptr(ctxt, bw, h->link);
+ if(h->name == nil)
+ printstr(ctxt, bw, "<no name>");
+ else
+ printstr(ctxt, bw, h->name);
+ printint(ctxt, bw, h->line);
+ printint(ctxt, bw, h->offset);
+ printhist(ctxt, bw, h->link);
+}