github.com/q45/go@v0.0.0-20151101211701-a4fb8c13db3f/src/cmd/link/internal/ld/ldmacho.go (about)

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