summaryrefslogtreecommitdiff
path: root/src/liblink/ld.c
diff options
context:
space:
mode:
authorRuss Cox <rsc@golang.org>2013-12-16 12:51:58 -0500
committerRuss Cox <rsc@golang.org>2013-12-16 12:51:58 -0500
commit43cad0aa4d6d397630daa553bf4ed28a078637f0 (patch)
treeecb464b206a70772c61e514e72a3b14d4c776b71 /src/liblink/ld.c
parent737d6de29569572e16839f9cf6d91cc1db75b622 (diff)
downloadgo-43cad0aa4d6d397630daa553bf4ed28a078637f0.tar.gz
cmd/ld: move instruction selection + layout into compilers, assemblers
- new object file reader/writer (liblink/objfile.c) - remove old object file writing routines - add pcdata iterator - remove all trace of "line number stack" and "path fragments" from object files, linker (!!!) - dwarf now writes a single "compilation unit" instead of one per package This CL disables the check for chains of no-split functions that could overflow the stack red zone. A future CL will attack the problem of reenabling that check (issue 6931). This CL is just the liblink and cmd/ld changes. There are minor associated adjustments in CL 37030045. Each depends on the other. R=golang-dev, dave, iant CC=golang-dev https://codereview.appspot.com/39680043
Diffstat (limited to 'src/liblink/ld.c')
-rw-r--r--src/liblink/ld.c340
1 files changed, 11 insertions, 329 deletions
diff --git a/src/liblink/ld.c b/src/liblink/ld.c
index f6632877b..1d06f809a 100644
--- a/src/liblink/ld.c
+++ b/src/liblink/ld.c
@@ -35,329 +35,14 @@
#include <link.h>
void
-copyhistfrog(Link *ctxt, char *buf, int nbuf)
+addlib(Link *ctxt, char *src, char *obj, char *pathname)
{
- char *p, *ep;
+ char name[1024], pname[1024], *p;
int i;
- p = buf;
- ep = buf + nbuf;
- for(i=0; i<ctxt->histfrogp; i++) {
- p = seprint(p, ep, "%s", ctxt->histfrog[i]->name+1);
- if(i+1<ctxt->histfrogp && (p == buf || p[-1] != '/'))
- p = seprint(p, ep, "/");
- }
-}
-
-void
-addhist(Link *ctxt, int32 line, int type)
-{
- Auto *u;
- LSym *s;
- int i, j, k;
-
- u = emallocz(sizeof(Auto));
- s = emallocz(sizeof(LSym));
- s->name = emallocz(2*(ctxt->histfrogp+1) + 1);
-
- u->asym = s;
- u->type = type;
- u->aoffset = line;
- u->link = ctxt->curhist;
- ctxt->curhist = u;
-
- s->name[0] = 0;
- j = 1;
- for(i=0; i<ctxt->histfrogp; i++) {
- k = ctxt->histfrog[i]->value;
- s->name[j+0] = k>>8;
- s->name[j+1] = k;
- j += 2;
- }
- s->name[j] = 0;
- s->name[j+1] = 0;
-}
-
-void
-histtoauto(Link *ctxt)
-{
- Auto *l;
-
- while(l = ctxt->curhist) {
- ctxt->curhist = l->link;
- l->link = ctxt->curauto;
- ctxt->curauto = l;
- }
-}
-
-void
-collapsefrog(Link *ctxt, LSym *s)
-{
- int i;
-
- /*
- * bad encoding of path components only allows
- * MAXHIST components. if there is an overflow,
- * first try to collapse xxx/..
- */
- for(i=1; i<ctxt->histfrogp; i++)
- if(strcmp(ctxt->histfrog[i]->name+1, "..") == 0) {
- memmove(ctxt->histfrog+i-1, ctxt->histfrog+i+1,
- (ctxt->histfrogp-i-1)*sizeof(ctxt->histfrog[0]));
- ctxt->histfrogp--;
- goto out;
- }
-
- /*
- * next try to collapse .
- */
- for(i=0; i<ctxt->histfrogp; i++)
- if(strcmp(ctxt->histfrog[i]->name+1, ".") == 0) {
- memmove(ctxt->histfrog+i, ctxt->histfrog+i+1,
- (ctxt->histfrogp-i-1)*sizeof(ctxt->histfrog[0]));
- goto out;
- }
-
- /*
- * last chance, just truncate from front
- */
- memmove(ctxt->histfrog+0, ctxt->histfrog+1,
- (ctxt->histfrogp-1)*sizeof(ctxt->histfrog[0]));
-
-out:
- ctxt->histfrog[ctxt->histfrogp-1] = s;
-}
-
-// Saved history stacks encountered while reading archives.
-// Keeping them allows us to answer virtual lineno -> file:line
-// queries.
-//
-// The history stack is a complex data structure, described best at the
-// bottom of http://plan9.bell-labs.com/magic/man2html/6/a.out.
-// One of the key benefits of interpreting it here is that the runtime
-// does not have to. Perhaps some day the compilers could generate
-// a simpler linker input too.
-
-// savehist processes a single line, off history directive
-// found in the input object file.
-void
-savehist(Link *ctxt, int32 line, int32 off)
-{
- char tmp[1024];
- LSym *file;
- Hist2 *h;
-
- // NOTE(rsc): We used to do the copyctxt->histfrog first and this
- // condition was if(tmp[0] != '\0') to check for an empty string,
- // implying that ctxt->histfrogp == 0, implying that this is a history pop.
- // However, on Windows in the misc/cgo test, the linker is
- // presented with an ANAME corresponding to an empty string,
- // that ANAME ends up being the only ctxt->histfrog, and thus we have
- // a situation where ctxt->histfrogp > 0 (not a pop) but the path we find
- // is the empty string. Really that shouldn't happen, but it doesn't
- // seem to be bothering anyone yet, and it's easier to fix the condition
- // to test ctxt->histfrogp than to track down where that empty string is
- // coming from. Probably it is coming from go tool pack's P command.
- if(ctxt->histfrogp > 0) {
- tmp[0] = '\0';
- copyhistfrog(ctxt, tmp, sizeof tmp);
- file = linklookup(ctxt, tmp, HistVersion);
- } else
- file = nil;
-
- if(file != nil && line == 1 && off == 0) {
- // start of new stack
- if(ctxt->histdepth != 0)
- sysfatal("history stack phase error: unexpected start of new stack depth=%d file=%s", ctxt->histdepth, tmp);
- ctxt->nhist2 = 0;
- ctxt->histcopy = nil;
- }
-
- if(ctxt->nhist2 >= ctxt->maxhist2) {
- if(ctxt->maxhist2 == 0)
- ctxt->maxhist2 = 1;
- ctxt->maxhist2 *= 2;
- ctxt->hist2 = erealloc(ctxt->hist2, ctxt->maxhist2*sizeof ctxt->hist2[0]);
- }
- h = &ctxt->hist2[ctxt->nhist2++];
- h->line = line;
- h->off = off;
- h->file = file;
-
- if(file != nil) {
- if(off == 0)
- ctxt->histdepth++;
- } else {
- if(off != 0)
- sysfatal("history stack phase error: bad offset in pop");
- ctxt->histdepth--;
- }
-}
-
-// gethist returns the history stack currently in effect.
-// The result is valid indefinitely.
-Hist2*
-gethist(Link *ctxt)
-{
- if(ctxt->histcopy == nil) {
- if(ctxt->nhist2 == 0)
- return nil;
- ctxt->histcopy = emallocz((ctxt->nhist2+1)*sizeof ctxt->hist2[0]);
- memmove(ctxt->histcopy, ctxt->hist2, ctxt->nhist2*sizeof ctxt->hist2[0]);
- ctxt->histcopy[ctxt->nhist2].line = -1;
- }
- return ctxt->histcopy;
-}
-
-typedef struct Hstack Hstack;
-struct Hstack
-{
- Hist2 *h;
- int delta;
-};
-
-// getline sets *f to the file number and *l to the line number
-// of the virtual line number line according to the history stack h.
-void
-linkgetline(Link *ctxt, Hist2 *h, int32 line, LSym **f, int32 *l)
-{
- Hstack stk[100];
- int nstk, start;
- Hist2 *top, *h0;
- static Hist2 *lasth;
- static int32 laststart, lastend, lastdelta;
- static LSym *lastfile;
-
- h0 = h;
- *f = 0;
- *l = 0;
- start = 0;
- if(h == nil || line == 0) {
- print("%s: getline: h=%p line=%d\n", ctxt->cursym->name, h, line);
- return;
- }
-
- // Cache span used during last lookup, so that sequential
- // translation of line numbers in compiled code is efficient.
- if(!ctxt->debughist && lasth == h && laststart <= line && line < lastend) {
- *f = lastfile;
- *l = line - lastdelta;
- return;
- }
-
- if(ctxt->debughist)
- print("getline %d laststart=%d lastend=%d\n", line, laststart, lastend);
-
- nstk = 0;
- for(; h->line != -1; h++) {
- if(ctxt->debughist)
- print("\t%s %d %d\n", h->file ? h->file->name : "?", h->line, h->off);
-
- if(h->line > line) {
- if(nstk == 0)
- sysfatal("history stack phase error: empty stack at line %d", (int)line);
- top = stk[nstk-1].h;
- lasth = h;
- lastfile = top->file;
- laststart = start;
- lastend = h->line;
- lastdelta = stk[nstk-1].delta;
- *f = lastfile;
- *l = line - lastdelta;
- if(ctxt->debughist)
- print("\tgot %d %d [%d %d %d]\n", *f, *l, laststart, lastend, lastdelta);
- return;
- }
- if(h->file == nil) {
- // pop included file
- if(nstk == 0)
- sysfatal("history stack phase error: stack underflow");
- nstk--;
- if(nstk > 0)
- stk[nstk-1].delta += h->line - stk[nstk].h->line;
- start = h->line;
- } else if(h->off == 0) {
- // push included file
- if(nstk >= nelem(stk))
- sysfatal("history stack phase error: stack overflow");
- start = h->line;
- stk[nstk].h = h;
- stk[nstk].delta = h->line - 1;
- nstk++;
- } else {
- // #line directive
- if(nstk == 0)
- sysfatal("history stack phase error: stack underflow");
- stk[nstk-1].h = h;
- stk[nstk-1].delta = h->line - h->off;
- start = h->line;
- }
- if(ctxt->debughist)
- print("\t\tnstk=%d delta=%d\n", nstk, stk[nstk].delta);
- }
-
- sysfatal("history stack phase error: cannot find line for %d", line);
- nstk = 0;
- for(h = h0; h->line != -1; h++) {
- print("\t%d %d %s\n", h->line, h->off, h->file ? h->file->name : "");
- if(h->file == nil)
- nstk--;
- else if(h->off == 0)
- nstk++;
- }
-}
-
-void
-addlib(Link *ctxt, char *src, char *obj)
-{
- char name[1024], pname[1024], comp[256], *p;
- int i, search;
-
- if(ctxt->histfrogp <= 0)
- return;
-
- search = 0;
- if(ctxt->histfrog[0]->name[1] == '/') {
- sprint(name, "");
- i = 1;
- } else
- if(isalpha((uchar)ctxt->histfrog[0]->name[1]) && ctxt->histfrog[0]->name[2] == ':') {
- strcpy(name, ctxt->histfrog[0]->name+1);
- i = 1;
- } else
- if(ctxt->histfrog[0]->name[1] == '.') {
- sprint(name, ".");
- i = 0;
- } else {
- sprint(name, "");
- i = 0;
- search = 1;
- }
-
- for(; i<ctxt->histfrogp; i++) {
- snprint(comp, sizeof comp, "%s", ctxt->histfrog[i]->name+1);
- for(;;) {
- p = strstr(comp, "$O");
- if(p == 0)
- break;
- memmove(p+1, p+2, strlen(p+2)+1);
- p[0] = ctxt->thechar;
- }
- for(;;) {
- p = strstr(comp, "$M");
- if(p == 0)
- break;
- if(strlen(comp)+strlen(ctxt->thestring)-2+1 >= sizeof comp)
- sysfatal("library component too long");
- memmove(p+strlen(ctxt->thestring), p+2, strlen(p+2)+1);
- memmove(p, ctxt->thestring, strlen(ctxt->thestring));
- }
- if(strlen(name) + strlen(comp) + 3 >= sizeof(name))
- sysfatal("library component too long");
- if(i > 0 || !search)
- strcat(name, "/");
- strcat(name, comp);
- }
+ if(strlen(pathname) >= sizeof name)
+ sysfatal("addlib pathname too long");
+ strcpy(name, pathname);
cleanname(name);
// runtime.a -> runtime
@@ -376,15 +61,12 @@ addlib(Link *ctxt, char *src, char *obj)
if(p != nil)
*p = '.';
- if(search) {
- // try dot, -L "libdir", and then goroot.
- for(i=0; i<ctxt->nlibdir; i++) {
- snprint(pname, sizeof pname, "%s/%s", ctxt->libdir[i], name);
- if(access(pname, AEXIST) >= 0)
- break;
- }
- }else
- strcpy(pname, name);
+ // try dot, -L "libdir", and then goroot.
+ for(i=0; i<ctxt->nlibdir; i++) {
+ snprint(pname, sizeof pname, "%s/%s", ctxt->libdir[i], name);
+ if(access(pname, AEXIST) >= 0)
+ break;
+ }
cleanname(pname);
/* runtime.a -> runtime */