From be818361b9a5e73ade75fa1999ed0dec81de7cb6 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Mon, 19 Jan 2015 13:24:43 -0500 Subject: [PATCH] [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 --- include/link.h | 3 + src/liblink/objfile.c | 52 ++++--- src/liblink/objfilego.c | 337 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 374 insertions(+), 18 deletions(-) create mode 100644 src/liblink/objfilego.c diff --git a/include/link.h b/include/link.h index 15a2878792..5dffe7bc64 100644 --- a/include/link.h +++ b/include/link.h @@ -115,6 +115,7 @@ struct Prog uchar ft; /* 6l, 8l oclass cache */ uchar tt; // 6l, 8l uchar isize; // 6l, 8l + uchar printed; char width; /* fake for DATA */ char mode; /* 16, 32, or 64 in 6l, 8l; internal use in 5g, 6g, 8g */ @@ -145,6 +146,7 @@ struct LSym uchar localentry; // ppc64: instrs between global & local entry uchar seenglobl; uchar onlist; // on the textp or datap lists + uchar printed; int16 symid; // for writing .5/.6/.8 files int32 dynid; int32 sig; @@ -300,6 +302,7 @@ struct Hist char* name; int32 line; int32 offset; + uchar printed; }; struct Plist 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 +#include +#include +#include + +/*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; inr; 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; inr; 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, ""); + else + printstr(ctxt, bw, h->name); + printint(ctxt, bw, h->line); + printint(ctxt, bw, h->offset); + printhist(ctxt, bw, h->link); +}