github.com/stingnevermore/go@v0.0.0-20180120041312-3810f5bfed72/src/cmd/link/internal/loadmacho/ldmacho.go (about)

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