github.com/bgentry/go@v0.0.0-20150121062915-6cf5a733d54d/src/liblink/objfile.c (about)

     1  // Copyright 2013 The Go Authors.  All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // Writing and reading of Go object files.
     6  //
     7  // Originally, Go object files were Plan 9 object files, but no longer.
     8  // Now they are more like standard object files, in that each symbol is defined
     9  // by an associated memory image (bytes) and a list of relocations to apply
    10  // during linking. We do not (yet?) use a standard file format, however.
    11  // For now, the format is chosen to be as simple as possible to read and write.
    12  // It may change for reasons of efficiency, or we may even switch to a
    13  // standard file format if there are compelling benefits to doing so.
    14  // See golang.org/s/go13linker for more background.
    15  //
    16  // The file format is:
    17  //
    18  //	- magic header: "\x00\x00go13ld"
    19  //	- byte 1 - version number
    20  //	- sequence of strings giving dependencies (imported packages)
    21  //	- empty string (marks end of sequence)
    22  //	- sequence of defined symbols
    23  //	- byte 0xff (marks end of sequence)
    24  //	- magic footer: "\xff\xffgo13ld"
    25  //
    26  // All integers are stored in a zigzag varint format.
    27  // See golang.org/s/go12symtab for a definition.
    28  //
    29  // Data blocks and strings are both stored as an integer
    30  // followed by that many bytes.
    31  //
    32  // A symbol reference is a string name followed by a version.
    33  // An empty name corresponds to a nil LSym* pointer.
    34  //
    35  // Each symbol is laid out as the following fields (taken from LSym*):
    36  //
    37  //	- byte 0xfe (sanity check for synchronization)
    38  //	- type [int]
    39  //	- name [string]
    40  //	- version [int]
    41  //	- flags [int]
    42  //		1 dupok
    43  //	- size [int]
    44  //	- gotype [symbol reference]
    45  //	- p [data block]
    46  //	- nr [int]
    47  //	- r [nr relocations, sorted by off]
    48  //
    49  // If type == STEXT, there are a few more fields:
    50  //
    51  //	- args [int]
    52  //	- locals [int]
    53  //	- nosplit [int]
    54  //	- flags [int]
    55  //		1 leaf
    56  //		2 C function
    57  //	- nlocal [int]
    58  //	- local [nlocal automatics]
    59  //	- pcln [pcln table]
    60  //
    61  // Each relocation has the encoding:
    62  //
    63  //	- off [int]
    64  //	- siz [int]
    65  //	- type [int]
    66  //	- add [int]
    67  //	- xadd [int]
    68  //	- sym [symbol reference]
    69  //	- xsym [symbol reference]
    70  //
    71  // Each local has the encoding:
    72  //
    73  //	- asym [symbol reference]
    74  //	- offset [int]
    75  //	- type [int]
    76  //	- gotype [symbol reference]
    77  //
    78  // The pcln table has the encoding:
    79  //
    80  //	- pcsp [data block]
    81  //	- pcfile [data block]
    82  //	- pcline [data block]
    83  //	- npcdata [int]
    84  //	- pcdata [npcdata data blocks]
    85  //	- nfuncdata [int]
    86  //	- funcdata [nfuncdata symbol references]
    87  //	- funcdatasym [nfuncdata ints]
    88  //	- nfile [int]
    89  //	- file [nfile symbol references]
    90  //
    91  // The file layout and meaning of type integers are architecture-independent.
    92  //
    93  // TODO(rsc): The file format is good for a first pass but needs work.
    94  //	- There are SymID in the object file that should really just be strings.
    95  //	- The actual symbol memory images are interlaced with the symbol
    96  //	  metadata. They should be separated, to reduce the I/O required to
    97  //	  load just the metadata.
    98  //	- The symbol references should be shortened, either with a symbol
    99  //	  table or by using a simple backward index to an earlier mentioned symbol.
   100  
   101  #include <u.h>
   102  #include <libc.h>
   103  #include <bio.h>
   104  #include <link.h>
   105  #include "../cmd/ld/textflag.h"
   106  #include "../runtime/funcdata.h"
   107  
   108  static void writesym(Link*, Biobuf*, LSym*);
   109  static void wrint(Biobuf*, int64);
   110  static void wrstring(Biobuf*, char*);
   111  static void wrpath(Link *, Biobuf*, char*);
   112  static void wrdata(Biobuf*, void*, int);
   113  static void wrsym(Biobuf*, LSym*);
   114  static void wrpathsym(Link *ctxt, Biobuf *b, LSym *s);
   115  
   116  static void readsym(Link*, Biobuf*, char*, char*);
   117  static int64 rdint(Biobuf*);
   118  static char *rdstring(Biobuf*);
   119  static void rddata(Biobuf*, uchar**, int*);
   120  static LSym *rdsym(Link*, Biobuf*, char*);
   121  
   122  // The Go and C compilers, and the assembler, call writeobj to write
   123  // out a Go object file.  The linker does not call this; the linker
   124  // does not write out object files.
   125  void
   126  writeobj(Link *ctxt, Biobuf *b)
   127  {
   128  	int flag, found;
   129  	Hist *h;
   130  	LSym *s, *text, *etext, *curtext, *data, *edata;
   131  	Plist *pl;
   132  	Prog *p, *plink;
   133  	Auto *a;
   134  
   135  	// Build list of symbols, and assign instructions to lists.
   136  	// Ignore ctxt->plist boundaries. There are no guarantees there,
   137  	// and the C compilers and assemblers just use one big list.
   138  	text = nil;
   139  	curtext = nil;
   140  	data = nil;
   141  	etext = nil;
   142  	edata = nil;
   143  	for(pl = ctxt->plist; pl != nil; pl = pl->link) {
   144  		for(p = pl->firstpc; p != nil; p = plink) {
   145  			if(ctxt->debugasm && ctxt->debugvlog)
   146  				print("obj: %p %P\n", p, p);
   147  			plink = p->link;
   148  			p->link = nil;
   149  
   150  			if(p->as == ctxt->arch->AEND)
   151  				continue;
   152  
   153  			if(p->as == ctxt->arch->ATYPE) {
   154  				// Assume each TYPE instruction describes
   155  				// a different local variable or parameter,
   156  				// so no dedup.
   157  				// Using only the TYPE instructions means
   158  				// that we discard location information about local variables
   159  				// in C and assembly functions; that information is inferred
   160  				// from ordinary references, because there are no TYPE
   161  				// instructions there. Without the type information, gdb can't
   162  				// use the locations, so we don't bother to save them.
   163  				// If something else could use them, we could arrange to
   164  				// preserve them.
   165  				if(curtext == nil)
   166  					continue;
   167  				a = emallocz(sizeof *a);
   168  				a->asym = p->from.sym;
   169  				a->aoffset = p->from.offset;
   170  				a->type = ctxt->arch->symtype(&p->from);
   171  				a->gotype = p->from.gotype;
   172  				a->link = curtext->autom;
   173  				curtext->autom = a;
   174  				continue;
   175  			}
   176  
   177  			if(p->as == ctxt->arch->AGLOBL) {
   178  				s = p->from.sym;
   179  				if(s->seenglobl++)
   180  					print("duplicate %P\n", p);
   181  				if(s->onlist)
   182  					sysfatal("symbol %s listed multiple times", s->name);
   183  				s->onlist = 1;
   184  				if(data == nil)
   185  					data = s;
   186  				else
   187  					edata->next = s;
   188  				s->next = nil;
   189  				s->size = p->to.offset;
   190  				if(s->type == 0 || s->type == SXREF)
   191  					s->type = SBSS;
   192  				flag = ctxt->arch->textflag(p);
   193  				if(flag & DUPOK)
   194  					s->dupok = 1;
   195  				if(flag & RODATA)
   196  					s->type = SRODATA;
   197  				else if(flag & NOPTR)
   198  					s->type = SNOPTRBSS;
   199  				edata = s;
   200  				continue;
   201  			}
   202  
   203  			if(p->as == ctxt->arch->ADATA) {
   204  				savedata(ctxt, p->from.sym, p, "<input>");
   205  				continue;
   206  			}
   207  
   208  			if(p->as == ctxt->arch->ATEXT) {
   209  				s = p->from.sym;
   210  				if(s == nil) {
   211  					// func _() { }
   212  					curtext = nil;
   213  					continue;
   214  				}
   215  				if(s->text != nil)
   216  					sysfatal("duplicate TEXT for %s", s->name);
   217  				if(s->onlist)
   218  					sysfatal("symbol %s listed multiple times", s->name);
   219  				s->onlist = 1;
   220  				if(text == nil)
   221  					text = s;
   222  				else
   223  					etext->next = s;
   224  				etext = s;
   225  				flag = ctxt->arch->textflag(p);
   226  				if(flag & DUPOK)
   227  					s->dupok = 1;
   228  				if(flag & NOSPLIT)
   229  					s->nosplit = 1;
   230  				s->next = nil;
   231  				s->type = STEXT;
   232  				s->text = p;
   233  				s->etext = p;
   234  				curtext = s;
   235  				continue;
   236  			}
   237  			
   238  			if(p->as == ctxt->arch->AFUNCDATA) {
   239  				// Rewrite reference to go_args_stackmap(SB) to the Go-provided declaration information.
   240  				if(curtext == nil) // func _() {}
   241  					continue;
   242  				if(strcmp(p->to.sym->name, "go_args_stackmap") == 0) {
   243  					if(p->from.type != ctxt->arch->D_CONST || p->from.offset != FUNCDATA_ArgsPointerMaps)
   244  						ctxt->diag("FUNCDATA use of go_args_stackmap(SB) without FUNCDATA_ArgsPointerMaps");
   245  					p->to.sym = linklookup(ctxt, smprint("%s.args_stackmap", curtext->name), curtext->version);
   246  				}
   247  			}
   248  			
   249  			if(curtext == nil)
   250  				continue;
   251  			s = curtext;
   252  			s->etext->link = p;
   253  			s->etext = p;
   254  		}
   255  	}
   256  	
   257  	// Add reference to Go arguments for C or assembly functions without them.
   258  	for(s = text; s != nil; s = s->next) {
   259  		if(strncmp(s->name, "\"\".", 3) != 0)
   260  			continue;
   261  		found = 0;
   262  		for(p = s->text; p != nil; p = p->link) {
   263  			if(p->as == ctxt->arch->AFUNCDATA && p->from.type == ctxt->arch->D_CONST && p->from.offset == FUNCDATA_ArgsPointerMaps) {
   264  				found = 1;
   265  				break;
   266  			}
   267  		}
   268  		if(!found) {
   269  			p = appendp(ctxt, s->text);
   270  			p->as = ctxt->arch->AFUNCDATA;
   271  			p->from.type = ctxt->arch->D_CONST;
   272  			p->from.offset = FUNCDATA_ArgsPointerMaps;
   273  			if(ctxt->arch->thechar == '6' || ctxt->arch->thechar == '8')
   274  				p->to.type = ctxt->arch->D_EXTERN;
   275  			else {
   276  				p->to.type = ctxt->arch->D_OREG;
   277  				p->to.name = ctxt->arch->D_EXTERN;
   278  			}
   279  			p->to.sym = linklookup(ctxt, smprint("%s.args_stackmap", s->name), s->version);
   280  		}
   281  	}
   282  
   283  	// Turn functions into machine code images.
   284  	for(s = text; s != nil; s = s->next) {
   285  		mkfwd(s);
   286  		linkpatch(ctxt, s);
   287  		ctxt->arch->follow(ctxt, s);
   288  		ctxt->arch->addstacksplit(ctxt, s);
   289  		ctxt->arch->assemble(ctxt, s);
   290  		linkpcln(ctxt, s);
   291  	}
   292  
   293  	// Emit header.
   294  	Bputc(b, 0);
   295  	Bputc(b, 0);
   296  	Bprint(b, "go13ld");
   297  	Bputc(b, 1); // version
   298  
   299  	// Emit autolib.
   300  	for(h = ctxt->hist; h != nil; h = h->link)
   301  		if(h->offset < 0)
   302  			wrstring(b, h->name);
   303  	wrstring(b, "");
   304  
   305  	// Emit symbols.
   306  	for(s = text; s != nil; s = s->next)
   307  		writesym(ctxt, b, s);
   308  	for(s = data; s != nil; s = s->next)
   309  		writesym(ctxt, b, s);
   310  
   311  	// Emit footer.
   312  	Bputc(b, 0xff);
   313  	Bputc(b, 0xff);
   314  	Bprint(b, "go13ld");
   315  }
   316  
   317  static void
   318  writesym(Link *ctxt, Biobuf *b, LSym *s)
   319  {
   320  	Reloc *r;
   321  	int i, j, c, n;
   322  	Pcln *pc;
   323  	Prog *p;
   324  	Auto *a;
   325  	char *name;
   326  
   327  	if(ctxt->debugasm) {
   328  		Bprint(ctxt->bso, "%s ", s->name);
   329  		if(s->version)
   330  			Bprint(ctxt->bso, "v=%d ", s->version);
   331  		if(s->type)
   332  			Bprint(ctxt->bso, "t=%d ", s->type);
   333  		if(s->dupok)
   334  			Bprint(ctxt->bso, "dupok ");
   335  		if(s->cfunc)
   336  			Bprint(ctxt->bso, "cfunc ");
   337  		if(s->nosplit)
   338  			Bprint(ctxt->bso, "nosplit ");
   339  		Bprint(ctxt->bso, "size=%lld value=%lld", (vlong)s->size, (vlong)s->value);
   340  		if(s->type == STEXT) {
   341  			Bprint(ctxt->bso, " args=%#llux locals=%#llux", (uvlong)s->args, (uvlong)s->locals);
   342  			if(s->leaf)
   343  				Bprint(ctxt->bso, " leaf");
   344  		}
   345  		Bprint(ctxt->bso, "\n");
   346  		for(p=s->text; p != nil; p = p->link)
   347  			Bprint(ctxt->bso, "\t%#06ux %P\n", (int)p->pc, p);
   348  		for(i=0; i<s->np; ) {
   349  			Bprint(ctxt->bso, "\t%#06ux", i);
   350  			for(j=i; j<i+16 && j<s->np; j++)
   351  				Bprint(ctxt->bso, " %02ux", s->p[j]);
   352  			for(; j<i+16; j++)
   353  				Bprint(ctxt->bso, "   ");
   354  			Bprint(ctxt->bso, "  ");
   355  			for(j=i; j<i+16 && j<s->np; j++) {
   356  				c = s->p[j];
   357  				if(' ' <= c && c <= 0x7e)
   358  					Bprint(ctxt->bso, "%c", c);
   359  				else
   360  					Bprint(ctxt->bso, ".");
   361  			}
   362  			Bprint(ctxt->bso, "\n");
   363  			i += 16;
   364  		}
   365  		for(i=0; i<s->nr; i++) {
   366  			r = &s->r[i];
   367  			name = "";
   368  			if(r->sym != nil)
   369  				name = r->sym->name;
   370  			if(ctxt->arch->thechar == '5' || ctxt->arch->thechar == '9')
   371  				Bprint(ctxt->bso, "\trel %d+%d t=%d %s+%llux\n", (int)r->off, r->siz, r->type, name, (vlong)r->add);
   372  			else
   373  				Bprint(ctxt->bso, "\trel %d+%d t=%d %s+%lld\n", (int)r->off, r->siz, r->type, name, (vlong)r->add);
   374  		}
   375  	}
   376  
   377  	Bputc(b, 0xfe);
   378  	wrint(b, s->type);
   379  	wrstring(b, s->name);
   380  	wrint(b, s->version);
   381  	wrint(b, s->dupok);
   382  	wrint(b, s->size);
   383  	wrsym(b, s->gotype);
   384  	wrdata(b, s->p, s->np);
   385  
   386  	wrint(b, s->nr);
   387  	for(i=0; i<s->nr; i++) {
   388  		r = &s->r[i];
   389  		wrint(b, r->off);
   390  		wrint(b, r->siz);
   391  		wrint(b, r->type);
   392  		wrint(b, r->add);
   393  		wrint(b, r->xadd);
   394  		wrsym(b, r->sym);
   395  		wrsym(b, r->xsym);
   396  	}
   397  	
   398  	if(s->type == STEXT) {
   399  		wrint(b, s->args);
   400  		wrint(b, s->locals);
   401  		wrint(b, s->nosplit);
   402  		wrint(b, s->leaf | s->cfunc<<1);
   403  		n = 0;
   404  		for(a = s->autom; a != nil; a = a->link)
   405  			n++;
   406  		wrint(b, n);
   407  		for(a = s->autom; a != nil; a = a->link) {
   408  			wrsym(b, a->asym);
   409  			wrint(b, a->aoffset);
   410  			if(a->type == ctxt->arch->D_AUTO)
   411  				wrint(b, A_AUTO);
   412  			else if(a->type == ctxt->arch->D_PARAM)
   413  				wrint(b, A_PARAM);
   414  			else
   415  				sysfatal("%s: invalid local variable type %d", s->name, a->type);
   416  			wrsym(b, a->gotype);
   417  		}
   418  
   419  		pc = s->pcln;
   420  		wrdata(b, pc->pcsp.p, pc->pcsp.n);
   421  		wrdata(b, pc->pcfile.p, pc->pcfile.n);
   422  		wrdata(b, pc->pcline.p, pc->pcline.n);
   423  		wrint(b, pc->npcdata);
   424  		for(i=0; i<pc->npcdata; i++)
   425  			wrdata(b, pc->pcdata[i].p, pc->pcdata[i].n);
   426  		wrint(b, pc->nfuncdata);
   427  		for(i=0; i<pc->nfuncdata; i++)
   428  			wrsym(b, pc->funcdata[i]);
   429  		for(i=0; i<pc->nfuncdata; i++)
   430  			wrint(b, pc->funcdataoff[i]);
   431  		wrint(b, pc->nfile);
   432  		for(i=0; i<pc->nfile; i++)
   433  			wrpathsym(ctxt, b, pc->file[i]);
   434  	}
   435  }
   436  
   437  static void
   438  wrint(Biobuf *b, int64 sval)
   439  {
   440  	uint64 uv, v;
   441  	uchar buf[10], *p;
   442  
   443  	uv = ((uint64)sval<<1) ^ (uint64)(int64)(sval>>63);
   444  
   445  	p = buf;
   446  	for(v = uv; v >= 0x80; v >>= 7)
   447  		*p++ = v | 0x80;
   448  	*p++ = v;
   449  	
   450  	Bwrite(b, buf, p - buf);
   451  }
   452  
   453  static void
   454  wrstring(Biobuf *b, char *s)
   455  {
   456  	wrdata(b, s, strlen(s));
   457  }
   458  
   459  // wrpath writes a path just like a string, but on windows, it
   460  // translates '\\' to '/' in the process.
   461  static void
   462  wrpath(Link *ctxt, Biobuf *b, char *p)
   463  {
   464  	int i, n;
   465  	if (!ctxt->windows || strchr(p, '\\') == nil) {
   466  		wrstring(b, p);
   467  		return;
   468  	} else {
   469  		n = strlen(p);
   470  		wrint(b, n);
   471  		for (i = 0; i < n; i++)
   472  			Bputc(b, p[i] == '\\' ? '/' : p[i]);
   473  	}
   474  }
   475  
   476  static void
   477  wrdata(Biobuf *b, void *v, int n)
   478  {
   479  	wrint(b, n);
   480  	Bwrite(b, v, n);
   481  }
   482  
   483  static void
   484  wrpathsym(Link *ctxt, Biobuf *b, LSym *s)
   485  {
   486  	if(s == nil) {
   487  		wrint(b, 0);
   488  		wrint(b, 0);
   489  		return;
   490  	}
   491  	wrpath(ctxt, b, s->name);
   492  	wrint(b, s->version);
   493  }
   494  
   495  static void
   496  wrsym(Biobuf *b, LSym *s)
   497  {
   498  	if(s == nil) {
   499  		wrint(b, 0);
   500  		wrint(b, 0);
   501  		return;
   502  	}
   503  	wrstring(b, s->name);
   504  	wrint(b, s->version);
   505  }
   506  
   507  static char startmagic[] = "\x00\x00go13ld";
   508  static char endmagic[] = "\xff\xffgo13ld";
   509  
   510  void
   511  ldobjfile(Link *ctxt, Biobuf *f, char *pkg, int64 len, char *pn)
   512  {
   513  	int c;
   514  	uchar buf[8];
   515  	int64 start;
   516  	char *lib;
   517  
   518  	start = Boffset(f);
   519  	ctxt->version++;
   520  	memset(buf, 0, sizeof buf);
   521  	Bread(f, buf, sizeof buf);
   522  	if(memcmp(buf, startmagic, sizeof buf) != 0)
   523  		sysfatal("%s: invalid file start %x %x %x %x %x %x %x %x", pn, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]);
   524  	if((c = Bgetc(f)) != 1)
   525  		sysfatal("%s: invalid file version number %d", pn, c);
   526  
   527  	for(;;) {
   528  		lib = rdstring(f);
   529  		if(lib[0] == 0)
   530  			break;
   531  		addlib(ctxt, pkg, pn, lib);
   532  	}
   533  	
   534  	for(;;) {
   535  		c = Bgetc(f);
   536  		Bungetc(f);
   537  		if(c == 0xff)
   538  			break;
   539  		readsym(ctxt, f, pkg, pn);
   540  	}
   541  	
   542  	memset(buf, 0, sizeof buf);
   543  	Bread(f, buf, sizeof buf);
   544  	if(memcmp(buf, endmagic, sizeof buf) != 0)
   545  		sysfatal("%s: invalid file end", pn);
   546  	
   547  	if(Boffset(f) != start+len)
   548  		sysfatal("%s: unexpected end at %lld, want %lld", pn, (vlong)Boffset(f), (vlong)(start+len));
   549  }
   550  
   551  static void
   552  readsym(Link *ctxt, Biobuf *f, char *pkg, char *pn)
   553  {
   554  	int i, j, c, t, v, n, ndata, nreloc, size, dupok;
   555  	static int ndup;
   556  	char *name;
   557  	uchar *data;
   558  	Reloc *r;
   559  	LSym *s, *dup, *typ;
   560  	Pcln *pc;
   561  	Auto *a;
   562  	
   563  	if(Bgetc(f) != 0xfe)
   564  		sysfatal("readsym out of sync");
   565  	t = rdint(f);
   566  	name = expandpkg(rdstring(f), pkg);
   567  	v = rdint(f);
   568  	if(v != 0 && v != 1)
   569  		sysfatal("invalid symbol version %d", v);
   570  	dupok = rdint(f);
   571  	dupok &= 1;
   572  	size = rdint(f);
   573  	typ = rdsym(ctxt, f, pkg);
   574  	rddata(f, &data, &ndata);
   575  	nreloc = rdint(f);
   576  	
   577  	if(v != 0)
   578  		v = ctxt->version;
   579  	s = linklookup(ctxt, name, v);
   580  	dup = nil;
   581  	if(s->type != 0 && s->type != SXREF) {
   582  		if((t == SDATA || t == SBSS || t == SNOPTRBSS) && ndata == 0 && nreloc == 0) {
   583  			if(s->size < size)
   584  				s->size = size;
   585  			if(typ != nil && s->gotype == nil)
   586  				s->gotype = typ;
   587  			return;
   588  		}
   589  		if((s->type == SDATA || s->type == SBSS || s->type == SNOPTRBSS) && s->np == 0 && s->nr == 0)
   590  			goto overwrite;
   591  		if(s->type != SBSS && s->type != SNOPTRBSS && !dupok && !s->dupok)
   592  			sysfatal("duplicate symbol %s (types %d and %d) in %s and %s", s->name, s->type, t, s->file, pn);
   593  		if(s->np > 0) {
   594  			dup = s;
   595  			s = linknewsym(ctxt, ".dup", ndup++); // scratch
   596  		}
   597  	}
   598  overwrite:
   599  	s->file = pkg;
   600  	s->dupok = dupok;
   601  	if(t == SXREF)
   602  		sysfatal("bad sxref");
   603  	if(t == 0)
   604  		sysfatal("missing type for %s in %s", name, pn);
   605  	if(t == SBSS && (s->type == SRODATA || s->type == SNOPTRBSS))
   606  		t = s->type;
   607  	s->type = t;
   608  	if(s->size < size)
   609  		s->size = size;
   610  	if(typ != nil) // if bss sym defined multiple times, take type from any one def
   611  		s->gotype = typ;
   612  	if(dup != nil && typ != nil)
   613  		dup->gotype = typ;
   614  	s->p = data;
   615  	s->np = ndata;
   616  	s->maxp = s->np;
   617  	if(nreloc > 0) {
   618  		s->r = emallocz(nreloc * sizeof s->r[0]);
   619  		s->nr = nreloc;
   620  		s->maxr = nreloc;
   621  		for(i=0; i<nreloc; i++) {
   622  			r = &s->r[i];
   623  			r->off = rdint(f);
   624  			r->siz = rdint(f);
   625  			r->type = rdint(f);
   626  			r->add = rdint(f);
   627  			r->xadd = rdint(f);
   628  			r->sym = rdsym(ctxt, f, pkg);
   629  			r->xsym = rdsym(ctxt, f, pkg);
   630  		}
   631  	}
   632  	
   633  	if(s->np > 0 && dup != nil && dup->np > 0 && strncmp(s->name, "gclocals·", 10) == 0) {
   634  		// content-addressed garbage collection liveness bitmap symbol.
   635  		// double check for hash collisions.
   636  		if(s->np != dup->np || memcmp(s->p, dup->p, s->np) != 0)
   637  			sysfatal("dupok hash collision for %s in %s and %s", s->name, s->file, pn);
   638  	}
   639  	
   640  	if(s->type == STEXT) {
   641  		s->args = rdint(f);
   642  		s->locals = rdint(f);
   643  		s->nosplit = rdint(f);
   644  		v = rdint(f);
   645  		s->leaf = v&1;
   646  		s->cfunc = v&2;
   647  		n = rdint(f);
   648  		for(i=0; i<n; i++) {
   649  			a = emallocz(sizeof *a);
   650  			a->asym = rdsym(ctxt, f, pkg);
   651  			a->aoffset = rdint(f);
   652  			a->type = rdint(f);
   653  			a->gotype = rdsym(ctxt, f, pkg);
   654  			a->link = s->autom;
   655  			s->autom = a;
   656  		}
   657  
   658  		s->pcln = emallocz(sizeof *s->pcln);
   659  		pc = s->pcln;
   660  		rddata(f, &pc->pcsp.p, &pc->pcsp.n);
   661  		rddata(f, &pc->pcfile.p, &pc->pcfile.n);
   662  		rddata(f, &pc->pcline.p, &pc->pcline.n);
   663  		n = rdint(f);
   664  		pc->pcdata = emallocz(n * sizeof pc->pcdata[0]);
   665  		pc->npcdata = n;
   666  		for(i=0; i<n; i++)
   667  			rddata(f, &pc->pcdata[i].p, &pc->pcdata[i].n);
   668  		n = rdint(f);
   669  		pc->funcdata = emallocz(n * sizeof pc->funcdata[0]);
   670  		pc->funcdataoff = emallocz(n * sizeof pc->funcdataoff[0]);
   671  		pc->nfuncdata = n;
   672  		for(i=0; i<n; i++)
   673  			pc->funcdata[i] = rdsym(ctxt, f, pkg);
   674  		for(i=0; i<n; i++)
   675  			pc->funcdataoff[i] = rdint(f);
   676  		n = rdint(f);
   677  		pc->file = emallocz(n * sizeof pc->file[0]);
   678  		pc->nfile = n;
   679  		for(i=0; i<n; i++)
   680  			pc->file[i] = rdsym(ctxt, f, pkg);
   681  
   682  		if(dup == nil) {
   683  			if(s->onlist)
   684  				sysfatal("symbol %s listed multiple times", s->name);
   685  			s->onlist = 1;
   686  			if(ctxt->etextp)
   687  				ctxt->etextp->next = s;
   688  			else
   689  				ctxt->textp = s;
   690  			ctxt->etextp = s;
   691  		}
   692  	}
   693  
   694  	if(ctxt->debugasm) {
   695  		Bprint(ctxt->bso, "%s ", s->name);
   696  		if(s->version)
   697  			Bprint(ctxt->bso, "v=%d ", s->version);
   698  		if(s->type)
   699  			Bprint(ctxt->bso, "t=%d ", s->type);
   700  		if(s->dupok)
   701  			Bprint(ctxt->bso, "dupok ");
   702  		if(s->cfunc)
   703  			Bprint(ctxt->bso, "cfunc ");
   704  		if(s->nosplit)
   705  			Bprint(ctxt->bso, "nosplit ");
   706  		Bprint(ctxt->bso, "size=%lld value=%lld", (vlong)s->size, (vlong)s->value);
   707  		if(s->type == STEXT)
   708  			Bprint(ctxt->bso, " args=%#llux locals=%#llux", (uvlong)s->args, (uvlong)s->locals);
   709  		Bprint(ctxt->bso, "\n");
   710  		for(i=0; i<s->np; ) {
   711  			Bprint(ctxt->bso, "\t%#06ux", i);
   712  			for(j=i; j<i+16 && j<s->np; j++)
   713  				Bprint(ctxt->bso, " %02ux", s->p[j]);
   714  			for(; j<i+16; j++)
   715  				Bprint(ctxt->bso, "   ");
   716  			Bprint(ctxt->bso, "  ");
   717  			for(j=i; j<i+16 && j<s->np; j++) {
   718  				c = s->p[j];
   719  				if(' ' <= c && c <= 0x7e)
   720  					Bprint(ctxt->bso, "%c", c);
   721  				else
   722  					Bprint(ctxt->bso, ".");
   723  			}
   724  			Bprint(ctxt->bso, "\n");
   725  			i += 16;
   726  		}
   727  		for(i=0; i<s->nr; i++) {
   728  			r = &s->r[i];
   729  			Bprint(ctxt->bso, "\trel %d+%d t=%d %s+%lld\n", (int)r->off, r->siz, r->type, r->sym->name, (vlong)r->add);
   730  		}
   731  	}
   732  }
   733  
   734  static int64
   735  rdint(Biobuf *f)
   736  {
   737  	int c;
   738  	uint64 uv;
   739  	int shift;
   740  	
   741  	uv = 0;
   742  	for(shift = 0;; shift += 7) {
   743  		if(shift >= 64)
   744  			sysfatal("corrupt input");
   745  		c = Bgetc(f);
   746  		uv |= (uint64)(c & 0x7F) << shift;
   747  		if(!(c & 0x80))
   748  			break;
   749  	}
   750  
   751  	return (int64)(uv>>1) ^ ((int64)((uint64)uv<<63)>>63);
   752  }
   753  
   754  static char*
   755  rdstring(Biobuf *f)
   756  {
   757  	int n;
   758  	char *p;
   759  	
   760  	n = rdint(f);
   761  	p = emallocz(n+1);
   762  	Bread(f, p, n);
   763  	return p;
   764  }
   765  
   766  static void
   767  rddata(Biobuf *f, uchar **pp, int *np)
   768  {
   769  	*np = rdint(f);
   770  	*pp = emallocz(*np);
   771  	Bread(f, *pp, *np);
   772  }
   773  
   774  static LSym*
   775  rdsym(Link *ctxt, Biobuf *f, char *pkg)
   776  {
   777  	int n, v;
   778  	char *p;
   779  	LSym *s;
   780  	
   781  	n = rdint(f);
   782  	if(n == 0) {
   783  		rdint(f);
   784  		return nil;
   785  	}
   786  	p = emallocz(n+1);
   787  	Bread(f, p, n);
   788  	v = rdint(f);
   789  	if(v != 0)
   790  		v = ctxt->version;
   791  	s = linklookup(ctxt, expandpkg(p, pkg), v);
   792  	
   793  	if(v == 0 && s->name[0] == '$' && s->type == 0) {
   794  		if(strncmp(s->name, "$f32.", 5) == 0) {
   795  			int32 i32;
   796  			i32 = strtoul(s->name+5, nil, 16);
   797  			s->type = SRODATA;
   798  			adduint32(ctxt, s, i32);
   799  			s->reachable = 0;
   800  		} else if(strncmp(s->name, "$f64.", 5) == 0 || strncmp(s->name, "$i64.", 5) == 0) {
   801  			int64 i64;
   802  			i64 = strtoull(s->name+5, nil, 16);
   803  			s->type = SRODATA;
   804  			adduint64(ctxt, s, i64);
   805  			s->reachable = 0;
   806  		}
   807  	}
   808  
   809  	return s;
   810  }