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