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