github.com/varialus/godfly@v0.0.0-20130904042352-1934f9f095ab/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  		sym->sym = s;
   615  		if(sym->sectnum == 0)	// undefined
   616  			continue;
   617  		if(sym->sectnum > c->seg.nsect) {
   618  			werrstr("reference to invalid section %d", sym->sectnum);
   619  			goto bad;
   620  		}
   621  		sect = &c->seg.sect[sym->sectnum-1];
   622  		outer = sect->sym;
   623  		if(outer == nil) {
   624  			werrstr("reference to invalid section %s/%s", sect->segname, sect->name);
   625  			continue;
   626  		}
   627  		if(s->outer != S) {
   628  			if(s->dupok)
   629  				continue;
   630  			diag("%s: duplicate symbol reference: %s in both %s and %s", pn, s->name, s->outer->name, sect->sym->name);
   631  			errorexit();
   632  		}
   633  		s->type = outer->type | SSUB;
   634  		s->sub = outer->sub;
   635  		outer->sub = s;
   636  		s->outer = outer;
   637  		s->value = sym->value - sect->addr;
   638  		if(!(s->cgoexport & CgoExportDynamic))
   639  			s->dynimplib = nil;	// satisfy dynimport
   640  		if(outer->type == STEXT) {
   641  			Prog *p;
   642  
   643  			if(s->text != P)
   644  				diag("%s sym#%d: duplicate definition of %s", pn, i, s->name);
   645  			// build a TEXT instruction with a unique pc
   646  			// just to make the rest of the linker happy.
   647  			// TODO: this is too 6l-specific ?
   648  			p = prg();
   649  			p->as = ATEXT;
   650  			p->from.type = D_EXTERN;
   651  			p->from.sym = s;
   652  			p->textflag = 7;
   653  			p->to.type = D_CONST;
   654  			p->link = nil;
   655  			p->pc = pc++;
   656  			s->text = p;
   657  		}
   658  		sym->sym = s;
   659  	}
   660  
   661  	// Sort outer lists by address, adding to textp.
   662  	// This keeps textp in increasing address order.
   663  	for(i=0; i<c->seg.nsect; i++) {
   664  		sect = &c->seg.sect[i];
   665  		if((s = sect->sym) == S)
   666  			continue;
   667  		if(s->sub) {
   668  			s->sub = listsort(s->sub, valuecmp, offsetof(Sym, sub));
   669  			
   670  			// assign sizes, now that we know symbols in sorted order.
   671  			for(s1 = s->sub; s1 != S; s1 = s1->sub) {
   672  				if(s1->sub)
   673  					s1->size = s1->sub->value - s1->value;
   674  				else
   675  					s1->size = s->value + s->size - s1->value;
   676  			}
   677  		}
   678  		if(s->type == STEXT) {
   679  			if(etextp)
   680  				etextp->next = s;
   681  			else
   682  				textp = s;
   683  			etextp = s;
   684  			for(s1 = s->sub; s1 != S; s1 = s1->sub) {
   685  				etextp->next = s1;
   686  				etextp = s1;
   687  			}
   688  		}
   689  	}
   690  
   691  	// load relocations
   692  	for(i=0; i<c->seg.nsect; i++) {
   693  		sect = &c->seg.sect[i];
   694  		if((s = sect->sym) == S)
   695  			continue;
   696  		macholoadrel(m, sect);
   697  		if(sect->rel == nil)
   698  			continue;
   699  		r = mal(sect->nreloc*sizeof r[0]);
   700  		rp = r;
   701  		rel = sect->rel;
   702  		for(j=0; j<sect->nreloc; j++, rel++) {
   703  			if(rel->scattered) {
   704  				int k;
   705  				MachoSect *ks;
   706  
   707  				if(thechar != '8') {
   708  					// mach-o only uses scattered relocation on 32-bit platforms
   709  					diag("unexpected scattered relocation");
   710  					continue;
   711  				}
   712  
   713  				// on 386, rewrite scattered 4/1 relocation and some
   714  				// scattered 2/1 relocation into the pseudo-pc-relative
   715  				// reference that it is.
   716  				// assume that the second in the pair is in this section
   717  				// and use that as the pc-relative base.
   718  				if(j+1 >= sect->nreloc) {
   719  					werrstr("unsupported scattered relocation %d", (int)rel->type);
   720  					goto bad;
   721  				}
   722  				if(!(rel+1)->scattered || (rel+1)->type != 1 ||
   723  				   (rel->type != 4 && rel->type != 2) ||
   724  				   (rel+1)->value < sect->addr || (rel+1)->value >= sect->addr+sect->size) {
   725  					werrstr("unsupported scattered relocation %d/%d", (int)rel->type, (int)(rel+1)->type);
   726  					goto bad;
   727  				}
   728  
   729  				rp->siz = rel->length;
   730  				rp->off = rel->addr;
   731  				
   732  				// NOTE(rsc): I haven't worked out why (really when)
   733  				// we should ignore the addend on a
   734  				// scattered relocation, but it seems that the
   735  				// common case is we ignore it.
   736  				// It's likely that this is not strictly correct
   737  				// and that the math should look something
   738  				// like the non-scattered case below.
   739  				rp->add = 0;
   740  				
   741  				// want to make it pc-relative aka relative to rp->off+4
   742  				// but the scatter asks for relative to off = (rel+1)->value - sect->addr.
   743  				// adjust rp->add accordingly.
   744  				rp->type = D_PCREL;
   745  				rp->add += (rp->off+4) - ((rel+1)->value - sect->addr);
   746  				
   747  				// now consider the desired symbol.
   748  				// find the section where it lives.
   749  				for(k=0; k<c->seg.nsect; k++) {
   750  					ks = &c->seg.sect[k];
   751  					if(ks->addr <= rel->value && rel->value < ks->addr+ks->size)
   752  						goto foundk;
   753  				}
   754  				werrstr("unsupported scattered relocation: invalid address %#ux", rel->addr);
   755  				goto bad;
   756  			foundk:
   757  				if(ks->sym != S) {
   758  					rp->sym = ks->sym;
   759  					rp->add += rel->value - ks->addr;
   760  				} else if(strcmp(ks->segname, "__IMPORT") == 0 && strcmp(ks->name, "__pointers") == 0) {
   761  					// handle reference to __IMPORT/__pointers.
   762  					// how much worse can this get?
   763  					// why are we supporting 386 on the mac anyway?
   764  					rp->type = 512 + MACHO_FAKE_GOTPCREL;
   765  					// figure out which pointer this is a reference to.
   766  					k = ks->res1 + (rel->value - ks->addr) / 4;
   767  					// load indirect table for __pointers
   768  					// fetch symbol number
   769  					if(dsymtab == nil || k < 0 || k >= dsymtab->nindirectsyms || dsymtab->indir == nil) {
   770  						werrstr("invalid scattered relocation: indirect symbol reference out of range");
   771  						goto bad;
   772  					}
   773  					k = dsymtab->indir[k];
   774  					if(k < 0 || k >= symtab->nsym) {
   775  						werrstr("invalid scattered relocation: symbol reference out of range");
   776  						goto bad;
   777  					}
   778  					rp->sym = symtab->sym[k].sym;
   779  				} else {
   780  					werrstr("unsupported scattered relocation: reference to %s/%s", ks->segname, ks->name);
   781  					goto bad;
   782  				}
   783  				rp++;
   784  				// skip #1 of 2 rel; continue skips #2 of 2.
   785  				rel++;
   786  				j++;
   787  				continue;
   788  			}
   789  
   790  			rp->siz = rel->length;
   791  			rp->type = 512 + (rel->type<<1) + rel->pcrel;
   792  			rp->off = rel->addr;
   793  
   794  			// Handle X86_64_RELOC_SIGNED referencing a section (rel->extrn == 0).
   795  			if (thechar == '6' && rel->extrn == 0 && rel->type == 1) {
   796  				// Calculate the addend as the offset into the section.
   797  				//
   798  				// The rip-relative offset stored in the object file is encoded
   799  				// as follows:
   800  				//    
   801  				//    movsd	0x00000360(%rip),%xmm0
   802  				//
   803  				// To get the absolute address of the value this rip-relative address is pointing
   804  				// to, we must add the address of the next instruction to it. This is done by
   805  				// taking the address of the relocation and adding 4 to it (since the rip-relative
   806  				// offset can at most be 32 bits long).  To calculate the offset into the section the
   807  				// relocation is referencing, we subtract the vaddr of the start of the referenced
   808  				// section found in the original object file.
   809  				//
   810  				// [For future reference, see Darwin's /usr/include/mach-o/x86_64/reloc.h]
   811  				secaddr = c->seg.sect[rel->symnum-1].addr;
   812  				rp->add = (int32)e->e32(s->p+rp->off) + rp->off + 4 - secaddr;
   813  			} else
   814  				rp->add = (int32)e->e32(s->p+rp->off);
   815  
   816  			// For i386 Mach-O PC-relative, the addend is written such that
   817  			// it *is* the PC being subtracted.  Use that to make
   818  			// it match our version of PC-relative.
   819  			if(rel->pcrel && thechar == '8')
   820  				rp->add += rp->off+rp->siz;
   821  			if(!rel->extrn) {
   822  				if(rel->symnum < 1 || rel->symnum > c->seg.nsect) {
   823  					werrstr("invalid relocation: section reference out of range %d vs %d", rel->symnum, c->seg.nsect);
   824  					goto bad;
   825  				}
   826  				rp->sym = c->seg.sect[rel->symnum-1].sym;
   827  				if(rp->sym == nil) {
   828  					werrstr("invalid relocation: %s", c->seg.sect[rel->symnum-1].name);
   829  					goto bad;
   830  				}
   831  				// References to symbols in other sections
   832  				// include that information in the addend.
   833  				// We only care about the delta from the 
   834  				// section base.
   835  				if(thechar == '8')
   836  					rp->add -= c->seg.sect[rel->symnum-1].addr;
   837  			} else {
   838  				if(rel->symnum >= symtab->nsym) {
   839  					werrstr("invalid relocation: symbol reference out of range");
   840  					goto bad;
   841  				}
   842  				rp->sym = symtab->sym[rel->symnum].sym;
   843  			}
   844  			rp++;
   845  		}			
   846  		qsort(r, rp - r, sizeof r[0], rbyoff);
   847  		s->r = r;
   848  		s->nr = rp - r;
   849  	}
   850  	return;
   851  
   852  bad:
   853  	diag("%s: malformed mach-o file: %r", pn);
   854  }