github.com/hongwozai/go-src-1.4.3@v0.0.0-20191127132709-dc3fce3dbccb/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  			plink = p->link;
   146  			p->link = nil;
   147  
   148  			if(p->as == ctxt->arch->AEND)
   149  				continue;
   150  
   151  			if(p->as == ctxt->arch->ATYPE) {
   152  				// Assume each TYPE instruction describes
   153  				// a different local variable or parameter,
   154  				// so no dedup.
   155  				// Using only the TYPE instructions means
   156  				// that we discard location information about local variables
   157  				// in C and assembly functions; that information is inferred
   158  				// from ordinary references, because there are no TYPE
   159  				// instructions there. Without the type information, gdb can't
   160  				// use the locations, so we don't bother to save them.
   161  				// If something else could use them, we could arrange to
   162  				// preserve them.
   163  				if(curtext == nil)
   164  					continue;
   165  				a = emallocz(sizeof *a);
   166  				a->asym = p->from.sym;
   167  				a->aoffset = p->from.offset;
   168  				a->type = ctxt->arch->symtype(&p->from);
   169  				a->gotype = p->from.gotype;
   170  				a->link = curtext->autom;
   171  				curtext->autom = a;
   172  				continue;
   173  			}
   174  
   175  			if(p->as == ctxt->arch->AGLOBL) {
   176  				s = p->from.sym;
   177  				if(s->seenglobl++)
   178  					print("duplicate %P\n", p);
   179  				if(s->onlist)
   180  					sysfatal("symbol %s listed multiple times", s->name);
   181  				s->onlist = 1;
   182  				if(data == nil)
   183  					data = s;
   184  				else
   185  					edata->next = s;
   186  				s->next = nil;
   187  				s->size = p->to.offset;
   188  				if(s->type == 0 || s->type == SXREF)
   189  					s->type = SBSS;
   190  				flag = ctxt->arch->textflag(p);
   191  				if(flag & DUPOK)
   192  					s->dupok = 1;
   193  				if(flag & RODATA)
   194  					s->type = SRODATA;
   195  				else if(flag & NOPTR)
   196  					s->type = SNOPTRBSS;
   197  				edata = s;
   198  				continue;
   199  			}
   200  
   201  			if(p->as == ctxt->arch->ADATA) {
   202  				savedata(ctxt, p->from.sym, p, "<input>");
   203  				continue;
   204  			}
   205  
   206  			if(p->as == ctxt->arch->ATEXT) {
   207  				s = p->from.sym;
   208  				if(s == nil) {
   209  					// func _() { }
   210  					curtext = nil;
   211  					continue;
   212  				}
   213  				if(s->text != nil)
   214  					sysfatal("duplicate TEXT for %s", s->name);
   215  				if(s->onlist)
   216  					sysfatal("symbol %s listed multiple times", s->name);
   217  				s->onlist = 1;
   218  				if(text == nil)
   219  					text = s;
   220  				else
   221  					etext->next = s;
   222  				etext = s;
   223  				flag = ctxt->arch->textflag(p);
   224  				if(flag & DUPOK)
   225  					s->dupok = 1;
   226  				if(flag & NOSPLIT)
   227  					s->nosplit = 1;
   228  				s->next = nil;
   229  				s->type = STEXT;
   230  				s->text = p;
   231  				s->etext = p;
   232  				curtext = s;
   233  				continue;
   234  			}
   235  			
   236  			if(p->as == ctxt->arch->AFUNCDATA) {
   237  				// Rewrite reference to go_args_stackmap(SB) to the Go-provided declaration information.
   238  				if(curtext == nil) // func _() {}
   239  					continue;
   240  				if(strcmp(p->to.sym->name, "go_args_stackmap") == 0) {
   241  					if(p->from.type != ctxt->arch->D_CONST || p->from.offset != FUNCDATA_ArgsPointerMaps)
   242  						ctxt->diag("FUNCDATA use of go_args_stackmap(SB) without FUNCDATA_ArgsPointerMaps");
   243  					p->to.sym = linklookup(ctxt, smprint("%s.args_stackmap", curtext->name), curtext->version);
   244  				}
   245  			}
   246  			
   247  			if(curtext == nil)
   248  				continue;
   249  			s = curtext;
   250  			s->etext->link = p;
   251  			s->etext = p;
   252  		}
   253  	}
   254  	
   255  	// Add reference to Go arguments for C or assembly functions without them.
   256  	for(s = text; s != nil; s = s->next) {
   257  		if(strncmp(s->name, "\"\".", 3) != 0)
   258  			continue;
   259  		found = 0;
   260  		for(p = s->text; p != nil; p = p->link) {
   261  			if(p->as == ctxt->arch->AFUNCDATA && p->from.type == ctxt->arch->D_CONST && p->from.offset == FUNCDATA_ArgsPointerMaps) {
   262  				found = 1;
   263  				break;
   264  			}
   265  		}
   266  		if(!found) {
   267  			p = appendp(ctxt, s->text);
   268  			p->as = ctxt->arch->AFUNCDATA;
   269  			p->from.type = ctxt->arch->D_CONST;
   270  			p->from.offset = FUNCDATA_ArgsPointerMaps;
   271  			if(ctxt->arch->thechar == '6' || ctxt->arch->thechar == '8')
   272  				p->to.type = ctxt->arch->D_EXTERN;
   273  			else {
   274  				p->to.type = ctxt->arch->D_OREG;
   275  				p->to.name = ctxt->arch->D_EXTERN;
   276  			}
   277  			p->to.sym = linklookup(ctxt, smprint("%s.args_stackmap", s->name), s->version);
   278  		}
   279  	}
   280  
   281  	// Turn functions into machine code images.
   282  	for(s = text; s != nil; s = s->next) {
   283  		mkfwd(s);
   284  		linkpatch(ctxt, s);
   285  		ctxt->arch->follow(ctxt, s);
   286  		ctxt->arch->addstacksplit(ctxt, s);
   287  		ctxt->arch->assemble(ctxt, s);
   288  		linkpcln(ctxt, s);
   289  	}
   290  
   291  	// Emit header.
   292  	Bputc(b, 0);
   293  	Bputc(b, 0);
   294  	Bprint(b, "go13ld");
   295  	Bputc(b, 1); // version
   296  
   297  	// Emit autolib.
   298  	for(h = ctxt->hist; h != nil; h = h->link)
   299  		if(h->offset < 0)
   300  			wrstring(b, h->name);
   301  	wrstring(b, "");
   302  
   303  	// Emit symbols.
   304  	for(s = text; s != nil; s = s->next)
   305  		writesym(ctxt, b, s);
   306  	for(s = data; s != nil; s = s->next)
   307  		writesym(ctxt, b, s);
   308  
   309  	// Emit footer.
   310  	Bputc(b, 0xff);
   311  	Bputc(b, 0xff);
   312  	Bprint(b, "go13ld");
   313  }
   314  
   315  static void
   316  writesym(Link *ctxt, Biobuf *b, LSym *s)
   317  {
   318  	Reloc *r;
   319  	int i, j, c, n;
   320  	Pcln *pc;
   321  	Prog *p;
   322  	Auto *a;
   323  	char *name;
   324  
   325  	if(ctxt->debugasm) {
   326  		Bprint(ctxt->bso, "%s ", s->name);
   327  		if(s->version)
   328  			Bprint(ctxt->bso, "v=%d ", s->version);
   329  		if(s->type)
   330  			Bprint(ctxt->bso, "t=%d ", s->type);
   331  		if(s->dupok)
   332  			Bprint(ctxt->bso, "dupok ");
   333  		if(s->cfunc)
   334  			Bprint(ctxt->bso, "cfunc ");
   335  		if(s->nosplit)
   336  			Bprint(ctxt->bso, "nosplit ");
   337  		Bprint(ctxt->bso, "size=%lld value=%lld", (vlong)s->size, (vlong)s->value);
   338  		if(s->type == STEXT) {
   339  			Bprint(ctxt->bso, " args=%#llux locals=%#llux", (uvlong)s->args, (uvlong)s->locals);
   340  			if(s->leaf)
   341  				Bprint(ctxt->bso, " leaf");
   342  		}
   343  		Bprint(ctxt->bso, "\n");
   344  		for(p=s->text; p != nil; p = p->link)
   345  			Bprint(ctxt->bso, "\t%#06ux %P\n", (int)p->pc, p);
   346  		for(i=0; i<s->np; ) {
   347  			Bprint(ctxt->bso, "\t%#06ux", i);
   348  			for(j=i; j<i+16 && j<s->np; j++)
   349  				Bprint(ctxt->bso, " %02ux", s->p[j]);
   350  			for(; j<i+16; j++)
   351  				Bprint(ctxt->bso, "   ");
   352  			Bprint(ctxt->bso, "  ");
   353  			for(j=i; j<i+16 && j<s->np; j++) {
   354  				c = s->p[j];
   355  				if(' ' <= c && c <= 0x7e)
   356  					Bprint(ctxt->bso, "%c", c);
   357  				else
   358  					Bprint(ctxt->bso, ".");
   359  			}
   360  			Bprint(ctxt->bso, "\n");
   361  			i += 16;
   362  		}
   363  		for(i=0; i<s->nr; i++) {
   364  			r = &s->r[i];
   365  			name = "";
   366  			if(r->sym != nil)
   367  				name = r->sym->name;
   368  			Bprint(ctxt->bso, "\trel %d+%d t=%d %s+%lld\n", (int)r->off, r->siz, r->type, name, (vlong)r->add);
   369  		}
   370  	}
   371  
   372  	Bputc(b, 0xfe);
   373  	wrint(b, s->type);
   374  	wrstring(b, s->name);
   375  	wrint(b, s->version);
   376  	wrint(b, s->dupok);
   377  	wrint(b, s->size);
   378  	wrsym(b, s->gotype);
   379  	wrdata(b, s->p, s->np);
   380  
   381  	wrint(b, s->nr);
   382  	for(i=0; i<s->nr; i++) {
   383  		r = &s->r[i];
   384  		wrint(b, r->off);
   385  		wrint(b, r->siz);
   386  		wrint(b, r->type);
   387  		wrint(b, r->add);
   388  		wrint(b, r->xadd);
   389  		wrsym(b, r->sym);
   390  		wrsym(b, r->xsym);
   391  	}
   392  	
   393  	if(s->type == STEXT) {
   394  		wrint(b, s->args);
   395  		wrint(b, s->locals);
   396  		wrint(b, s->nosplit);
   397  		wrint(b, s->leaf | s->cfunc<<1);
   398  		n = 0;
   399  		for(a = s->autom; a != nil; a = a->link)
   400  			n++;
   401  		wrint(b, n);
   402  		for(a = s->autom; a != nil; a = a->link) {
   403  			wrsym(b, a->asym);
   404  			wrint(b, a->aoffset);
   405  			if(a->type == ctxt->arch->D_AUTO)
   406  				wrint(b, A_AUTO);
   407  			else if(a->type == ctxt->arch->D_PARAM)
   408  				wrint(b, A_PARAM);
   409  			else
   410  				sysfatal("%s: invalid local variable type %d", s->name, a->type);
   411  			wrsym(b, a->gotype);
   412  		}
   413  
   414  		pc = s->pcln;
   415  		wrdata(b, pc->pcsp.p, pc->pcsp.n);
   416  		wrdata(b, pc->pcfile.p, pc->pcfile.n);
   417  		wrdata(b, pc->pcline.p, pc->pcline.n);
   418  		wrint(b, pc->npcdata);
   419  		for(i=0; i<pc->npcdata; i++)
   420  			wrdata(b, pc->pcdata[i].p, pc->pcdata[i].n);
   421  		wrint(b, pc->nfuncdata);
   422  		for(i=0; i<pc->nfuncdata; i++)
   423  			wrsym(b, pc->funcdata[i]);
   424  		for(i=0; i<pc->nfuncdata; i++)
   425  			wrint(b, pc->funcdataoff[i]);
   426  		wrint(b, pc->nfile);
   427  		for(i=0; i<pc->nfile; i++)
   428  			wrpathsym(ctxt, b, pc->file[i]);
   429  	}
   430  }
   431  
   432  static void
   433  wrint(Biobuf *b, int64 sval)
   434  {
   435  	uint64 uv, v;
   436  	uchar buf[10], *p;
   437  
   438  	uv = ((uint64)sval<<1) ^ (uint64)(int64)(sval>>63);
   439  
   440  	p = buf;
   441  	for(v = uv; v >= 0x80; v >>= 7)
   442  		*p++ = v | 0x80;
   443  	*p++ = v;
   444  	
   445  	Bwrite(b, buf, p - buf);
   446  }
   447  
   448  static void
   449  wrstring(Biobuf *b, char *s)
   450  {
   451  	wrdata(b, s, strlen(s));
   452  }
   453  
   454  // wrpath writes a path just like a string, but on windows, it
   455  // translates '\\' to '/' in the process.
   456  static void
   457  wrpath(Link *ctxt, Biobuf *b, char *p)
   458  {
   459  	int i, n;
   460  	if (!ctxt->windows || strchr(p, '\\') == nil) {
   461  		wrstring(b, p);
   462  		return;
   463  	} else {
   464  		n = strlen(p);
   465  		wrint(b, n);
   466  		for (i = 0; i < n; i++)
   467  			Bputc(b, p[i] == '\\' ? '/' : p[i]);
   468  	}
   469  }
   470  
   471  static void
   472  wrdata(Biobuf *b, void *v, int n)
   473  {
   474  	wrint(b, n);
   475  	Bwrite(b, v, n);
   476  }
   477  
   478  static void
   479  wrpathsym(Link *ctxt, Biobuf *b, LSym *s)
   480  {
   481  	if(s == nil) {
   482  		wrint(b, 0);
   483  		wrint(b, 0);
   484  		return;
   485  	}
   486  	wrpath(ctxt, b, s->name);
   487  	wrint(b, s->version);
   488  }
   489  
   490  static void
   491  wrsym(Biobuf *b, LSym *s)
   492  {
   493  	if(s == nil) {
   494  		wrint(b, 0);
   495  		wrint(b, 0);
   496  		return;
   497  	}
   498  	wrstring(b, s->name);
   499  	wrint(b, s->version);
   500  }
   501  
   502  static char startmagic[] = "\x00\x00go13ld";
   503  static char endmagic[] = "\xff\xffgo13ld";
   504  
   505  void
   506  ldobjfile(Link *ctxt, Biobuf *f, char *pkg, int64 len, char *pn)
   507  {
   508  	int c;
   509  	uchar buf[8];
   510  	int64 start;
   511  	char *lib;
   512  
   513  	start = Boffset(f);
   514  	ctxt->version++;
   515  	memset(buf, 0, sizeof buf);
   516  	Bread(f, buf, sizeof buf);
   517  	if(memcmp(buf, startmagic, sizeof buf) != 0)
   518  		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]);
   519  	if((c = Bgetc(f)) != 1)
   520  		sysfatal("%s: invalid file version number %d", pn, c);
   521  
   522  	for(;;) {
   523  		lib = rdstring(f);
   524  		if(lib[0] == 0)
   525  			break;
   526  		addlib(ctxt, pkg, pn, lib);
   527  	}
   528  	
   529  	for(;;) {
   530  		c = Bgetc(f);
   531  		Bungetc(f);
   532  		if(c == 0xff)
   533  			break;
   534  		readsym(ctxt, f, pkg, pn);
   535  	}
   536  	
   537  	memset(buf, 0, sizeof buf);
   538  	Bread(f, buf, sizeof buf);
   539  	if(memcmp(buf, endmagic, sizeof buf) != 0)
   540  		sysfatal("%s: invalid file end", pn);
   541  	
   542  	if(Boffset(f) != start+len)
   543  		sysfatal("%s: unexpected end at %lld, want %lld", pn, (vlong)Boffset(f), (vlong)(start+len));
   544  }
   545  
   546  static void
   547  readsym(Link *ctxt, Biobuf *f, char *pkg, char *pn)
   548  {
   549  	int i, j, c, t, v, n, size, dupok;
   550  	static int ndup;
   551  	char *name;
   552  	Reloc *r;
   553  	LSym *s, *dup, *typ;
   554  	Pcln *pc;
   555  	Auto *a;
   556  	
   557  	if(Bgetc(f) != 0xfe)
   558  		sysfatal("readsym out of sync");
   559  	t = rdint(f);
   560  	name = expandpkg(rdstring(f), pkg);
   561  	v = rdint(f);
   562  	if(v != 0 && v != 1)
   563  		sysfatal("invalid symbol version %d", v);
   564  	dupok = rdint(f);
   565  	dupok &= 1;
   566  	size = rdint(f);
   567  	
   568  	if(v != 0)
   569  		v = ctxt->version;
   570  	s = linklookup(ctxt, name, v);
   571  	dup = nil;
   572  	if(s->type != 0 && s->type != SXREF) {
   573  		if(s->type != SBSS && s->type != SNOPTRBSS && !dupok && !s->dupok)
   574  			sysfatal("duplicate symbol %s (types %d and %d) in %s and %s", s->name, s->type, t, s->file, pn);
   575  		if(s->np > 0) {
   576  			dup = s;
   577  			s = linknewsym(ctxt, ".dup", ndup++); // scratch
   578  		}
   579  	}
   580  	s->file = pkg;
   581  	s->dupok = dupok;
   582  	if(t == SXREF)
   583  		sysfatal("bad sxref");
   584  	if(t == 0)
   585  		sysfatal("missing type for %s in %s", name, pn);
   586  	s->type = t;
   587  	if(s->size < size)
   588  		s->size = size;
   589  	typ = rdsym(ctxt, f, pkg);
   590  	if(typ != nil) // if bss sym defined multiple times, take type from any one def
   591  		s->gotype = typ;
   592  	if(dup != nil && typ != nil)
   593  		dup->gotype = typ;
   594  	rddata(f, &s->p, &s->np);
   595  	s->maxp = s->np;
   596  	n = rdint(f);
   597  	if(n > 0) {
   598  		s->r = emallocz(n * sizeof s->r[0]);
   599  		s->nr = n;
   600  		s->maxr = n;
   601  		for(i=0; i<n; i++) {
   602  			r = &s->r[i];
   603  			r->off = rdint(f);
   604  			r->siz = rdint(f);
   605  			r->type = rdint(f);
   606  			r->add = rdint(f);
   607  			r->xadd = rdint(f);
   608  			r->sym = rdsym(ctxt, f, pkg);
   609  			r->xsym = rdsym(ctxt, f, pkg);
   610  		}
   611  	}
   612  	
   613  	if(s->np > 0 && dup != nil && dup->np > 0 && strncmp(s->name, "gclocals·", 10) == 0) {
   614  		// content-addressed garbage collection liveness bitmap symbol.
   615  		// double check for hash collisions.
   616  		if(s->np != dup->np || memcmp(s->p, dup->p, s->np) != 0)
   617  			sysfatal("dupok hash collision for %s in %s and %s", s->name, s->file, pn);
   618  	}
   619  	
   620  	if(s->type == STEXT) {
   621  		s->args = rdint(f);
   622  		s->locals = rdint(f);
   623  		s->nosplit = rdint(f);
   624  		v = rdint(f);
   625  		s->leaf = v&1;
   626  		s->cfunc = v&2;
   627  		n = rdint(f);
   628  		for(i=0; i<n; i++) {
   629  			a = emallocz(sizeof *a);
   630  			a->asym = rdsym(ctxt, f, pkg);
   631  			a->aoffset = rdint(f);
   632  			a->type = rdint(f);
   633  			a->gotype = rdsym(ctxt, f, pkg);
   634  			a->link = s->autom;
   635  			s->autom = a;
   636  		}
   637  
   638  		s->pcln = emallocz(sizeof *s->pcln);
   639  		pc = s->pcln;
   640  		rddata(f, &pc->pcsp.p, &pc->pcsp.n);
   641  		rddata(f, &pc->pcfile.p, &pc->pcfile.n);
   642  		rddata(f, &pc->pcline.p, &pc->pcline.n);
   643  		n = rdint(f);
   644  		pc->pcdata = emallocz(n * sizeof pc->pcdata[0]);
   645  		pc->npcdata = n;
   646  		for(i=0; i<n; i++)
   647  			rddata(f, &pc->pcdata[i].p, &pc->pcdata[i].n);
   648  		n = rdint(f);
   649  		pc->funcdata = emallocz(n * sizeof pc->funcdata[0]);
   650  		pc->funcdataoff = emallocz(n * sizeof pc->funcdataoff[0]);
   651  		pc->nfuncdata = n;
   652  		for(i=0; i<n; i++)
   653  			pc->funcdata[i] = rdsym(ctxt, f, pkg);
   654  		for(i=0; i<n; i++)
   655  			pc->funcdataoff[i] = rdint(f);
   656  		n = rdint(f);
   657  		pc->file = emallocz(n * sizeof pc->file[0]);
   658  		pc->nfile = n;
   659  		for(i=0; i<n; i++)
   660  			pc->file[i] = rdsym(ctxt, f, pkg);
   661  
   662  		if(dup == nil) {
   663  			if(s->onlist)
   664  				sysfatal("symbol %s listed multiple times", s->name);
   665  			s->onlist = 1;
   666  			if(ctxt->etextp)
   667  				ctxt->etextp->next = s;
   668  			else
   669  				ctxt->textp = s;
   670  			ctxt->etextp = s;
   671  		}
   672  	}
   673  
   674  	if(ctxt->debugasm) {
   675  		Bprint(ctxt->bso, "%s ", s->name);
   676  		if(s->version)
   677  			Bprint(ctxt->bso, "v=%d ", s->version);
   678  		if(s->type)
   679  			Bprint(ctxt->bso, "t=%d ", s->type);
   680  		if(s->dupok)
   681  			Bprint(ctxt->bso, "dupok ");
   682  		if(s->cfunc)
   683  			Bprint(ctxt->bso, "cfunc ");
   684  		if(s->nosplit)
   685  			Bprint(ctxt->bso, "nosplit ");
   686  		Bprint(ctxt->bso, "size=%lld value=%lld", (vlong)s->size, (vlong)s->value);
   687  		if(s->type == STEXT)
   688  			Bprint(ctxt->bso, " args=%#llux locals=%#llux", (uvlong)s->args, (uvlong)s->locals);
   689  		Bprint(ctxt->bso, "\n");
   690  		for(i=0; i<s->np; ) {
   691  			Bprint(ctxt->bso, "\t%#06ux", i);
   692  			for(j=i; j<i+16 && j<s->np; j++)
   693  				Bprint(ctxt->bso, " %02ux", s->p[j]);
   694  			for(; j<i+16; j++)
   695  				Bprint(ctxt->bso, "   ");
   696  			Bprint(ctxt->bso, "  ");
   697  			for(j=i; j<i+16 && j<s->np; j++) {
   698  				c = s->p[j];
   699  				if(' ' <= c && c <= 0x7e)
   700  					Bprint(ctxt->bso, "%c", c);
   701  				else
   702  					Bprint(ctxt->bso, ".");
   703  			}
   704  			Bprint(ctxt->bso, "\n");
   705  			i += 16;
   706  		}
   707  		for(i=0; i<s->nr; i++) {
   708  			r = &s->r[i];
   709  			Bprint(ctxt->bso, "\trel %d+%d t=%d %s+%lld\n", (int)r->off, r->siz, r->type, r->sym->name, (vlong)r->add);
   710  		}
   711  	}
   712  }
   713  
   714  static int64
   715  rdint(Biobuf *f)
   716  {
   717  	int c;
   718  	uint64 uv;
   719  	int shift;
   720  	
   721  	uv = 0;
   722  	for(shift = 0;; shift += 7) {
   723  		if(shift >= 64)
   724  			sysfatal("corrupt input");
   725  		c = Bgetc(f);
   726  		uv |= (uint64)(c & 0x7F) << shift;
   727  		if(!(c & 0x80))
   728  			break;
   729  	}
   730  
   731  	return (int64)(uv>>1) ^ ((int64)((uint64)uv<<63)>>63);
   732  }
   733  
   734  static char*
   735  rdstring(Biobuf *f)
   736  {
   737  	int n;
   738  	char *p;
   739  	
   740  	n = rdint(f);
   741  	p = emallocz(n+1);
   742  	Bread(f, p, n);
   743  	return p;
   744  }
   745  
   746  static void
   747  rddata(Biobuf *f, uchar **pp, int *np)
   748  {
   749  	*np = rdint(f);
   750  	*pp = emallocz(*np);
   751  	Bread(f, *pp, *np);
   752  }
   753  
   754  static LSym*
   755  rdsym(Link *ctxt, Biobuf *f, char *pkg)
   756  {
   757  	int n, v;
   758  	char *p;
   759  	LSym *s;
   760  	
   761  	n = rdint(f);
   762  	if(n == 0) {
   763  		rdint(f);
   764  		return nil;
   765  	}
   766  	p = emallocz(n+1);
   767  	Bread(f, p, n);
   768  	v = rdint(f);
   769  	if(v != 0)
   770  		v = ctxt->version;
   771  	s = linklookup(ctxt, expandpkg(p, pkg), v);
   772  	
   773  	if(v == 0 && s->name[0] == '$' && s->type == 0) {
   774  		if(strncmp(s->name, "$f32.", 5) == 0) {
   775  			int32 i32;
   776  			i32 = strtoul(s->name+5, nil, 16);
   777  			s->type = SRODATA;
   778  			adduint32(ctxt, s, i32);
   779  			s->reachable = 0;
   780  		} else if(strncmp(s->name, "$f64.", 5) == 0) {
   781  			int64 i64;
   782  			i64 = strtoull(s->name+5, nil, 16);
   783  			s->type = SRODATA;
   784  			adduint64(ctxt, s, i64);
   785  			s->reachable = 0;
   786  		}
   787  	}
   788  
   789  	return s;
   790  }