github.com/dannin/go@v0.0.0-20161031215817-d35dfd405eaa/src/cmd/link/internal/ld/ldmacho.go (about)

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