github.com/xushiwei/go@v0.0.0-20130601165731-2b9d83f45bc9/src/cmd/ld/data.c (about)

     1  // Inferno utils/8l/asm.c
     2  // http://code.google.com/p/inferno-os/source/browse/utils/8l/asm.c
     3  //
     4  //	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
     5  //	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
     6  //	Portions Copyright © 1997-1999 Vita Nuova Limited
     7  //	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
     8  //	Portions Copyright © 2004,2006 Bruce Ellis
     9  //	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
    10  //	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
    11  //	Portions Copyright © 2009 The Go Authors.  All rights reserved.
    12  //
    13  // Permission is hereby granted, free of charge, to any person obtaining a copy
    14  // of this software and associated documentation files (the "Software"), to deal
    15  // in the Software without restriction, including without limitation the rights
    16  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    17  // copies of the Software, and to permit persons to whom the Software is
    18  // furnished to do so, subject to the following conditions:
    19  //
    20  // The above copyright notice and this permission notice shall be included in
    21  // all copies or substantial portions of the Software.
    22  //
    23  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    24  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    25  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
    26  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    27  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    28  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    29  // THE SOFTWARE.
    30  
    31  // Data layout and relocation.
    32  
    33  #include	"l.h"
    34  #include	"../ld/lib.h"
    35  #include	"../ld/elf.h"
    36  #include	"../ld/macho.h"
    37  #include	"../ld/pe.h"
    38  #include	"../../pkg/runtime/mgc0.h"
    39  
    40  void	dynreloc(void);
    41  static vlong addaddrplus4(Sym *s, Sym *t, vlong add);
    42  
    43  /*
    44   * divide-and-conquer list-link
    45   * sort of Sym* structures.
    46   * Used for the data block.
    47   */
    48  int
    49  datcmp(Sym *s1, Sym *s2)
    50  {
    51  	if(s1->type != s2->type)
    52  		return (int)s1->type - (int)s2->type;
    53  	if(s1->size != s2->size) {
    54  		if(s1->size < s2->size)
    55  			return -1;
    56  		return +1;
    57  	}
    58  	return strcmp(s1->name, s2->name);
    59  }
    60  
    61  Sym*
    62  listsort(Sym *l, int (*cmp)(Sym*, Sym*), int off)
    63  {
    64  	Sym *l1, *l2, *le;
    65  	#define NEXT(l) (*(Sym**)((char*)(l)+off))
    66  
    67  	if(l == 0 || NEXT(l) == 0)
    68  		return l;
    69  
    70  	l1 = l;
    71  	l2 = l;
    72  	for(;;) {
    73  		l2 = NEXT(l2);
    74  		if(l2 == 0)
    75  			break;
    76  		l2 = NEXT(l2);
    77  		if(l2 == 0)
    78  			break;
    79  		l1 = NEXT(l1);
    80  	}
    81  
    82  	l2 = NEXT(l1);
    83  	NEXT(l1) = 0;
    84  	l1 = listsort(l, cmp, off);
    85  	l2 = listsort(l2, cmp, off);
    86  
    87  	/* set up lead element */
    88  	if(cmp(l1, l2) < 0) {
    89  		l = l1;
    90  		l1 = NEXT(l1);
    91  	} else {
    92  		l = l2;
    93  		l2 = NEXT(l2);
    94  	}
    95  	le = l;
    96  
    97  	for(;;) {
    98  		if(l1 == 0) {
    99  			while(l2) {
   100  				NEXT(le) = l2;
   101  				le = l2;
   102  				l2 = NEXT(l2);
   103  			}
   104  			NEXT(le) = 0;
   105  			break;
   106  		}
   107  		if(l2 == 0) {
   108  			while(l1) {
   109  				NEXT(le) = l1;
   110  				le = l1;
   111  				l1 = NEXT(l1);
   112  			}
   113  			break;
   114  		}
   115  		if(cmp(l1, l2) < 0) {
   116  			NEXT(le) = l1;
   117  			le = l1;
   118  			l1 = NEXT(l1);
   119  		} else {
   120  			NEXT(le) = l2;
   121  			le = l2;
   122  			l2 = NEXT(l2);
   123  		}
   124  	}
   125  	NEXT(le) = 0;
   126  	return l;
   127  	
   128  	#undef NEXT
   129  }
   130  
   131  Reloc*
   132  addrel(Sym *s)
   133  {
   134  	if(s->nr >= s->maxr) {
   135  		if(s->maxr == 0)
   136  			s->maxr = 4;
   137  		else
   138  			s->maxr <<= 1;
   139  		s->r = erealloc(s->r, s->maxr*sizeof s->r[0]);
   140  		memset(s->r+s->nr, 0, (s->maxr-s->nr)*sizeof s->r[0]);
   141  	}
   142  	return &s->r[s->nr++];
   143  }
   144  
   145  void
   146  relocsym(Sym *s)
   147  {
   148  	Reloc *r;
   149  	Sym *rs;
   150  	Prog p;
   151  	int32 i, off, siz, fl;
   152  	vlong o;
   153  	uchar *cast;
   154  
   155  	cursym = s;
   156  	memset(&p, 0, sizeof p);
   157  	for(r=s->r; r<s->r+s->nr; r++) {
   158  		r->done = 1;
   159  		off = r->off;
   160  		siz = r->siz;
   161  		if(off < 0 || off+siz > s->np) {
   162  			diag("%s: invalid relocation %d+%d not in [%d,%d)", s->name, off, siz, 0, s->np);
   163  			continue;
   164  		}
   165  		if(r->sym != S && (r->sym->type & SMASK == 0 || r->sym->type & SMASK == SXREF)) {
   166  			diag("%s: not defined", r->sym->name);
   167  			continue;
   168  		}
   169  		if(r->type >= 256)
   170  			continue;
   171  
   172  		if(r->sym != S && r->sym->type == SDYNIMPORT)
   173  			diag("unhandled relocation for %s (type %d rtype %d)", r->sym->name, r->sym->type, r->type);
   174  
   175  		if(r->sym != S && r->sym->type != STLSBSS && !r->sym->reachable)
   176  			diag("unreachable sym in relocation: %s %s", s->name, r->sym->name);
   177  
   178  		switch(r->type) {
   179  		default:
   180  			o = 0;
   181  			if(linkmode == LinkExternal || archreloc(r, s, &o) < 0)
   182  				diag("unknown reloc %d", r->type);
   183  			break;
   184  		case D_TLS:
   185  			r->done = 0;
   186  			o = 0;
   187  			break;
   188  		case D_ADDR:
   189  			if(linkmode == LinkExternal && r->sym->type != SCONST) {
   190  				r->done = 0;
   191  
   192  				// set up addend for eventual relocation via outer symbol.
   193  				rs = r->sym;
   194  				r->xadd = r->add;
   195  				while(rs->outer != nil) {
   196  					r->xadd += symaddr(rs) - symaddr(rs->outer);
   197  					rs = rs->outer;
   198  				}
   199  				if(rs->type != SHOSTOBJ && rs->sect == nil)
   200  					diag("missing section for %s", rs->name);
   201  				r->xsym = rs;
   202  
   203  				o = r->xadd;
   204  				if(iself) {
   205  					if(thechar == '6')
   206  						o = 0;
   207  				} else if(HEADTYPE == Hdarwin) {
   208  					if(rs->type != SHOSTOBJ)
   209  						o += symaddr(rs);
   210  				} else {
   211  					diag("unhandled pcrel relocation for %s", headtype);
   212  				}
   213  				break;
   214  			}
   215  			o = symaddr(r->sym) + r->add;
   216  			break;
   217  		case D_PCREL:
   218  			// r->sym can be null when CALL $(constant) is transformed from absolute PC to relative PC call.
   219  			if(linkmode == LinkExternal && r->sym && r->sym->type != SCONST && r->sym->sect != cursym->sect) {
   220  				r->done = 0;
   221  
   222  				// set up addend for eventual relocation via outer symbol.
   223  				rs = r->sym;
   224  				r->xadd = r->add;
   225  				while(rs->outer != nil) {
   226  					r->xadd += symaddr(rs) - symaddr(rs->outer);
   227  					rs = rs->outer;
   228  				}
   229  				r->xadd -= r->siz; // relative to address after the relocated chunk
   230  				if(rs->type != SHOSTOBJ && rs->sect == nil)
   231  					diag("missing section for %s", rs->name);
   232  				r->xsym = rs;
   233  
   234  				o = r->xadd;
   235  				if(iself) {
   236  					if(thechar == '6')
   237  						o = 0;
   238  				} else if(HEADTYPE == Hdarwin) {
   239  					if(rs->type != SHOSTOBJ)
   240  						o += symaddr(rs) - rs->sect->vaddr;
   241  					o -= r->off; // WTF?
   242  				} else {
   243  					diag("unhandled pcrel relocation for %s", headtype);
   244  				}
   245  				break;
   246  			}
   247  			o = 0;
   248  			if(r->sym)
   249  				o += symaddr(r->sym);
   250  			// NOTE: The (int32) cast on the next line works around a bug in Plan 9's 8c
   251  			// compiler. The expression s->value + r->off + r->siz is int32 + int32 +
   252  			// uchar, and Plan 9 8c incorrectly treats the expression as type uint32
   253  			// instead of int32, causing incorrect values when sign extended for adding
   254  			// to o. The bug only occurs on Plan 9, because this C program is compiled by
   255  			// the standard host compiler (gcc on most other systems).
   256  			o += r->add - (s->value + r->off + (int32)r->siz);
   257  			break;
   258  		case D_SIZE:
   259  			o = r->sym->size + r->add;
   260  			break;
   261  		}
   262  //print("relocate %s %p %s => %p %p %p %p [%p]\n", s->name, s->value+off, r->sym ? r->sym->name : "<nil>", (void*)symaddr(r->sym), (void*)s->value, (void*)r->off, (void*)r->siz, (void*)o);
   263  		switch(siz) {
   264  		default:
   265  			cursym = s;
   266  			diag("bad reloc size %#ux for %s", siz, r->sym->name);
   267  		case 4:
   268  			if(r->type == D_PCREL) {
   269  				if(o != (int32)o)
   270  					diag("pc-relative relocation address is too big: %#llx", o);
   271  			} else {
   272  				if(o != (int32)o && o != (uint32)o)
   273  					diag("non-pc-relative relocation address is too big: %#llux", o);
   274  			}
   275  			fl = o;
   276  			cast = (uchar*)&fl;
   277  			for(i=0; i<4; i++)
   278  				s->p[off+i] = cast[inuxi4[i]];
   279  			break;
   280  		case 8:
   281  			cast = (uchar*)&o;
   282  			for(i=0; i<8; i++)
   283  				s->p[off+i] = cast[inuxi8[i]];
   284  			break;
   285  		}
   286  	}
   287  }
   288  
   289  void
   290  reloc(void)
   291  {
   292  	Sym *s;
   293  
   294  	if(debug['v'])
   295  		Bprint(&bso, "%5.2f reloc\n", cputime());
   296  	Bflush(&bso);
   297  
   298  	for(s=textp; s!=S; s=s->next)
   299  		relocsym(s);
   300  	for(s=datap; s!=S; s=s->next)
   301  		relocsym(s);
   302  }
   303  
   304  void
   305  dynrelocsym(Sym *s)
   306  {
   307  	Reloc *r;
   308  	Sym *rel;
   309  	Sym *got;
   310  	
   311  	if(HEADTYPE == Hwindows) {
   312  		Sym *rel, *targ;
   313  
   314  		rel = lookup(".rel", 0);
   315  		if(s == rel)
   316  			return;
   317  		for(r=s->r; r<s->r+s->nr; r++) {
   318  			targ = r->sym;
   319  			if(r->sym->plt == -2 && r->sym->got != -2) { // make dynimport JMP table for PE object files.
   320  				targ->plt = rel->size;
   321  				r->sym = rel;
   322  				r->add = targ->plt;
   323  
   324  				// jmp *addr
   325  				if(thechar == '8') {
   326  					adduint8(rel, 0xff);
   327  					adduint8(rel, 0x25);
   328  					addaddr(rel, targ);
   329  					adduint8(rel, 0x90);
   330  					adduint8(rel, 0x90);
   331  				} else {
   332  					adduint8(rel, 0xff);
   333  					adduint8(rel, 0x24);
   334  					adduint8(rel, 0x25);
   335  					addaddrplus4(rel, targ, 0);
   336  					adduint8(rel, 0x90);
   337  				}
   338  			} else if(r->sym->plt >= 0) {
   339  				r->sym = rel;
   340  				r->add = targ->plt;
   341  			}
   342  		}
   343  		return;
   344  	}
   345  
   346  	got = rel = nil;
   347  	if(flag_shared) {
   348  		rel = lookuprel();
   349  		got = lookup(".got", 0);
   350  	}
   351  	s->rel_ro = 0;
   352  	for(r=s->r; r<s->r+s->nr; r++) {
   353  		if(r->sym != S && r->sym->type == SDYNIMPORT || r->type >= 256)
   354  			adddynrel(s, r);
   355  		if(flag_shared && r->sym != S && s->type != SDYNIMPORT && r->type == D_ADDR
   356  				&& (s == got || s->type == SDATA || s->type == SGOSTRING || s->type == STYPE || s->type == SRODATA)) {
   357  			// Create address based RELATIVE relocation
   358  			adddynrela(rel, s, r);
   359  			if(s->type < SNOPTRDATA)
   360  				s->rel_ro = 1;
   361  		}
   362  	}
   363  }
   364  
   365  void
   366  dynreloc(void)
   367  {
   368  	Sym *s;
   369  
   370  	// -d supresses dynamic loader format, so we may as well not
   371  	// compute these sections or mark their symbols as reachable.
   372  	if(debug['d'] && HEADTYPE != Hwindows)
   373  		return;
   374  	if(debug['v'])
   375  		Bprint(&bso, "%5.2f reloc\n", cputime());
   376  	Bflush(&bso);
   377  
   378  	for(s=textp; s!=S; s=s->next)
   379  		dynrelocsym(s);
   380  	for(s=datap; s!=S; s=s->next)
   381  		dynrelocsym(s);
   382  	if(iself)
   383  		elfdynhash();
   384  }
   385  
   386  void
   387  symgrow(Sym *s, int32 siz)
   388  {
   389  	if(s->np >= siz)
   390  		return;
   391  
   392  	if(s->maxp < siz) {
   393  		if(s->maxp == 0)
   394  			s->maxp = 8;
   395  		while(s->maxp < siz)
   396  			s->maxp <<= 1;
   397  		s->p = erealloc(s->p, s->maxp);
   398  		memset(s->p+s->np, 0, s->maxp-s->np);
   399  	}
   400  	s->np = siz;
   401  }
   402  
   403  void
   404  savedata(Sym *s, Prog *p, char *pn)
   405  {
   406  	int32 off, siz, i, fl;
   407  	uchar *cast;
   408  	vlong o;
   409  	Reloc *r;
   410  
   411  	off = p->from.offset;
   412  	siz = p->datasize;
   413  	if(off < 0 || siz < 0 || off >= 1<<30 || siz >= 100)
   414  		mangle(pn);
   415  	symgrow(s, off+siz);
   416  
   417  	switch(p->to.type) {
   418  	default:
   419  		diag("bad data: %P", p);
   420  		break;
   421  
   422  	case D_FCONST:
   423  		switch(siz) {
   424  		default:
   425  		case 4:
   426  			fl = ieeedtof(&p->to.ieee);
   427  			cast = (uchar*)&fl;
   428  			for(i=0; i<4; i++)
   429  				s->p[off+i] = cast[fnuxi4[i]];
   430  			break;
   431  		case 8:
   432  			cast = (uchar*)&p->to.ieee;
   433  			for(i=0; i<8; i++)
   434  				s->p[off+i] = cast[fnuxi8[i]];
   435  			break;
   436  		}
   437  		break;
   438  
   439  	case D_SCONST:
   440  		for(i=0; i<siz; i++)
   441  			s->p[off+i] = p->to.scon[i];
   442  		break;
   443  
   444  	case D_CONST:
   445  		if(p->to.sym)
   446  			goto Addr;
   447  		o = p->to.offset;
   448  		fl = o;
   449  		cast = (uchar*)&fl;
   450  		switch(siz) {
   451  		default:
   452  			diag("bad nuxi %d\n%P", siz, p);
   453  			break;
   454  		case 1:
   455  			s->p[off] = cast[inuxi1[0]];
   456  			break;
   457  		case 2:
   458  			for(i=0; i<2; i++)
   459  				s->p[off+i] = cast[inuxi2[i]];
   460  			break;
   461  		case 4:
   462  			for(i=0; i<4; i++)
   463  				s->p[off+i] = cast[inuxi4[i]];
   464  			break;
   465  		case 8:
   466  			cast = (uchar*)&o;
   467  			for(i=0; i<8; i++)
   468  				s->p[off+i] = cast[inuxi8[i]];
   469  			break;
   470  		}
   471  		break;
   472  
   473  	case D_ADDR:
   474  	case D_SIZE:
   475  	Addr:
   476  		r = addrel(s);
   477  		r->off = off;
   478  		r->siz = siz;
   479  		r->sym = p->to.sym;
   480  		r->type = p->to.type;
   481  		if(r->type != D_SIZE)
   482  			r->type = D_ADDR;
   483  		r->add = p->to.offset;
   484  		break;
   485  	}
   486  }
   487  
   488  static void
   489  blk(Sym *start, int32 addr, int32 size)
   490  {
   491  	Sym *sym;
   492  	int32 eaddr;
   493  	uchar *p, *ep;
   494  
   495  	for(sym = start; sym != nil; sym = sym->next)
   496  		if(!(sym->type&SSUB) && sym->value >= addr)
   497  			break;
   498  
   499  	eaddr = addr+size;
   500  	for(; sym != nil; sym = sym->next) {
   501  		if(sym->type&SSUB)
   502  			continue;
   503  		if(sym->value >= eaddr)
   504  			break;
   505  		if(sym->value < addr) {
   506  			diag("phase error: addr=%#llx but sym=%#llx type=%d", (vlong)addr, (vlong)sym->value, sym->type);
   507  			errorexit();
   508  		}
   509  		cursym = sym;
   510  		for(; addr < sym->value; addr++)
   511  			cput(0);
   512  		p = sym->p;
   513  		ep = p + sym->np;
   514  		while(p < ep)
   515  			cput(*p++);
   516  		addr += sym->np;
   517  		for(; addr < sym->value+sym->size; addr++)
   518  			cput(0);
   519  		if(addr != sym->value+sym->size) {
   520  			diag("phase error: addr=%#llx value+size=%#llx", (vlong)addr, (vlong)sym->value+sym->size);
   521  			errorexit();
   522  		}
   523  	}
   524  
   525  	for(; addr < eaddr; addr++)
   526  		cput(0);
   527  	cflush();
   528  }
   529  
   530  void
   531  codeblk(int32 addr, int32 size)
   532  {
   533  	Sym *sym;
   534  	int32 eaddr, n, epc;
   535  	Prog *p;
   536  	uchar *q;
   537  
   538  	if(debug['a'])
   539  		Bprint(&bso, "codeblk [%#x,%#x) at offset %#llx\n", addr, addr+size, cpos());
   540  
   541  	blk(textp, addr, size);
   542  
   543  	/* again for printing */
   544  	if(!debug['a'])
   545  		return;
   546  
   547  	for(sym = textp; sym != nil; sym = sym->next) {
   548  		if(!sym->reachable)
   549  			continue;
   550  		if(sym->value >= addr)
   551  			break;
   552  	}
   553  
   554  	eaddr = addr + size;
   555  	for(; sym != nil; sym = sym->next) {
   556  		if(!sym->reachable)
   557  			continue;
   558  		if(sym->value >= eaddr)
   559  			break;
   560  
   561  		if(addr < sym->value) {
   562  			Bprint(&bso, "%-20s %.8llux|", "_", (vlong)addr);
   563  			for(; addr < sym->value; addr++)
   564  				Bprint(&bso, " %.2ux", 0);
   565  			Bprint(&bso, "\n");
   566  		}
   567  		p = sym->text;
   568  		if(p == nil) {
   569  			Bprint(&bso, "%.6llux\t%-20s | foreign text\n", (vlong)addr, sym->name);
   570  			n = sym->size;
   571  			q = sym->p;
   572  
   573  			while(n >= 16) {
   574  				Bprint(&bso, "%.6ux\t%-20.16I\n", addr, q);
   575  				addr += 16;
   576  				q += 16;
   577  				n -= 16;
   578  			}
   579  			if(n > 0)
   580  				Bprint(&bso, "%.6ux\t%-20.*I\n", addr, (int)n, q);
   581  			addr += n;
   582  			continue;
   583  		}
   584  
   585  		Bprint(&bso, "%.6llux\t%-20s | %P\n", (vlong)sym->value, sym->name, p);
   586  		for(p = p->link; p != P; p = p->link) {
   587  			if(p->link != P)
   588  				epc = p->link->pc;
   589  			else
   590  				epc = sym->value + sym->size;
   591  			Bprint(&bso, "%.6llux\t", (uvlong)p->pc);
   592  			q = sym->p + p->pc - sym->value;
   593  			n = epc - p->pc;
   594  			Bprint(&bso, "%-20.*I | %P\n", (int)n, q, p);
   595  			addr += n;
   596  		}
   597  	}
   598  
   599  	if(addr < eaddr) {
   600  		Bprint(&bso, "%-20s %.8llux|", "_", (vlong)addr);
   601  		for(; addr < eaddr; addr++)
   602  			Bprint(&bso, " %.2ux", 0);
   603  	}
   604  	Bflush(&bso);
   605  }
   606  
   607  void
   608  datblk(int32 addr, int32 size)
   609  {
   610  	Sym *sym;
   611  	int32 i, eaddr;
   612  	uchar *p, *ep;
   613  	char *typ, *rsname;
   614  	Reloc *r;
   615  
   616  	if(debug['a'])
   617  		Bprint(&bso, "datblk [%#x,%#x) at offset %#llx\n", addr, addr+size, cpos());
   618  
   619  	blk(datap, addr, size);
   620  
   621  	/* again for printing */
   622  	if(!debug['a'])
   623  		return;
   624  
   625  	for(sym = datap; sym != nil; sym = sym->next)
   626  		if(sym->value >= addr)
   627  			break;
   628  
   629  	eaddr = addr + size;
   630  	for(; sym != nil; sym = sym->next) {
   631  		if(sym->value >= eaddr)
   632  			break;
   633  		if(addr < sym->value) {
   634  			Bprint(&bso, "\t%.8ux| 00 ...\n", addr);
   635  			addr = sym->value;
   636  		}
   637  		Bprint(&bso, "%s\n\t%.8ux|", sym->name, (uint)addr);
   638  		p = sym->p;
   639  		ep = p + sym->np;
   640  		while(p < ep) {
   641  			if(p > sym->p && (int)(p-sym->p)%16 == 0)
   642  				Bprint(&bso, "\n\t%.8ux|", (uint)(addr+(p-sym->p)));
   643  			Bprint(&bso, " %.2ux", *p++);
   644  		}
   645  		addr += sym->np;
   646  		for(; addr < sym->value+sym->size; addr++)
   647  			Bprint(&bso, " %.2ux", 0);
   648  		Bprint(&bso, "\n");
   649  		
   650  		if(linkmode == LinkExternal) {
   651  			for(i=0; i<sym->nr; i++) {
   652  				r = &sym->r[i];
   653  				rsname = "";
   654  				if(r->sym)
   655  					rsname = r->sym->name;
   656  				typ = "?";
   657  				switch(r->type) {
   658  				case D_ADDR:
   659  					typ = "addr";
   660  					break;
   661  				case D_PCREL:
   662  					typ = "pcrel";
   663  					break;
   664  				}
   665  				Bprint(&bso, "\treloc %.8ux/%d %s %s+%#llx [%#llx]\n",
   666  					(uint)(sym->value+r->off), r->siz, typ, rsname, (vlong)r->add, (vlong)(r->sym->value+r->add));
   667  			}
   668  		}				
   669  	}
   670  
   671  	if(addr < eaddr)
   672  		Bprint(&bso, "\t%.8ux| 00 ...\n", (uint)addr);
   673  	Bprint(&bso, "\t%.8ux|\n", (uint)eaddr);
   674  }
   675  
   676  void
   677  strnput(char *s, int n)
   678  {
   679  	for(; n > 0 && *s; s++) {
   680  		cput(*s);
   681  		n--;
   682  	}
   683  	while(n > 0) {
   684  		cput(0);
   685  		n--;
   686  	}
   687  }
   688  
   689  void
   690  addstrdata(char *name, char *value)
   691  {
   692  	Sym *s, *sp;
   693  	char *p;
   694  
   695  	p = smprint("%s.str", name);
   696  	sp = lookup(p, 0);
   697  	free(p);
   698  	addstring(sp, value);
   699  
   700  	s = lookup(name, 0);
   701  	s->size = 0;
   702  	s->dupok = 1;
   703  	addaddr(s, sp);
   704  	adduint32(s, strlen(value));
   705  	if(PtrSize == 8)
   706  		adduint32(s, 0);  // round struct to pointer width
   707  
   708  	// in case reachability has already been computed
   709  	sp->reachable = s->reachable;
   710  }
   711  
   712  vlong
   713  addstring(Sym *s, char *str)
   714  {
   715  	int n;
   716  	int32 r;
   717  
   718  	if(s->type == 0)
   719  		s->type = SNOPTRDATA;
   720  	s->reachable = 1;
   721  	r = s->size;
   722  	n = strlen(str)+1;
   723  	if(strcmp(s->name, ".shstrtab") == 0)
   724  		elfsetstring(str, r);
   725  	symgrow(s, r+n);
   726  	memmove(s->p+r, str, n);
   727  	s->size += n;
   728  	return r;
   729  }
   730  
   731  vlong
   732  setuintxx(Sym *s, vlong off, uint64 v, vlong wid)
   733  {
   734  	int32 i, fl;
   735  	vlong o;
   736  	uchar *cast;
   737  
   738  	if(s->type == 0)
   739  		s->type = SDATA;
   740  	s->reachable = 1;
   741  	if(s->size < off+wid) {
   742  		s->size = off+wid;
   743  		symgrow(s, s->size);
   744  	}
   745  	fl = v;
   746  	cast = (uchar*)&fl;
   747  	switch(wid) {
   748  	case 1:
   749  		s->p[off] = cast[inuxi1[0]];
   750  		break;
   751  	case 2:
   752  		for(i=0; i<2; i++)
   753  			s->p[off+i] = cast[inuxi2[i]];
   754  		break;
   755  	case 4:
   756  		for(i=0; i<4; i++)
   757  			s->p[off+i] = cast[inuxi4[i]];
   758  		break;
   759  	case 8:
   760  		o = v;
   761  		cast = (uchar*)&o;
   762  		for(i=0; i<8; i++)
   763  			s->p[off+i] = cast[inuxi8[i]];
   764  		break;
   765  	}
   766  	return off;
   767  }
   768  
   769  vlong
   770  adduintxx(Sym *s, uint64 v, int wid)
   771  {
   772  	vlong off;
   773  
   774  	off = s->size;
   775  	setuintxx(s, off, v, wid);
   776  	return off;
   777  }
   778  
   779  vlong
   780  adduint8(Sym *s, uint8 v)
   781  {
   782  	return adduintxx(s, v, 1);
   783  }
   784  
   785  vlong
   786  adduint16(Sym *s, uint16 v)
   787  {
   788  	return adduintxx(s, v, 2);
   789  }
   790  
   791  vlong
   792  adduint32(Sym *s, uint32 v)
   793  {
   794  	return adduintxx(s, v, 4);
   795  }
   796  
   797  vlong
   798  adduint64(Sym *s, uint64 v)
   799  {
   800  	return adduintxx(s, v, 8);
   801  }
   802  
   803  void
   804  setuint8(Sym *s, vlong r, uint8 v)
   805  {
   806  	setuintxx(s, r, v, 1);
   807  }
   808  
   809  void
   810  setuint16(Sym *s, vlong r, uint16 v)
   811  {
   812  	setuintxx(s, r, v, 2);
   813  }
   814  
   815  void
   816  setuint32(Sym *s, vlong r, uint32 v)
   817  {
   818  	setuintxx(s, r, v, 4);
   819  }
   820  
   821  void
   822  setuint64(Sym *s, vlong r, uint64 v)
   823  {
   824  	setuintxx(s, r, v, 8);
   825  }
   826  
   827  vlong
   828  addaddrplus(Sym *s, Sym *t, vlong add)
   829  {
   830  	vlong i;
   831  	Reloc *r;
   832  
   833  	if(s->type == 0)
   834  		s->type = SDATA;
   835  	s->reachable = 1;
   836  	i = s->size;
   837  	s->size += PtrSize;
   838  	symgrow(s, s->size);
   839  	r = addrel(s);
   840  	r->sym = t;
   841  	r->off = i;
   842  	r->siz = PtrSize;
   843  	r->type = D_ADDR;
   844  	r->add = add;
   845  	return i;
   846  }
   847  
   848  static vlong
   849  addaddrplus4(Sym *s, Sym *t, vlong add)
   850  {
   851  	vlong i;
   852  	Reloc *r;
   853  
   854  	if(s->type == 0)
   855  		s->type = SDATA;
   856  	s->reachable = 1;
   857  	i = s->size;
   858  	s->size += 4;
   859  	symgrow(s, s->size);
   860  	r = addrel(s);
   861  	r->sym = t;
   862  	r->off = i;
   863  	r->siz = 4;
   864  	r->type = D_ADDR;
   865  	r->add = add;
   866  	return i;
   867  }
   868  
   869  vlong
   870  addpcrelplus(Sym *s, Sym *t, vlong add)
   871  {
   872  	vlong i;
   873  	Reloc *r;
   874  
   875  	if(s->type == 0)
   876  		s->type = SDATA;
   877  	s->reachable = 1;
   878  	i = s->size;
   879  	s->size += 4;
   880  	symgrow(s, s->size);
   881  	r = addrel(s);
   882  	r->sym = t;
   883  	r->off = i;
   884  	r->add = add;
   885  	r->type = D_PCREL;
   886  	r->siz = 4;
   887  	return i;
   888  }
   889  
   890  vlong
   891  addaddr(Sym *s, Sym *t)
   892  {
   893  	return addaddrplus(s, t, 0);
   894  }
   895  
   896  vlong
   897  setaddrplus(Sym *s, vlong off, Sym *t, vlong add)
   898  {
   899  	Reloc *r;
   900  
   901  	if(s->type == 0)
   902  		s->type = SDATA;
   903  	s->reachable = 1;
   904  	if(off+PtrSize > s->size) {
   905  		s->size = off + PtrSize;
   906  		symgrow(s, s->size);
   907  	}
   908  	r = addrel(s);
   909  	r->sym = t;
   910  	r->off = off;
   911  	r->siz = PtrSize;
   912  	r->type = D_ADDR;
   913  	r->add = add;
   914  	return off;
   915  }
   916  
   917  vlong
   918  setaddr(Sym *s, vlong off, Sym *t)
   919  {
   920  	return setaddrplus(s, off, t, 0);
   921  }
   922  
   923  vlong
   924  addsize(Sym *s, Sym *t)
   925  {
   926  	vlong i;
   927  	Reloc *r;
   928  
   929  	if(s->type == 0)
   930  		s->type = SDATA;
   931  	s->reachable = 1;
   932  	i = s->size;
   933  	s->size += PtrSize;
   934  	symgrow(s, s->size);
   935  	r = addrel(s);
   936  	r->sym = t;
   937  	r->off = i;
   938  	r->siz = PtrSize;
   939  	r->type = D_SIZE;
   940  	return i;
   941  }
   942  
   943  void
   944  dosymtype(void)
   945  {
   946  	Sym *s;
   947  
   948  	for(s = allsym; s != nil; s = s->allsym) {
   949  		if(s->np > 0) {
   950  			if(s->type == SBSS)
   951  				s->type = SDATA;
   952  			if(s->type == SNOPTRBSS)
   953  				s->type = SNOPTRDATA;
   954  		}
   955  	}
   956  }
   957  
   958  static int32
   959  symalign(Sym *s)
   960  {
   961  	int32 align;
   962  
   963  	if(s->align != 0)
   964  		return s->align;
   965  
   966  	align = MaxAlign;
   967  	while(align > s->size && align > 1)
   968  		align >>= 1;
   969  	if(align < s->align)
   970  		align = s->align;
   971  	return align;
   972  }
   973  	
   974  static vlong
   975  aligndatsize(vlong datsize, Sym *s)
   976  {
   977  	return rnd(datsize, symalign(s));
   978  }
   979  
   980  // maxalign returns the maximum required alignment for
   981  // the list of symbols s; the list stops when s->type exceeds type.
   982  static int32
   983  maxalign(Sym *s, int type)
   984  {
   985  	int32 align, max;
   986  	
   987  	max = 0;
   988  	for(; s != S && s->type <= type; s = s->next) {
   989  		align = symalign(s);
   990  		if(max < align)
   991  			max = align;
   992  	}
   993  	return max;
   994  }
   995  
   996  static void
   997  gcaddsym(Sym *gc, Sym *s, vlong off)
   998  {
   999  	vlong a;
  1000  	Sym *gotype;
  1001  
  1002  	if(s->size < PtrSize)
  1003  		return;
  1004  	if(strcmp(s->name, ".string") == 0)
  1005  		return;
  1006  
  1007  	gotype = s->gotype;
  1008  	if(gotype != nil) {
  1009  		//print("gcaddsym:    %s    %d    %s\n", s->name, s->size, gotype->name);
  1010  		adduintxx(gc, GC_CALL, PtrSize);
  1011  		adduintxx(gc, off, PtrSize);
  1012  		addpcrelplus(gc, decodetype_gc(gotype), 3*PtrSize+4);
  1013  		if(PtrSize == 8)
  1014  			adduintxx(gc, 0, 4);
  1015  	} else {
  1016  		//print("gcaddsym:    %s    %d    <unknown type>\n", s->name, s->size);
  1017  		for(a = -off&(PtrSize-1); a+PtrSize<=s->size; a+=PtrSize) {
  1018  			adduintxx(gc, GC_APTR, PtrSize);
  1019  			adduintxx(gc, off+a, PtrSize);
  1020  		}
  1021  	}
  1022  }
  1023  
  1024  void
  1025  growdatsize(vlong *datsizep, Sym *s)
  1026  {
  1027  	vlong datsize;
  1028  	
  1029  	datsize = *datsizep;
  1030  	if(s->size < 0)
  1031  		diag("negative size (datsize = %lld, s->size = %lld)", datsize, s->size);
  1032  	if(datsize + s->size < datsize)
  1033  		diag("symbol too large (datsize = %lld, s->size = %lld)", datsize, s->size);
  1034  	*datsizep = datsize + s->size;
  1035  }
  1036  
  1037  void
  1038  dodata(void)
  1039  {
  1040  	int32 n;
  1041  	vlong datsize;
  1042  	Section *sect;
  1043  	Sym *s, *last, **l;
  1044  	Sym *gcdata1, *gcbss1;
  1045  
  1046  	if(debug['v'])
  1047  		Bprint(&bso, "%5.2f dodata\n", cputime());
  1048  	Bflush(&bso);
  1049  
  1050  	// define garbage collection symbols
  1051  	gcdata1 = lookup("gcdata", 0);
  1052  	gcdata1->type = STYPE;
  1053  	gcdata1->reachable = 1;
  1054  	gcbss1 = lookup("gcbss", 0);
  1055  	gcbss1->type = STYPE;
  1056  	gcbss1->reachable = 1;
  1057  
  1058  	// size of .data and .bss section. the zero value is later replaced by the actual size of the section.
  1059  	adduintxx(gcdata1, 0, PtrSize);
  1060  	adduintxx(gcbss1, 0, PtrSize);
  1061  
  1062  	last = nil;
  1063  	datap = nil;
  1064  
  1065  	for(s=allsym; s!=S; s=s->allsym) {
  1066  		if(!s->reachable || s->special)
  1067  			continue;
  1068  		if(STEXT < s->type && s->type < SXREF) {
  1069  			if(last == nil)
  1070  				datap = s;
  1071  			else
  1072  				last->next = s;
  1073  			s->next = nil;
  1074  			last = s;
  1075  		}
  1076  	}
  1077  
  1078  	for(s = datap; s != nil; s = s->next) {
  1079  		if(s->np > s->size)
  1080  			diag("%s: initialize bounds (%lld < %d)",
  1081  				s->name, (vlong)s->size, s->np);
  1082  	}
  1083  
  1084  
  1085  	/*
  1086  	 * now that we have the datap list, but before we start
  1087  	 * to assign addresses, record all the necessary
  1088  	 * dynamic relocations.  these will grow the relocation
  1089  	 * symbol, which is itself data.
  1090  	 *
  1091  	 * on darwin, we need the symbol table numbers for dynreloc.
  1092  	 */
  1093  	if(HEADTYPE == Hdarwin)
  1094  		machosymorder();
  1095  	dynreloc();
  1096  
  1097  	/* some symbols may no longer belong in datap (Mach-O) */
  1098  	for(l=&datap; (s=*l) != nil; ) {
  1099  		if(s->type <= STEXT || SXREF <= s->type)
  1100  			*l = s->next;
  1101  		else
  1102  			l = &s->next;
  1103  	}
  1104  	*l = nil;
  1105  
  1106  	if(flag_shared) {
  1107  		for(s=datap; s != nil; s = s->next) {
  1108  			if(s->rel_ro)
  1109  				s->type = SDATARELRO;
  1110  		}
  1111  	}
  1112  	datap = listsort(datap, datcmp, offsetof(Sym, next));
  1113  
  1114  	/*
  1115  	 * allocate sections.  list is sorted by type,
  1116  	 * so we can just walk it for each piece we want to emit.
  1117  	 * segdata is processed before segtext, because we need
  1118  	 * to see all symbols in the .data and .bss sections in order
  1119  	 * to generate garbage collection information.
  1120  	 */
  1121  
  1122  	/* begin segdata */
  1123  
  1124  	/* skip symbols belonging to segtext */
  1125  	s = datap;
  1126  	for(; s != nil && s->type < SELFSECT; s = s->next)
  1127  		;
  1128  
  1129  	/* writable ELF sections */
  1130  	datsize = 0;
  1131  	for(; s != nil && s->type < SNOPTRDATA; s = s->next) {
  1132  		sect = addsection(&segdata, s->name, 06);
  1133  		sect->align = symalign(s);
  1134  		datsize = rnd(datsize, sect->align);
  1135  		sect->vaddr = datsize;
  1136  		s->sect = sect;
  1137  		s->type = SDATA;
  1138  		s->value = datsize;
  1139  		growdatsize(&datsize, s);
  1140  		sect->len = datsize - sect->vaddr;
  1141  	}
  1142  
  1143  	/* pointer-free data */
  1144  	sect = addsection(&segdata, ".noptrdata", 06);
  1145  	sect->align = maxalign(s, SDATARELRO-1);
  1146  	datsize = rnd(datsize, sect->align);
  1147  	sect->vaddr = datsize;
  1148  	lookup("noptrdata", 0)->sect = sect;
  1149  	lookup("enoptrdata", 0)->sect = sect;
  1150  	for(; s != nil && s->type < SDATARELRO; s = s->next) {
  1151  		datsize = aligndatsize(datsize, s);
  1152  		s->sect = sect;
  1153  		s->type = SDATA;
  1154  		s->value = datsize;
  1155  		growdatsize(&datsize, s);
  1156  	}
  1157  	sect->len = datsize - sect->vaddr;
  1158  
  1159  	/* dynamic relocated rodata */
  1160  	if(flag_shared) {
  1161  		sect = addsection(&segdata, ".data.rel.ro", 06);
  1162  		sect->align = maxalign(s, SDATARELRO);
  1163  		datsize = rnd(datsize, sect->align);
  1164  		sect->vaddr = datsize;
  1165  		lookup("datarelro", 0)->sect = sect;
  1166  		lookup("edatarelro", 0)->sect = sect;
  1167  		for(; s != nil && s->type == SDATARELRO; s = s->next) {
  1168  			datsize = aligndatsize(datsize, s);
  1169  			s->sect = sect;
  1170  			s->type = SDATA;
  1171  			s->value = datsize;
  1172  			growdatsize(&datsize, s);
  1173  		}
  1174  		sect->len = datsize - sect->vaddr;
  1175  	}
  1176  
  1177  	/* data */
  1178  	sect = addsection(&segdata, ".data", 06);
  1179  	sect->align = maxalign(s, SBSS-1);
  1180  	datsize = rnd(datsize, sect->align);
  1181  	sect->vaddr = datsize;
  1182  	lookup("data", 0)->sect = sect;
  1183  	lookup("edata", 0)->sect = sect;
  1184  	for(; s != nil && s->type < SBSS; s = s->next) {
  1185  		if(s->type == SDATARELRO) {
  1186  			cursym = s;
  1187  			diag("unexpected symbol type %d", s->type);
  1188  		}
  1189  		s->sect = sect;
  1190  		s->type = SDATA;
  1191  		datsize = aligndatsize(datsize, s);
  1192  		s->value = datsize;
  1193  		gcaddsym(gcdata1, s, datsize - sect->vaddr);  // gc
  1194  		growdatsize(&datsize, s);
  1195  	}
  1196  	sect->len = datsize - sect->vaddr;
  1197  
  1198  	adduintxx(gcdata1, GC_END, PtrSize);
  1199  	setuintxx(gcdata1, 0, sect->len, PtrSize);
  1200  
  1201  	/* bss */
  1202  	sect = addsection(&segdata, ".bss", 06);
  1203  	sect->align = maxalign(s, SNOPTRBSS-1);
  1204  	datsize = rnd(datsize, sect->align);
  1205  	sect->vaddr = datsize;
  1206  	lookup("bss", 0)->sect = sect;
  1207  	lookup("ebss", 0)->sect = sect;
  1208  	for(; s != nil && s->type < SNOPTRBSS; s = s->next) {
  1209  		s->sect = sect;
  1210  		datsize = aligndatsize(datsize, s);
  1211  		s->value = datsize;
  1212  		gcaddsym(gcbss1, s, datsize - sect->vaddr);  // gc
  1213  		growdatsize(&datsize, s);
  1214  	}
  1215  	sect->len = datsize - sect->vaddr;
  1216  
  1217  	adduintxx(gcbss1, GC_END, PtrSize);
  1218  	setuintxx(gcbss1, 0, sect->len, PtrSize);
  1219  
  1220  	/* pointer-free bss */
  1221  	sect = addsection(&segdata, ".noptrbss", 06);
  1222  	sect->align = maxalign(s, SNOPTRBSS);
  1223  	datsize = rnd(datsize, sect->align);
  1224  	sect->vaddr = datsize;
  1225  	lookup("noptrbss", 0)->sect = sect;
  1226  	lookup("enoptrbss", 0)->sect = sect;
  1227  	for(; s != nil && s->type == SNOPTRBSS; s = s->next) {
  1228  		datsize = aligndatsize(datsize, s);
  1229  		s->sect = sect;
  1230  		s->value = datsize;
  1231  		growdatsize(&datsize, s);
  1232  	}
  1233  	sect->len = datsize - sect->vaddr;
  1234  	lookup("end", 0)->sect = sect;
  1235  
  1236  	// 6g uses 4-byte relocation offsets, so the entire segment must fit in 32 bits.
  1237  	if(datsize != (uint32)datsize) {
  1238  		diag("data or bss segment too large");
  1239  	}
  1240  	
  1241  	if(iself && linkmode == LinkExternal && s != nil && s->type == STLSBSS && HEADTYPE != Hopenbsd) {
  1242  		sect = addsection(&segdata, ".tbss", 06);
  1243  		sect->align = PtrSize;
  1244  		sect->vaddr = 0;
  1245  		datsize = 0;
  1246  		for(; s != nil && s->type == STLSBSS; s = s->next) {
  1247  			datsize = aligndatsize(datsize, s);
  1248  			s->sect = sect;
  1249  			s->value = datsize;
  1250  			growdatsize(&datsize, s);
  1251  		}
  1252  		sect->len = datsize;
  1253  	}
  1254  	
  1255  	if(s != nil) {
  1256  		cursym = nil;
  1257  		diag("unexpected symbol type %d for %s", s->type, s->name);
  1258  	}
  1259  
  1260  	/* we finished segdata, begin segtext */
  1261  	s = datap;
  1262  
  1263  	/* read-only data */
  1264  	sect = addsection(&segtext, ".rodata", 04);
  1265  	sect->align = maxalign(s, STYPELINK-1);
  1266  	sect->vaddr = 0;
  1267  	lookup("rodata", 0)->sect = sect;
  1268  	lookup("erodata", 0)->sect = sect;
  1269  	datsize = 0;
  1270  	for(; s != nil && s->type < STYPELINK; s = s->next) {
  1271  		datsize = aligndatsize(datsize, s);
  1272  		s->sect = sect;
  1273  		s->type = SRODATA;
  1274  		s->value = datsize;
  1275  		growdatsize(&datsize, s);
  1276  	}
  1277  	sect->len = datsize - sect->vaddr;
  1278  
  1279  	/* typelink */
  1280  	sect = addsection(&segtext, ".typelink", 04);
  1281  	sect->align = maxalign(s, STYPELINK);
  1282  	datsize = rnd(datsize, sect->align);
  1283  	sect->vaddr = datsize;
  1284  	lookup("typelink", 0)->sect = sect;
  1285  	lookup("etypelink", 0)->sect = sect;
  1286  	for(; s != nil && s->type == STYPELINK; s = s->next) {
  1287  		datsize = aligndatsize(datsize, s);
  1288  		s->sect = sect;
  1289  		s->type = SRODATA;
  1290  		s->value = datsize;
  1291  		growdatsize(&datsize, s);
  1292  	}
  1293  	sect->len = datsize - sect->vaddr;
  1294  
  1295  	/* gosymtab */
  1296  	sect = addsection(&segtext, ".gosymtab", 04);
  1297  	sect->align = maxalign(s, SPCLNTAB-1);
  1298  	datsize = rnd(datsize, sect->align);
  1299  	sect->vaddr = datsize;
  1300  	lookup("symtab", 0)->sect = sect;
  1301  	lookup("esymtab", 0)->sect = sect;
  1302  	for(; s != nil && s->type < SPCLNTAB; s = s->next) {
  1303  		datsize = aligndatsize(datsize, s);
  1304  		s->sect = sect;
  1305  		s->type = SRODATA;
  1306  		s->value = datsize;
  1307  		growdatsize(&datsize, s);
  1308  	}
  1309  	sect->len = datsize - sect->vaddr;
  1310  
  1311  	/* gopclntab */
  1312  	sect = addsection(&segtext, ".gopclntab", 04);
  1313  	sect->align = maxalign(s, SELFROSECT-1);
  1314  	datsize = rnd(datsize, sect->align);
  1315  	sect->vaddr = datsize;
  1316  	lookup("pclntab", 0)->sect = sect;
  1317  	lookup("epclntab", 0)->sect = sect;
  1318  	for(; s != nil && s->type < SELFROSECT; s = s->next) {
  1319  		datsize = aligndatsize(datsize, s);
  1320  		s->sect = sect;
  1321  		s->type = SRODATA;
  1322  		s->value = datsize;
  1323  		growdatsize(&datsize, s);
  1324  	}
  1325  	sect->len = datsize - sect->vaddr;
  1326  
  1327  	/* read-only ELF, Mach-O sections */
  1328  	for(; s != nil && s->type < SELFSECT; s = s->next) {
  1329  		sect = addsection(&segtext, s->name, 04);
  1330  		sect->align = symalign(s);
  1331  		datsize = rnd(datsize, sect->align);
  1332  		sect->vaddr = datsize;
  1333  		s->sect = sect;
  1334  		s->type = SRODATA;
  1335  		s->value = datsize;
  1336  		growdatsize(&datsize, s);
  1337  		sect->len = datsize - sect->vaddr;
  1338  	}
  1339  
  1340  	// 6g uses 4-byte relocation offsets, so the entire segment must fit in 32 bits.
  1341  	if(datsize != (uint32)datsize) {
  1342  		diag("text segment too large");
  1343  	}
  1344  	
  1345  	/* number the sections */
  1346  	n = 1;
  1347  	for(sect = segtext.sect; sect != nil; sect = sect->next)
  1348  		sect->extnum = n++;
  1349  	for(sect = segdata.sect; sect != nil; sect = sect->next)
  1350  		sect->extnum = n++;
  1351  }
  1352  
  1353  // assign addresses to text
  1354  void
  1355  textaddress(void)
  1356  {
  1357  	uvlong va;
  1358  	Prog *p;
  1359  	Section *sect;
  1360  	Sym *sym, *sub;
  1361  
  1362  	addsection(&segtext, ".text", 05);
  1363  
  1364  	// Assign PCs in text segment.
  1365  	// Could parallelize, by assigning to text
  1366  	// and then letting threads copy down, but probably not worth it.
  1367  	sect = segtext.sect;
  1368  	sect->align = FuncAlign;
  1369  	lookup("text", 0)->sect = sect;
  1370  	lookup("etext", 0)->sect = sect;
  1371  	va = INITTEXT;
  1372  	sect->vaddr = va;
  1373  	for(sym = textp; sym != nil; sym = sym->next) {
  1374  		sym->sect = sect;
  1375  		if(sym->type & SSUB)
  1376  			continue;
  1377  		if(sym->align != 0)
  1378  			va = rnd(va, sym->align);
  1379  		else if(sym->text != P)
  1380  			va = rnd(va, FuncAlign);
  1381  		sym->value = 0;
  1382  		for(sub = sym; sub != S; sub = sub->sub) {
  1383  			sub->value += va;
  1384  			for(p = sub->text; p != P; p = p->link)
  1385  				p->pc += sub->value;
  1386  		}
  1387  		if(sym->size == 0 && sym->sub != S) {
  1388  			cursym = sym;
  1389  		}
  1390  		va += sym->size;
  1391  	}
  1392  	sect->len = va - sect->vaddr;
  1393  }
  1394  
  1395  // assign addresses
  1396  void
  1397  address(void)
  1398  {
  1399  	Section *s, *text, *data, *rodata, *symtab, *pclntab, *noptr, *bss, *noptrbss, *datarelro;
  1400  	Section *typelink;
  1401  	Sym *sym, *sub;
  1402  	uvlong va;
  1403  	vlong vlen;
  1404  
  1405  	va = INITTEXT;
  1406  	segtext.rwx = 05;
  1407  	segtext.vaddr = va;
  1408  	segtext.fileoff = HEADR;
  1409  	for(s=segtext.sect; s != nil; s=s->next) {
  1410  		va = rnd(va, s->align);
  1411  		s->vaddr = va;
  1412  		va += s->len;
  1413  	}
  1414  	segtext.len = va - INITTEXT;
  1415  	segtext.filelen = segtext.len;
  1416  
  1417  	va = rnd(va, INITRND);
  1418  
  1419  	segdata.rwx = 06;
  1420  	segdata.vaddr = va;
  1421  	segdata.fileoff = va - segtext.vaddr + segtext.fileoff;
  1422  	segdata.filelen = 0;
  1423  	if(HEADTYPE == Hwindows)
  1424  		segdata.fileoff = segtext.fileoff + rnd(segtext.len, PEFILEALIGN);
  1425  	if(HEADTYPE == Hplan9x64 || HEADTYPE == Hplan9x32)
  1426  		segdata.fileoff = segtext.fileoff + segtext.filelen;
  1427  	data = nil;
  1428  	noptr = nil;
  1429  	bss = nil;
  1430  	noptrbss = nil;
  1431  	datarelro = nil;
  1432  	for(s=segdata.sect; s != nil; s=s->next) {
  1433  		vlen = s->len;
  1434  		if(s->next)
  1435  			vlen = s->next->vaddr - s->vaddr;
  1436  		s->vaddr = va;
  1437  		va += vlen;
  1438  		segdata.len = va - segdata.vaddr;
  1439  		if(strcmp(s->name, ".data") == 0)
  1440  			data = s;
  1441  		if(strcmp(s->name, ".noptrdata") == 0)
  1442  			noptr = s;
  1443  		if(strcmp(s->name, ".bss") == 0)
  1444  			bss = s;
  1445  		if(strcmp(s->name, ".noptrbss") == 0)
  1446  			noptrbss = s;
  1447  		if(strcmp(s->name, ".data.rel.ro") == 0)
  1448  			datarelro = s;
  1449  	}
  1450  	segdata.filelen = bss->vaddr - segdata.vaddr;
  1451  
  1452  	text = segtext.sect;
  1453  	rodata = text->next;
  1454  	typelink = rodata->next;
  1455  	symtab = typelink->next;
  1456  	pclntab = symtab->next;
  1457  
  1458  	for(sym = datap; sym != nil; sym = sym->next) {
  1459  		cursym = sym;
  1460  		if(sym->type < SNOPTRDATA)
  1461  			sym->value += rodata->vaddr;
  1462  		else
  1463  			sym->value += segdata.sect->vaddr;
  1464  		for(sub = sym->sub; sub != nil; sub = sub->sub)
  1465  			sub->value += sym->value;
  1466  	}
  1467  
  1468  	xdefine("text", STEXT, text->vaddr);
  1469  	xdefine("etext", STEXT, text->vaddr + text->len);
  1470  	xdefine("rodata", SRODATA, rodata->vaddr);
  1471  	xdefine("erodata", SRODATA, rodata->vaddr + rodata->len);
  1472  	xdefine("typelink", SRODATA, typelink->vaddr);
  1473  	xdefine("etypelink", SRODATA, typelink->vaddr + typelink->len);
  1474  	if(datarelro != nil) {
  1475  		xdefine("datarelro", SRODATA, datarelro->vaddr);
  1476  		xdefine("edatarelro", SRODATA, datarelro->vaddr + datarelro->len);
  1477  	}
  1478  
  1479  	sym = lookup("gcdata", 0);
  1480  	xdefine("egcdata", STYPE, symaddr(sym) + sym->size);
  1481  	lookup("egcdata", 0)->sect = sym->sect;
  1482  
  1483  	sym = lookup("gcbss", 0);
  1484  	xdefine("egcbss", STYPE, symaddr(sym) + sym->size);
  1485  	lookup("egcbss", 0)->sect = sym->sect;
  1486  
  1487  	xdefine("symtab", SRODATA, symtab->vaddr);
  1488  	xdefine("esymtab", SRODATA, symtab->vaddr + symtab->len);
  1489  	xdefine("pclntab", SRODATA, pclntab->vaddr);
  1490  	xdefine("epclntab", SRODATA, pclntab->vaddr + pclntab->len);
  1491  	xdefine("noptrdata", SNOPTRDATA, noptr->vaddr);
  1492  	xdefine("enoptrdata", SNOPTRDATA, noptr->vaddr + noptr->len);
  1493  	xdefine("bss", SBSS, bss->vaddr);
  1494  	xdefine("ebss", SBSS, bss->vaddr + bss->len);
  1495  	xdefine("data", SDATA, data->vaddr);
  1496  	xdefine("edata", SDATA, data->vaddr + data->len);
  1497  	xdefine("noptrbss", SNOPTRBSS, noptrbss->vaddr);
  1498  	xdefine("enoptrbss", SNOPTRBSS, noptrbss->vaddr + noptrbss->len);
  1499  	xdefine("end", SBSS, segdata.vaddr + segdata.len);
  1500  }