github.com/rohankumardubey/syslog-redirector-golang@v0.0.0-20140320174030-4859f03d829a/src/cmd/ld/ldmacho.c (about)

     1  /*
     2  Derived from Plan 9 from User Space's src/libmach/elf.h, elf.c
     3  http://code.swtch.com/plan9port/src/tip/src/libmach/
     4  
     5  	Copyright © 2004 Russ Cox.
     6  	Portions Copyright © 2008-2010 Google Inc.
     7  	Portions Copyright © 2010 The Go Authors.
     8  
     9  Permission is hereby granted, free of charge, to any person obtaining a copy
    10  of this software and associated documentation files (the "Software"), to deal
    11  in the Software without restriction, including without limitation the rights
    12  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    13  copies of the Software, and to permit persons to whom the Software is
    14  furnished to do so, subject to the following conditions:
    15  
    16  The above copyright notice and this permission notice shall be included in
    17  all copies or substantial portions of the Software.
    18  
    19  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    20  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    21  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
    22  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    23  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    24  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    25  THE SOFTWARE.
    26  */
    27  
    28  #include	"l.h"
    29  #include	"lib.h"
    30  
    31  enum {
    32  	MACHO_FAKE_GOTPCREL = 100,	// from macho.h
    33  	
    34  	N_EXT = 0x01,
    35  	N_TYPE = 0x1e,
    36  	N_STAB = 0xe0,
    37  };
    38  
    39  typedef struct MachoObj MachoObj;
    40  typedef struct MachoCmd MachoCmd;
    41  typedef struct MachoSeg MachoSeg;
    42  typedef struct MachoSect MachoSect;
    43  typedef struct MachoRel MachoRel;
    44  typedef struct MachoSymtab MachoSymtab;
    45  typedef struct MachoSym MachoSym;
    46  typedef struct MachoDysymtab MachoDysymtab;
    47  
    48  enum
    49  {
    50  	MachoCpuVax = 1,
    51  	MachoCpu68000 = 6,
    52  	MachoCpu386 = 7,
    53  	MachoCpuAmd64 = 0x1000007,
    54  	MachoCpuMips = 8,
    55  	MachoCpu98000 = 10,
    56  	MachoCpuHppa = 11,
    57  	MachoCpuArm = 12,
    58  	MachoCpu88000 = 13,
    59  	MachoCpuSparc = 14,
    60  	MachoCpu860 = 15,
    61  	MachoCpuAlpha = 16,
    62  	MachoCpuPower = 18,
    63  
    64  	MachoCmdSegment = 1,
    65  	MachoCmdSymtab = 2,
    66  	MachoCmdSymseg = 3,
    67  	MachoCmdThread = 4,
    68  	MachoCmdDysymtab = 11,
    69  	MachoCmdSegment64 = 25,
    70  
    71  	MachoFileObject = 1,
    72  	MachoFileExecutable = 2,
    73  	MachoFileFvmlib = 3,
    74  	MachoFileCore = 4,
    75  	MachoFilePreload = 5,
    76  };
    77  
    78  struct MachoSeg
    79  {
    80  	char name[16+1];
    81  	uint64 vmaddr;
    82  	uint64 vmsize;
    83  	uint32 fileoff;
    84  	uint32 filesz;
    85  	uint32 maxprot;
    86  	uint32 initprot;
    87  	uint32 nsect;
    88  	uint32 flags;
    89  	MachoSect *sect;
    90  };
    91  
    92  struct MachoSect
    93  {
    94  	char	name[16+1];
    95  	char	segname[16+1];
    96  	uint64 addr;
    97  	uint64 size;
    98  	uint32 off;
    99  	uint32 align;
   100  	uint32 reloff;
   101  	uint32 nreloc;
   102  	uint32 flags;
   103  	uint32 res1;
   104  	uint32 res2;
   105  	Sym *sym;
   106  	
   107  	MachoRel *rel;
   108  };
   109  
   110  struct MachoRel
   111  {
   112  	uint32 addr;
   113  	uint32 symnum;
   114  	uint8 pcrel;
   115  	uint8 length;
   116  	uint8 extrn;
   117  	uint8 type;
   118  	uint8 scattered;
   119  	uint32 value;
   120  };
   121  
   122  struct MachoSymtab
   123  {
   124  	uint32 symoff;
   125  	uint32 nsym;
   126  	uint32 stroff;
   127  	uint32 strsize;
   128  	
   129  	char *str;
   130  	MachoSym *sym;
   131  };
   132  
   133  struct MachoSym
   134  {
   135  	char *name;
   136  	uint8 type;
   137  	uint8 sectnum;
   138  	uint16 desc;
   139  	char kind;
   140  	uint64 value;
   141  	Sym *sym;
   142  };
   143  
   144  struct MachoDysymtab
   145  {
   146  	uint32 ilocalsym;
   147  	uint32 nlocalsym;
   148  	uint32 iextdefsym;
   149  	uint32 nextdefsym;
   150  	uint32 iundefsym;
   151  	uint32 nundefsym;
   152  	uint32 tocoff;
   153  	uint32 ntoc;
   154  	uint32 modtaboff;
   155  	uint32 nmodtab;
   156  	uint32 extrefsymoff;
   157  	uint32 nextrefsyms;
   158  	uint32 indirectsymoff;
   159  	uint32 nindirectsyms;
   160  	uint32 extreloff;
   161  	uint32 nextrel;
   162  	uint32 locreloff;
   163  	uint32 nlocrel;
   164  	uint32 *indir;
   165  };
   166  
   167  struct MachoCmd
   168  {
   169  	int type;
   170  	uint32 off;
   171  	uint32 size;
   172  	MachoSeg seg;
   173  	MachoSymtab sym;
   174  	MachoDysymtab dsym;
   175  };
   176  
   177  struct MachoObj
   178  {
   179  	Biobuf	*f;
   180  	int64	base;	// off in f where Mach-O begins
   181  	int64	len;		// length of Mach-O
   182  	int is64;
   183  	char	*name;
   184  
   185  	Endian	*e;
   186  	uint cputype;
   187  	uint subcputype;
   188  	uint32 filetype;
   189  	uint32 flags;
   190  	MachoCmd *cmd;
   191  	uint ncmd;
   192  };
   193  
   194  static int
   195  unpackcmd(uchar *p, MachoObj *m, MachoCmd *c, uint type, uint sz)
   196  {
   197  	uint32 (*e4)(uchar*);
   198  	uint64 (*e8)(uchar*);
   199  	MachoSect *s;
   200  	int i;
   201  
   202  	e4 = m->e->e32;
   203  	e8 = m->e->e64;
   204  
   205  	c->type = type;
   206  	c->size = sz;
   207  	switch(type){
   208  	default:
   209  		return -1;
   210  	case MachoCmdSegment:
   211  		if(sz < 56)
   212  			return -1;
   213  		strecpy(c->seg.name, c->seg.name+sizeof c->seg.name, (char*)p+8);
   214  		c->seg.vmaddr = e4(p+24);
   215  		c->seg.vmsize = e4(p+28);
   216  		c->seg.fileoff = e4(p+32);
   217  		c->seg.filesz = e4(p+36);
   218  		c->seg.maxprot = e4(p+40);
   219  		c->seg.initprot = e4(p+44);
   220  		c->seg.nsect = e4(p+48);
   221  		c->seg.flags = e4(p+52);
   222  		c->seg.sect = mal(c->seg.nsect * sizeof c->seg.sect[0]);
   223  		if(sz < 56+c->seg.nsect*68)
   224  			return -1;
   225  		p += 56;
   226  		for(i=0; i<c->seg.nsect; i++) {
   227  			s = &c->seg.sect[i];
   228  			strecpy(s->name, s->name+sizeof s->name, (char*)p+0);
   229  			strecpy(s->segname, s->segname+sizeof s->segname, (char*)p+16);
   230  			s->addr = e4(p+32);
   231  			s->size = e4(p+36);
   232  			s->off = e4(p+40);
   233  			s->align = e4(p+44);
   234  			s->reloff = e4(p+48);
   235  			s->nreloc = e4(p+52);
   236  			s->flags = e4(p+56);
   237  			s->res1 = e4(p+60);
   238  			s->res2 = e4(p+64);
   239  			p += 68;
   240  		}
   241  		break;
   242  	case MachoCmdSegment64:
   243  		if(sz < 72)
   244  			return -1;
   245  		strecpy(c->seg.name, c->seg.name+sizeof c->seg.name, (char*)p+8);
   246  		c->seg.vmaddr = e8(p+24);
   247  		c->seg.vmsize = e8(p+32);
   248  		c->seg.fileoff = e8(p+40);
   249  		c->seg.filesz = e8(p+48);
   250  		c->seg.maxprot = e4(p+56);
   251  		c->seg.initprot = e4(p+60);
   252  		c->seg.nsect = e4(p+64);
   253  		c->seg.flags = e4(p+68);
   254  		c->seg.sect = mal(c->seg.nsect * sizeof c->seg.sect[0]);
   255  		if(sz < 72+c->seg.nsect*80)
   256  			return -1;
   257  		p += 72;
   258  		for(i=0; i<c->seg.nsect; i++) {
   259  			s = &c->seg.sect[i];
   260  			strecpy(s->name, s->name+sizeof s->name, (char*)p+0);
   261  			strecpy(s->segname, s->segname+sizeof s->segname, (char*)p+16);
   262  			s->addr = e8(p+32);
   263  			s->size = e8(p+40);
   264  			s->off = e4(p+48);
   265  			s->align = e4(p+52);
   266  			s->reloff = e4(p+56);
   267  			s->nreloc = e4(p+60);
   268  			s->flags = e4(p+64);
   269  			s->res1 = e4(p+68);
   270  			s->res2 = e4(p+72);
   271  			// p+76 is reserved
   272  			p += 80;
   273  		}
   274  		break;
   275  	case MachoCmdSymtab:
   276  		if(sz < 24)
   277  			return -1;
   278  		c->sym.symoff = e4(p+8);
   279  		c->sym.nsym = e4(p+12);
   280  		c->sym.stroff = e4(p+16);
   281  		c->sym.strsize = e4(p+20);
   282  		break;
   283  	case MachoCmdDysymtab:
   284  		if(sz < 80)
   285  			return -1;
   286  		c->dsym.ilocalsym = e4(p+8);
   287  		c->dsym.nlocalsym = e4(p+12);
   288  		c->dsym.iextdefsym = e4(p+16);
   289  		c->dsym.nextdefsym = e4(p+20);
   290  		c->dsym.iundefsym = e4(p+24);
   291  		c->dsym.nundefsym = e4(p+28);
   292  		c->dsym.tocoff = e4(p+32);
   293  		c->dsym.ntoc = e4(p+36);
   294  		c->dsym.modtaboff = e4(p+40);
   295  		c->dsym.nmodtab = e4(p+44);
   296  		c->dsym.extrefsymoff = e4(p+48);
   297  		c->dsym.nextrefsyms = e4(p+52);
   298  		c->dsym.indirectsymoff = e4(p+56);
   299  		c->dsym.nindirectsyms = e4(p+60);
   300  		c->dsym.extreloff = e4(p+64);
   301  		c->dsym.nextrel = e4(p+68);
   302  		c->dsym.locreloff = e4(p+72);
   303  		c->dsym.nlocrel = e4(p+76);
   304  		break;
   305  	}
   306  	return 0;
   307  }
   308  
   309  static int
   310  macholoadrel(MachoObj *m, MachoSect *sect)
   311  {
   312  	MachoRel *rel, *r;
   313  	uchar *buf, *p;
   314  	int i, n;
   315  	uint32 v;
   316  	
   317  	if(sect->rel != nil || sect->nreloc == 0)
   318  		return 0;
   319  	rel = mal(sect->nreloc * sizeof r[0]);
   320  	n = sect->nreloc * 8;
   321  	buf = mal(n);
   322  	if(Bseek(m->f, m->base + sect->reloff, 0) < 0 || Bread(m->f, buf, n) != n)
   323  		return -1;
   324  	for(i=0; i<sect->nreloc; i++) {
   325  		r = &rel[i];
   326  		p = buf+i*8;
   327  		r->addr = m->e->e32(p);
   328  		
   329  		// TODO(rsc): Wrong interpretation for big-endian bitfields?
   330  		if(r->addr & 0x80000000) {
   331  			// scatterbrained relocation
   332  			r->scattered = 1;
   333  			v = r->addr >> 24;
   334  			r->addr &= 0xFFFFFF;
   335  			r->type = v & 0xF;
   336  			v >>= 4;
   337  			r->length = 1<<(v&3);
   338  			v >>= 2;
   339  			r->pcrel = v & 1;
   340  			r->value = m->e->e32(p+4);
   341  		} else {
   342  			v = m->e->e32(p+4);
   343  			r->symnum = v & 0xFFFFFF;
   344  			v >>= 24;
   345  			r->pcrel = v&1;
   346  			v >>= 1;
   347  			r->length = 1<<(v&3);
   348  			v >>= 2;
   349  			r->extrn = v&1;
   350  			v >>= 1;
   351  			r->type = v;
   352  		}
   353  	}
   354  	sect->rel = rel;
   355  	return 0;
   356  }
   357  
   358  static int
   359  macholoaddsym(MachoObj *m, MachoDysymtab *d)
   360  {
   361  	uchar *p;
   362  	int i, n;
   363  	
   364  	n = d->nindirectsyms;
   365  	
   366  	p = mal(n*4);
   367  	if(Bseek(m->f, m->base + d->indirectsymoff, 0) < 0 || Bread(m->f, p, n*4) != n*4)
   368  		return -1;
   369  	
   370  	d->indir = (uint32*)p;
   371  	for(i=0; i<n; i++)
   372  		d->indir[i] = m->e->e32(p+4*i);
   373  	return 0;
   374  }
   375  
   376  static int 
   377  macholoadsym(MachoObj *m, MachoSymtab *symtab)
   378  {
   379  	char *strbuf;
   380  	uchar *symbuf, *p;
   381  	int i, n, symsize;
   382  	MachoSym *sym, *s;
   383  	uint32 v;
   384  
   385  	if(symtab->sym != nil)
   386  		return 0;
   387  
   388  	strbuf = mal(symtab->strsize);
   389  	if(Bseek(m->f, m->base + symtab->stroff, 0) < 0 || Bread(m->f, strbuf, symtab->strsize) != symtab->strsize)
   390  		return -1;
   391  	
   392  	symsize = 12;
   393  	if(m->is64)
   394  		symsize = 16;
   395  	n = symtab->nsym * symsize;
   396  	symbuf = mal(n);
   397  	if(Bseek(m->f, m->base + symtab->symoff, 0) < 0 || Bread(m->f, symbuf, n) != n)
   398  		return -1;
   399  	sym = mal(symtab->nsym * sizeof sym[0]);
   400  	p = symbuf;
   401  	for(i=0; i<symtab->nsym; i++) {
   402  		s = &sym[i];
   403  		v = m->e->e32(p);
   404  		if(v >= symtab->strsize)
   405  			return -1;
   406  		s->name = strbuf + v;
   407  		s->type = p[4];
   408  		s->sectnum = p[5];
   409  		s->desc = m->e->e16(p+6);
   410  		if(m->is64)
   411  			s->value = m->e->e64(p+8);
   412  		else
   413  			s->value = m->e->e32(p+8);
   414  		p += symsize;
   415  	}
   416  	symtab->str = strbuf;
   417  	symtab->sym = sym;
   418  	return 0;
   419  }
   420  
   421  void
   422  ldmacho(Biobuf *f, char *pkg, int64 len, char *pn)
   423  {
   424  	int i, j, is64;
   425  	uint64 secaddr;
   426  	uchar hdr[7*4], *cmdp;
   427  	uchar tmp[4];
   428  	uchar *dat;
   429  	ulong ncmd, cmdsz, ty, sz, off;
   430  	MachoObj *m;
   431  	Endian *e;
   432  	int64 base;
   433  	MachoSect *sect;
   434  	MachoRel *rel;
   435  	Sym *s, *s1, *outer;
   436  	MachoCmd *c;
   437  	MachoSymtab *symtab;
   438  	MachoDysymtab *dsymtab;
   439  	MachoSym *sym;
   440  	Reloc *r, *rp;
   441  	char *name;
   442  
   443  	version++;
   444  	base = Boffset(f);
   445  	if(Bread(f, hdr, sizeof hdr) != sizeof hdr)
   446  		goto bad;
   447  
   448  	if((be.e32(hdr)&~1) == 0xFEEDFACE){
   449  		e = &be;
   450  	}else if((le.e32(hdr)&~1) == 0xFEEDFACE){
   451  		e = &le;
   452  	}else{
   453  		werrstr("bad magic - not mach-o file");
   454  		goto bad;
   455  	}
   456  
   457  	is64 = e->e32(hdr) == 0xFEEDFACF;
   458  	ncmd = e->e32(hdr+4*4);
   459  	cmdsz = e->e32(hdr+5*4);
   460  	if(ncmd > 0x10000 || cmdsz >= 0x01000000){
   461  		werrstr("implausible mach-o header ncmd=%lud cmdsz=%lud", ncmd, cmdsz);
   462  		goto bad;
   463  	}
   464  	if(is64)
   465  		Bread(f, tmp, 4);	// skip reserved word in header
   466  
   467  	m = mal(sizeof(*m)+ncmd*sizeof(MachoCmd)+cmdsz);
   468  	m->f = f;
   469  	m->e = e;
   470  	m->cputype = e->e32(hdr+1*4);
   471  	m->subcputype = e->e32(hdr+2*4);
   472  	m->filetype = e->e32(hdr+3*4);
   473  	m->ncmd = ncmd;
   474  	m->flags = e->e32(hdr+6*4);
   475  	m->is64 = is64;
   476  	m->base = base;
   477  	m->len = len;
   478  	m->name = pn;
   479  	
   480  	switch(thechar) {
   481  	default:
   482  		diag("%s: mach-o %s unimplemented", pn, thestring);
   483  		return;
   484  	case '6':
   485  		if(e != &le || m->cputype != MachoCpuAmd64) {
   486  			diag("%s: mach-o object but not amd64", pn);
   487  			return;
   488  		}
   489  		break;
   490  	case '8':
   491  		if(e != &le || m->cputype != MachoCpu386) {
   492  			diag("%s: mach-o object but not 386", pn);
   493  			return;
   494  		}
   495  		break;
   496  	}
   497  
   498  	m->cmd = (MachoCmd*)(m+1);
   499  	off = sizeof hdr;
   500  	cmdp = (uchar*)(m->cmd+ncmd);
   501  	if(Bread(f, cmdp, cmdsz) != cmdsz){
   502  		werrstr("reading cmds: %r");
   503  		goto bad;
   504  	}
   505  
   506  	// read and parse load commands
   507  	c = nil;
   508  	symtab = nil;
   509  	dsymtab = nil;
   510  	for(i=0; i<ncmd; i++){
   511  		ty = e->e32(cmdp);
   512  		sz = e->e32(cmdp+4);
   513  		m->cmd[i].off = off;
   514  		unpackcmd(cmdp, m, &m->cmd[i], ty, sz);
   515  		cmdp += sz;
   516  		off += sz;
   517  		if(ty == MachoCmdSymtab) {
   518  			if(symtab != nil) {
   519  				werrstr("multiple symbol tables");
   520  				goto bad;
   521  			}
   522  			symtab = &m->cmd[i].sym;
   523  			macholoadsym(m, symtab);
   524  		}
   525  		if(ty == MachoCmdDysymtab) {
   526  			dsymtab = &m->cmd[i].dsym;
   527  			macholoaddsym(m, dsymtab);
   528  		}
   529  		if((is64 && ty == MachoCmdSegment64) || (!is64 && ty == MachoCmdSegment)) {
   530  			if(c != nil) {
   531  				werrstr("multiple load commands");
   532  				goto bad;
   533  			}
   534  			c = &m->cmd[i];
   535  		}
   536  	}
   537  
   538  	// load text and data segments into memory.
   539  	// they are not as small as the load commands, but we'll need
   540  	// the memory anyway for the symbol images, so we might
   541  	// as well use one large chunk.
   542  	if(c == nil) {
   543  		werrstr("no load command");
   544  		goto bad;
   545  	}
   546  	if(symtab == nil) {
   547  		// our work is done here - no symbols means nothing can refer to this file
   548  		return;
   549  	}
   550  
   551  	if(c->seg.fileoff+c->seg.filesz >= len) {
   552  		werrstr("load segment out of range");
   553  		goto bad;
   554  	}
   555  
   556  	dat = mal(c->seg.filesz);
   557  	if(Bseek(f, m->base + c->seg.fileoff, 0) < 0 || Bread(f, dat, c->seg.filesz) != c->seg.filesz) {
   558  		werrstr("cannot load object data: %r");
   559  		goto bad;
   560  	}
   561  	
   562  	for(i=0; i<c->seg.nsect; i++) {
   563  		sect = &c->seg.sect[i];
   564  		if(strcmp(sect->segname, "__TEXT") != 0 && strcmp(sect->segname, "__DATA") != 0)
   565  			continue;
   566  		if(strcmp(sect->name, "__eh_frame") == 0)
   567  			continue;
   568  		name = smprint("%s(%s/%s)", pkg, sect->segname, sect->name);
   569  		s = lookup(name, version);
   570  		if(s->type != 0) {
   571  			werrstr("duplicate %s/%s", sect->segname, sect->name);
   572  			goto bad;
   573  		}
   574  		free(name);
   575  
   576  		s->np = sect->size;
   577  		s->size = s->np;
   578  		if((sect->flags & 0xff) == 1) // S_ZEROFILL
   579  			s->p = mal(s->size);
   580  		else {
   581  			s->p = dat + sect->addr - c->seg.vmaddr;
   582  		}
   583  		
   584  		if(strcmp(sect->segname, "__TEXT") == 0) {
   585  			if(strcmp(sect->name, "__text") == 0)
   586  				s->type = STEXT;
   587  			else
   588  				s->type = SRODATA;
   589  		} else {
   590  			if (strcmp(sect->name, "__bss") == 0) {
   591  				s->type = SBSS;
   592  				s->np = 0;
   593  			} else
   594  				s->type = SDATA;
   595  		}
   596  		sect->sym = s;
   597  	}
   598  	
   599  	// enter sub-symbols into symbol table.
   600  	// have to guess sizes from next symbol.
   601  	for(i=0; i<symtab->nsym; i++) {
   602  		int v;
   603  		sym = &symtab->sym[i];
   604  		if(sym->type&N_STAB)
   605  			continue;
   606  		// TODO: check sym->type against outer->type.
   607  		name = sym->name;
   608  		if(name[0] == '_' && name[1] != '\0')
   609  			name++;
   610  		v = 0;
   611  		if(!(sym->type&N_EXT))
   612  			v = version;
   613  		s = lookup(name, v);
   614  		if(!(sym->type&N_EXT))
   615  			s->dupok = 1;
   616  		sym->sym = s;
   617  		if(sym->sectnum == 0)	// undefined
   618  			continue;
   619  		if(sym->sectnum > c->seg.nsect) {
   620  			werrstr("reference to invalid section %d", sym->sectnum);
   621  			goto bad;
   622  		}
   623  		sect = &c->seg.sect[sym->sectnum-1];
   624  		outer = sect->sym;
   625  		if(outer == nil) {
   626  			werrstr("reference to invalid section %s/%s", sect->segname, sect->name);
   627  			continue;
   628  		}
   629  		if(s->outer != S) {
   630  			if(s->dupok)
   631  				continue;
   632  			diag("%s: duplicate symbol reference: %s in both %s and %s", pn, s->name, s->outer->name, sect->sym->name);
   633  			errorexit();
   634  		}
   635  		s->type = outer->type | SSUB;
   636  		s->sub = outer->sub;
   637  		outer->sub = s;
   638  		s->outer = outer;
   639  		s->value = sym->value - sect->addr;
   640  		if(!(s->cgoexport & CgoExportDynamic))
   641  			s->dynimplib = nil;	// satisfy dynimport
   642  		if(outer->type == STEXT) {
   643  			Prog *p;
   644  
   645  			if(s->text != P)
   646  				diag("%s sym#%d: duplicate definition of %s", pn, i, s->name);
   647  			// build a TEXT instruction with a unique pc
   648  			// just to make the rest of the linker happy.
   649  			// TODO: this is too 6l-specific ?
   650  			p = prg();
   651  			p->as = ATEXT;
   652  			p->from.type = D_EXTERN;
   653  			p->from.sym = s;
   654  			p->textflag = 7;
   655  			p->to.type = D_CONST;
   656  			p->link = nil;
   657  			p->pc = pc++;
   658  			s->text = p;
   659  		}
   660  		sym->sym = s;
   661  	}
   662  
   663  	// Sort outer lists by address, adding to textp.
   664  	// This keeps textp in increasing address order.
   665  	for(i=0; i<c->seg.nsect; i++) {
   666  		sect = &c->seg.sect[i];
   667  		if((s = sect->sym) == S)
   668  			continue;
   669  		if(s->sub) {
   670  			s->sub = listsort(s->sub, valuecmp, offsetof(Sym, sub));
   671  			
   672  			// assign sizes, now that we know symbols in sorted order.
   673  			for(s1 = s->sub; s1 != S; s1 = s1->sub) {
   674  				if(s1->sub)
   675  					s1->size = s1->sub->value - s1->value;
   676  				else
   677  					s1->size = s->value + s->size - s1->value;
   678  			}
   679  		}
   680  		if(s->type == STEXT) {
   681  			if(etextp)
   682  				etextp->next = s;
   683  			else
   684  				textp = s;
   685  			etextp = s;
   686  			for(s1 = s->sub; s1 != S; s1 = s1->sub) {
   687  				etextp->next = s1;
   688  				etextp = s1;
   689  			}
   690  		}
   691  	}
   692  
   693  	// load relocations
   694  	for(i=0; i<c->seg.nsect; i++) {
   695  		sect = &c->seg.sect[i];
   696  		if((s = sect->sym) == S)
   697  			continue;
   698  		macholoadrel(m, sect);
   699  		if(sect->rel == nil)
   700  			continue;
   701  		r = mal(sect->nreloc*sizeof r[0]);
   702  		rp = r;
   703  		rel = sect->rel;
   704  		for(j=0; j<sect->nreloc; j++, rel++) {
   705  			if(rel->scattered) {
   706  				int k;
   707  				MachoSect *ks;
   708  
   709  				if(thechar != '8') {
   710  					// mach-o only uses scattered relocation on 32-bit platforms
   711  					diag("unexpected scattered relocation");
   712  					continue;
   713  				}
   714  
   715  				// on 386, rewrite scattered 4/1 relocation and some
   716  				// scattered 2/1 relocation into the pseudo-pc-relative
   717  				// reference that it is.
   718  				// assume that the second in the pair is in this section
   719  				// and use that as the pc-relative base.
   720  				if(j+1 >= sect->nreloc) {
   721  					werrstr("unsupported scattered relocation %d", (int)rel->type);
   722  					goto bad;
   723  				}
   724  				if(!(rel+1)->scattered || (rel+1)->type != 1 ||
   725  				   (rel->type != 4 && rel->type != 2) ||
   726  				   (rel+1)->value < sect->addr || (rel+1)->value >= sect->addr+sect->size) {
   727  					werrstr("unsupported scattered relocation %d/%d", (int)rel->type, (int)(rel+1)->type);
   728  					goto bad;
   729  				}
   730  
   731  				rp->siz = rel->length;
   732  				rp->off = rel->addr;
   733  				
   734  				// NOTE(rsc): I haven't worked out why (really when)
   735  				// we should ignore the addend on a
   736  				// scattered relocation, but it seems that the
   737  				// common case is we ignore it.
   738  				// It's likely that this is not strictly correct
   739  				// and that the math should look something
   740  				// like the non-scattered case below.
   741  				rp->add = 0;
   742  				
   743  				// want to make it pc-relative aka relative to rp->off+4
   744  				// but the scatter asks for relative to off = (rel+1)->value - sect->addr.
   745  				// adjust rp->add accordingly.
   746  				rp->type = D_PCREL;
   747  				rp->add += (rp->off+4) - ((rel+1)->value - sect->addr);
   748  				
   749  				// now consider the desired symbol.
   750  				// find the section where it lives.
   751  				for(k=0; k<c->seg.nsect; k++) {
   752  					ks = &c->seg.sect[k];
   753  					if(ks->addr <= rel->value && rel->value < ks->addr+ks->size)
   754  						goto foundk;
   755  				}
   756  				werrstr("unsupported scattered relocation: invalid address %#ux", rel->addr);
   757  				goto bad;
   758  			foundk:
   759  				if(ks->sym != S) {
   760  					rp->sym = ks->sym;
   761  					rp->add += rel->value - ks->addr;
   762  				} else if(strcmp(ks->segname, "__IMPORT") == 0 && strcmp(ks->name, "__pointers") == 0) {
   763  					// handle reference to __IMPORT/__pointers.
   764  					// how much worse can this get?
   765  					// why are we supporting 386 on the mac anyway?
   766  					rp->type = 512 + MACHO_FAKE_GOTPCREL;
   767  					// figure out which pointer this is a reference to.
   768  					k = ks->res1 + (rel->value - ks->addr) / 4;
   769  					// load indirect table for __pointers
   770  					// fetch symbol number
   771  					if(dsymtab == nil || k < 0 || k >= dsymtab->nindirectsyms || dsymtab->indir == nil) {
   772  						werrstr("invalid scattered relocation: indirect symbol reference out of range");
   773  						goto bad;
   774  					}
   775  					k = dsymtab->indir[k];
   776  					if(k < 0 || k >= symtab->nsym) {
   777  						werrstr("invalid scattered relocation: symbol reference out of range");
   778  						goto bad;
   779  					}
   780  					rp->sym = symtab->sym[k].sym;
   781  				} else {
   782  					werrstr("unsupported scattered relocation: reference to %s/%s", ks->segname, ks->name);
   783  					goto bad;
   784  				}
   785  				rp++;
   786  				// skip #1 of 2 rel; continue skips #2 of 2.
   787  				rel++;
   788  				j++;
   789  				continue;
   790  			}
   791  
   792  			rp->siz = rel->length;
   793  			rp->type = 512 + (rel->type<<1) + rel->pcrel;
   794  			rp->off = rel->addr;
   795  
   796  			// Handle X86_64_RELOC_SIGNED referencing a section (rel->extrn == 0).
   797  			if (thechar == '6' && rel->extrn == 0 && rel->type == 1) {
   798  				// Calculate the addend as the offset into the section.
   799  				//
   800  				// The rip-relative offset stored in the object file is encoded
   801  				// as follows:
   802  				//    
   803  				//    movsd	0x00000360(%rip),%xmm0
   804  				//
   805  				// To get the absolute address of the value this rip-relative address is pointing
   806  				// to, we must add the address of the next instruction to it. This is done by
   807  				// taking the address of the relocation and adding 4 to it (since the rip-relative
   808  				// offset can at most be 32 bits long).  To calculate the offset into the section the
   809  				// relocation is referencing, we subtract the vaddr of the start of the referenced
   810  				// section found in the original object file.
   811  				//
   812  				// [For future reference, see Darwin's /usr/include/mach-o/x86_64/reloc.h]
   813  				secaddr = c->seg.sect[rel->symnum-1].addr;
   814  				rp->add = (int32)e->e32(s->p+rp->off) + rp->off + 4 - secaddr;
   815  			} else
   816  				rp->add = (int32)e->e32(s->p+rp->off);
   817  
   818  			// For i386 Mach-O PC-relative, the addend is written such that
   819  			// it *is* the PC being subtracted.  Use that to make
   820  			// it match our version of PC-relative.
   821  			if(rel->pcrel && thechar == '8')
   822  				rp->add += rp->off+rp->siz;
   823  			if(!rel->extrn) {
   824  				if(rel->symnum < 1 || rel->symnum > c->seg.nsect) {
   825  					werrstr("invalid relocation: section reference out of range %d vs %d", rel->symnum, c->seg.nsect);
   826  					goto bad;
   827  				}
   828  				rp->sym = c->seg.sect[rel->symnum-1].sym;
   829  				if(rp->sym == nil) {
   830  					werrstr("invalid relocation: %s", c->seg.sect[rel->symnum-1].name);
   831  					goto bad;
   832  				}
   833  				// References to symbols in other sections
   834  				// include that information in the addend.
   835  				// We only care about the delta from the 
   836  				// section base.
   837  				if(thechar == '8')
   838  					rp->add -= c->seg.sect[rel->symnum-1].addr;
   839  			} else {
   840  				if(rel->symnum >= symtab->nsym) {
   841  					werrstr("invalid relocation: symbol reference out of range");
   842  					goto bad;
   843  				}
   844  				rp->sym = symtab->sym[rel->symnum].sym;
   845  			}
   846  			rp++;
   847  		}			
   848  		qsort(r, rp - r, sizeof r[0], rbyoff);
   849  		s->r = r;
   850  		s->nr = rp - r;
   851  	}
   852  	return;
   853  
   854  bad:
   855  	diag("%s: malformed mach-o file: %r", pn);
   856  }