rsc.io/go@v0.0.0-20150416155037-e040fd465409/src/cmd/internal/ld/ldmacho.go (about)

     1  package ld
     2  
     3  import (
     4  	"encoding/binary"
     5  	"fmt"
     6  	"log"
     7  	"sort"
     8  )
     9  
    10  /*
    11  Derived from Plan 9 from User Space's src/libmach/elf.h, elf.c
    12  http://code.swtch.com/plan9port/src/tip/src/libmach/
    13  
    14  	Copyright © 2004 Russ Cox.
    15  	Portions Copyright © 2008-2010 Google Inc.
    16  	Portions Copyright © 2010 The Go Authors.
    17  
    18  Permission is hereby granted, free of charge, to any person obtaining a copy
    19  of this software and associated documentation files (the "Software"), to deal
    20  in the Software without restriction, including without limitation the rights
    21  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    22  copies of the Software, and to permit persons to whom the Software is
    23  furnished to do so, subject to the following conditions:
    24  
    25  The above copyright notice and this permission notice shall be included in
    26  all copies or substantial portions of the Software.
    27  
    28  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    29  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    30  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
    31  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    32  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    33  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    34  THE SOFTWARE.
    35  */
    36  const (
    37  	N_EXT  = 0x01
    38  	N_TYPE = 0x1e
    39  	N_STAB = 0xe0
    40  )
    41  
    42  type LdMachoObj struct {
    43  	f          *Biobuf
    44  	base       int64 // off in f where Mach-O begins
    45  	length     int64 // length of Mach-O
    46  	is64       bool
    47  	name       string
    48  	e          binary.ByteOrder
    49  	cputype    uint
    50  	subcputype uint
    51  	filetype   uint32
    52  	flags      uint32
    53  	cmd        []LdMachoCmd
    54  	ncmd       uint
    55  }
    56  
    57  type LdMachoCmd struct {
    58  	type_ int
    59  	off   uint32
    60  	size  uint32
    61  	seg   LdMachoSeg
    62  	sym   LdMachoSymtab
    63  	dsym  LdMachoDysymtab
    64  }
    65  
    66  type LdMachoSeg struct {
    67  	name     string
    68  	vmaddr   uint64
    69  	vmsize   uint64
    70  	fileoff  uint32
    71  	filesz   uint32
    72  	maxprot  uint32
    73  	initprot uint32
    74  	nsect    uint32
    75  	flags    uint32
    76  	sect     []LdMachoSect
    77  }
    78  
    79  type LdMachoSect struct {
    80  	name    string
    81  	segname string
    82  	addr    uint64
    83  	size    uint64
    84  	off     uint32
    85  	align   uint32
    86  	reloff  uint32
    87  	nreloc  uint32
    88  	flags   uint32
    89  	res1    uint32
    90  	res2    uint32
    91  	sym     *LSym
    92  	rel     []LdMachoRel
    93  }
    94  
    95  type LdMachoRel struct {
    96  	addr      uint32
    97  	symnum    uint32
    98  	pcrel     uint8
    99  	length    uint8
   100  	extrn     uint8
   101  	type_     uint8
   102  	scattered uint8
   103  	value     uint32
   104  }
   105  
   106  type LdMachoSymtab struct {
   107  	symoff  uint32
   108  	nsym    uint32
   109  	stroff  uint32
   110  	strsize uint32
   111  	str     []byte
   112  	sym     []LdMachoSym
   113  }
   114  
   115  type LdMachoSym struct {
   116  	name    string
   117  	type_   uint8
   118  	sectnum uint8
   119  	desc    uint16
   120  	kind    int8
   121  	value   uint64
   122  	sym     *LSym
   123  }
   124  
   125  type LdMachoDysymtab struct {
   126  	ilocalsym      uint32
   127  	nlocalsym      uint32
   128  	iextdefsym     uint32
   129  	nextdefsym     uint32
   130  	iundefsym      uint32
   131  	nundefsym      uint32
   132  	tocoff         uint32
   133  	ntoc           uint32
   134  	modtaboff      uint32
   135  	nmodtab        uint32
   136  	extrefsymoff   uint32
   137  	nextrefsyms    uint32
   138  	indirectsymoff uint32
   139  	nindirectsyms  uint32
   140  	extreloff      uint32
   141  	nextrel        uint32
   142  	locreloff      uint32
   143  	nlocrel        uint32
   144  	indir          []uint32
   145  }
   146  
   147  const (
   148  	LdMachoCpuVax         = 1
   149  	LdMachoCpu68000       = 6
   150  	LdMachoCpu386         = 7
   151  	LdMachoCpuAmd64       = 0x1000007
   152  	LdMachoCpuMips        = 8
   153  	LdMachoCpu98000       = 10
   154  	LdMachoCpuHppa        = 11
   155  	LdMachoCpuArm         = 12
   156  	LdMachoCpu88000       = 13
   157  	LdMachoCpuSparc       = 14
   158  	LdMachoCpu860         = 15
   159  	LdMachoCpuAlpha       = 16
   160  	LdMachoCpuPower       = 18
   161  	LdMachoCmdSegment     = 1
   162  	LdMachoCmdSymtab      = 2
   163  	LdMachoCmdSymseg      = 3
   164  	LdMachoCmdThread      = 4
   165  	LdMachoCmdDysymtab    = 11
   166  	LdMachoCmdSegment64   = 25
   167  	LdMachoFileObject     = 1
   168  	LdMachoFileExecutable = 2
   169  	LdMachoFileFvmlib     = 3
   170  	LdMachoFileCore       = 4
   171  	LdMachoFilePreload    = 5
   172  )
   173  
   174  func unpackcmd(p []byte, m *LdMachoObj, c *LdMachoCmd, type_ uint, sz uint) int {
   175  	e4 := m.e.Uint32
   176  	e8 := m.e.Uint64
   177  
   178  	c.type_ = int(type_)
   179  	c.size = uint32(sz)
   180  	switch type_ {
   181  	default:
   182  		return -1
   183  
   184  	case LdMachoCmdSegment:
   185  		if sz < 56 {
   186  			return -1
   187  		}
   188  		c.seg.name = cstring(p[8:24])
   189  		c.seg.vmaddr = uint64(e4(p[24:]))
   190  		c.seg.vmsize = uint64(e4(p[28:]))
   191  		c.seg.fileoff = e4(p[32:])
   192  		c.seg.filesz = e4(p[36:])
   193  		c.seg.maxprot = e4(p[40:])
   194  		c.seg.initprot = e4(p[44:])
   195  		c.seg.nsect = e4(p[48:])
   196  		c.seg.flags = e4(p[52:])
   197  		c.seg.sect = make([]LdMachoSect, c.seg.nsect)
   198  		if uint32(sz) < 56+c.seg.nsect*68 {
   199  			return -1
   200  		}
   201  		p = p[56:]
   202  		var s *LdMachoSect
   203  		for i := 0; uint32(i) < c.seg.nsect; i++ {
   204  			s = &c.seg.sect[i]
   205  			s.name = cstring(p[0:16])
   206  			s.segname = cstring(p[16:32])
   207  			s.addr = uint64(e4(p[32:]))
   208  			s.size = uint64(e4(p[36:]))
   209  			s.off = e4(p[40:])
   210  			s.align = e4(p[44:])
   211  			s.reloff = e4(p[48:])
   212  			s.nreloc = e4(p[52:])
   213  			s.flags = e4(p[56:])
   214  			s.res1 = e4(p[60:])
   215  			s.res2 = e4(p[64:])
   216  			p = p[68:]
   217  		}
   218  
   219  	case LdMachoCmdSegment64:
   220  		if sz < 72 {
   221  			return -1
   222  		}
   223  		c.seg.name = cstring(p[8:24])
   224  		c.seg.vmaddr = e8(p[24:])
   225  		c.seg.vmsize = e8(p[32:])
   226  		c.seg.fileoff = uint32(e8(p[40:]))
   227  		c.seg.filesz = uint32(e8(p[48:]))
   228  		c.seg.maxprot = e4(p[56:])
   229  		c.seg.initprot = e4(p[60:])
   230  		c.seg.nsect = e4(p[64:])
   231  		c.seg.flags = e4(p[68:])
   232  		c.seg.sect = make([]LdMachoSect, c.seg.nsect)
   233  		if uint32(sz) < 72+c.seg.nsect*80 {
   234  			return -1
   235  		}
   236  		p = p[72:]
   237  		var s *LdMachoSect
   238  		for i := 0; uint32(i) < c.seg.nsect; i++ {
   239  			s = &c.seg.sect[i]
   240  			s.name = cstring(p[0:16])
   241  			s.segname = cstring(p[16:32])
   242  			s.addr = e8(p[32:])
   243  			s.size = e8(p[40:])
   244  			s.off = e4(p[48:])
   245  			s.align = e4(p[52:])
   246  			s.reloff = e4(p[56:])
   247  			s.nreloc = e4(p[60:])
   248  			s.flags = e4(p[64:])
   249  			s.res1 = e4(p[68:])
   250  			s.res2 = e4(p[72:])
   251  
   252  			// p+76 is reserved
   253  			p = p[80:]
   254  		}
   255  
   256  	case LdMachoCmdSymtab:
   257  		if sz < 24 {
   258  			return -1
   259  		}
   260  		c.sym.symoff = e4(p[8:])
   261  		c.sym.nsym = e4(p[12:])
   262  		c.sym.stroff = e4(p[16:])
   263  		c.sym.strsize = e4(p[20:])
   264  
   265  	case LdMachoCmdDysymtab:
   266  		if sz < 80 {
   267  			return -1
   268  		}
   269  		c.dsym.ilocalsym = e4(p[8:])
   270  		c.dsym.nlocalsym = e4(p[12:])
   271  		c.dsym.iextdefsym = e4(p[16:])
   272  		c.dsym.nextdefsym = e4(p[20:])
   273  		c.dsym.iundefsym = e4(p[24:])
   274  		c.dsym.nundefsym = e4(p[28:])
   275  		c.dsym.tocoff = e4(p[32:])
   276  		c.dsym.ntoc = e4(p[36:])
   277  		c.dsym.modtaboff = e4(p[40:])
   278  		c.dsym.nmodtab = e4(p[44:])
   279  		c.dsym.extrefsymoff = e4(p[48:])
   280  		c.dsym.nextrefsyms = e4(p[52:])
   281  		c.dsym.indirectsymoff = e4(p[56:])
   282  		c.dsym.nindirectsyms = e4(p[60:])
   283  		c.dsym.extreloff = e4(p[64:])
   284  		c.dsym.nextrel = e4(p[68:])
   285  		c.dsym.locreloff = e4(p[72:])
   286  		c.dsym.nlocrel = e4(p[76:])
   287  	}
   288  
   289  	return 0
   290  }
   291  
   292  func macholoadrel(m *LdMachoObj, sect *LdMachoSect) int {
   293  	if sect.rel != nil || sect.nreloc == 0 {
   294  		return 0
   295  	}
   296  	rel := make([]LdMachoRel, sect.nreloc)
   297  	n := int(sect.nreloc * 8)
   298  	buf := make([]byte, n)
   299  	if Bseek(m.f, m.base+int64(sect.reloff), 0) < 0 || Bread(m.f, buf) != n {
   300  		return -1
   301  	}
   302  	var p []byte
   303  	var r *LdMachoRel
   304  	var v uint32
   305  	for i := 0; uint32(i) < sect.nreloc; i++ {
   306  		r = &rel[i]
   307  		p = buf[i*8:]
   308  		r.addr = m.e.Uint32(p)
   309  
   310  		// TODO(rsc): Wrong interpretation for big-endian bitfields?
   311  		if r.addr&0x80000000 != 0 {
   312  			// scatterbrained relocation
   313  			r.scattered = 1
   314  
   315  			v = r.addr >> 24
   316  			r.addr &= 0xFFFFFF
   317  			r.type_ = uint8(v & 0xF)
   318  			v >>= 4
   319  			r.length = 1 << (v & 3)
   320  			v >>= 2
   321  			r.pcrel = uint8(v & 1)
   322  			r.value = m.e.Uint32(p[4:])
   323  		} else {
   324  			v = m.e.Uint32(p[4:])
   325  			r.symnum = v & 0xFFFFFF
   326  			v >>= 24
   327  			r.pcrel = uint8(v & 1)
   328  			v >>= 1
   329  			r.length = 1 << (v & 3)
   330  			v >>= 2
   331  			r.extrn = uint8(v & 1)
   332  			v >>= 1
   333  			r.type_ = uint8(v)
   334  		}
   335  	}
   336  
   337  	sect.rel = rel
   338  	return 0
   339  }
   340  
   341  func macholoaddsym(m *LdMachoObj, d *LdMachoDysymtab) int {
   342  	n := int(d.nindirectsyms)
   343  
   344  	p := make([]byte, n*4)
   345  	if Bseek(m.f, m.base+int64(d.indirectsymoff), 0) < 0 || Bread(m.f, p) != len(p) {
   346  		return -1
   347  	}
   348  
   349  	d.indir = make([]uint32, n)
   350  	for i := 0; i < n; i++ {
   351  		d.indir[i] = m.e.Uint32(p[4*i:])
   352  	}
   353  	return 0
   354  }
   355  
   356  func macholoadsym(m *LdMachoObj, symtab *LdMachoSymtab) int {
   357  	if symtab.sym != nil {
   358  		return 0
   359  	}
   360  
   361  	strbuf := make([]byte, symtab.strsize)
   362  	if Bseek(m.f, m.base+int64(symtab.stroff), 0) < 0 || Bread(m.f, strbuf) != len(strbuf) {
   363  		return -1
   364  	}
   365  
   366  	symsize := 12
   367  	if m.is64 {
   368  		symsize = 16
   369  	}
   370  	n := int(symtab.nsym * uint32(symsize))
   371  	symbuf := make([]byte, n)
   372  	if Bseek(m.f, m.base+int64(symtab.symoff), 0) < 0 || Bread(m.f, symbuf) != len(symbuf) {
   373  		return -1
   374  	}
   375  	sym := make([]LdMachoSym, symtab.nsym)
   376  	p := symbuf
   377  	var s *LdMachoSym
   378  	var v uint32
   379  	for i := 0; uint32(i) < symtab.nsym; i++ {
   380  		s = &sym[i]
   381  		v = m.e.Uint32(p)
   382  		if v >= symtab.strsize {
   383  			return -1
   384  		}
   385  		s.name = cstring(strbuf[v:])
   386  		s.type_ = uint8(p[4])
   387  		s.sectnum = uint8(p[5])
   388  		s.desc = m.e.Uint16(p[6:])
   389  		if m.is64 {
   390  			s.value = m.e.Uint64(p[8:])
   391  		} else {
   392  			s.value = uint64(m.e.Uint32(p[8:]))
   393  		}
   394  		p = p[symsize:]
   395  	}
   396  
   397  	symtab.str = strbuf
   398  	symtab.sym = sym
   399  	return 0
   400  }
   401  
   402  func ldmacho(f *Biobuf, pkg string, length int64, pn string) {
   403  	var err error
   404  	var j int
   405  	var is64 bool
   406  	var secaddr uint64
   407  	var hdr [7 * 4]uint8
   408  	var cmdp []byte
   409  	var dat []byte
   410  	var ncmd uint32
   411  	var cmdsz uint32
   412  	var ty uint32
   413  	var sz uint32
   414  	var off uint32
   415  	var m *LdMachoObj
   416  	var e binary.ByteOrder
   417  	var sect *LdMachoSect
   418  	var rel *LdMachoRel
   419  	var rpi int
   420  	var s *LSym
   421  	var s1 *LSym
   422  	var outer *LSym
   423  	var c *LdMachoCmd
   424  	var symtab *LdMachoSymtab
   425  	var dsymtab *LdMachoDysymtab
   426  	var sym *LdMachoSym
   427  	var r []Reloc
   428  	var rp *Reloc
   429  	var name string
   430  
   431  	Ctxt.Version++
   432  	base := Boffset(f)
   433  	if Bread(f, hdr[:]) != len(hdr) {
   434  		goto bad
   435  	}
   436  
   437  	if binary.BigEndian.Uint32(hdr[:])&^1 == 0xFEEDFACE {
   438  		e = binary.BigEndian
   439  	} else if binary.LittleEndian.Uint32(hdr[:])&^1 == 0xFEEDFACE {
   440  		e = binary.LittleEndian
   441  	} else {
   442  		err = fmt.Errorf("bad magic - not mach-o file")
   443  		goto bad
   444  	}
   445  
   446  	is64 = e.Uint32(hdr[:]) == 0xFEEDFACF
   447  	ncmd = e.Uint32([]byte(hdr[4*4:]))
   448  	cmdsz = e.Uint32([]byte(hdr[5*4:]))
   449  	if ncmd > 0x10000 || cmdsz >= 0x01000000 {
   450  		err = fmt.Errorf("implausible mach-o header ncmd=%d cmdsz=%d", ncmd, cmdsz)
   451  		goto bad
   452  	}
   453  
   454  	if is64 {
   455  		var tmp [4]uint8
   456  		Bread(f, tmp[:4]) // skip reserved word in header
   457  	}
   458  
   459  	m = new(LdMachoObj)
   460  
   461  	m.f = f
   462  	m.e = e
   463  	m.cputype = uint(e.Uint32([]byte(hdr[1*4:])))
   464  	m.subcputype = uint(e.Uint32([]byte(hdr[2*4:])))
   465  	m.filetype = e.Uint32([]byte(hdr[3*4:]))
   466  	m.ncmd = uint(ncmd)
   467  	m.flags = e.Uint32([]byte(hdr[6*4:]))
   468  	m.is64 = is64
   469  	m.base = base
   470  	m.length = length
   471  	m.name = pn
   472  
   473  	switch Thearch.Thechar {
   474  	default:
   475  		Diag("%s: mach-o %s unimplemented", pn, Thestring)
   476  		return
   477  
   478  	case '6':
   479  		if e != binary.LittleEndian || m.cputype != LdMachoCpuAmd64 {
   480  			Diag("%s: mach-o object but not amd64", pn)
   481  			return
   482  		}
   483  
   484  	case '8':
   485  		if e != binary.LittleEndian || m.cputype != LdMachoCpu386 {
   486  			Diag("%s: mach-o object but not 386", pn)
   487  			return
   488  		}
   489  	}
   490  
   491  	m.cmd = make([]LdMachoCmd, ncmd)
   492  	off = uint32(len(hdr))
   493  	cmdp = make([]byte, cmdsz)
   494  	if Bread(f, cmdp) != len(cmdp) {
   495  		err = fmt.Errorf("reading cmds: %v", err)
   496  		goto bad
   497  	}
   498  
   499  	// read and parse load commands
   500  	c = nil
   501  
   502  	symtab = nil
   503  	dsymtab = nil
   504  
   505  	for i := 0; uint32(i) < ncmd; i++ {
   506  		ty = e.Uint32(cmdp)
   507  		sz = e.Uint32(cmdp[4:])
   508  		m.cmd[i].off = off
   509  		unpackcmd(cmdp, m, &m.cmd[i], uint(ty), uint(sz))
   510  		cmdp = cmdp[sz:]
   511  		off += sz
   512  		if ty == LdMachoCmdSymtab {
   513  			if symtab != nil {
   514  				err = fmt.Errorf("multiple symbol tables")
   515  				goto bad
   516  			}
   517  
   518  			symtab = &m.cmd[i].sym
   519  			macholoadsym(m, symtab)
   520  		}
   521  
   522  		if ty == LdMachoCmdDysymtab {
   523  			dsymtab = &m.cmd[i].dsym
   524  			macholoaddsym(m, dsymtab)
   525  		}
   526  
   527  		if (is64 && ty == LdMachoCmdSegment64) || (!is64 && ty == LdMachoCmdSegment) {
   528  			if c != nil {
   529  				err = fmt.Errorf("multiple load commands")
   530  				goto bad
   531  			}
   532  
   533  			c = &m.cmd[i]
   534  		}
   535  	}
   536  
   537  	// load text and data segments into memory.
   538  	// they are not as small as the load commands, but we'll need
   539  	// the memory anyway for the symbol images, so we might
   540  	// as well use one large chunk.
   541  	if c == nil {
   542  		err = fmt.Errorf("no load command")
   543  		goto bad
   544  	}
   545  
   546  	if symtab == nil {
   547  		// our work is done here - no symbols means nothing can refer to this file
   548  		return
   549  	}
   550  
   551  	if int64(c.seg.fileoff+c.seg.filesz) >= length {
   552  		err = fmt.Errorf("load segment out of range")
   553  		goto bad
   554  	}
   555  
   556  	dat = make([]byte, c.seg.filesz)
   557  	if Bseek(f, m.base+int64(c.seg.fileoff), 0) < 0 || Bread(f, dat) != len(dat) {
   558  		err = fmt.Errorf("cannot load object data: %v", err)
   559  		goto bad
   560  	}
   561  
   562  	for i := 0; uint32(i) < c.seg.nsect; i++ {
   563  		sect = &c.seg.sect[i]
   564  		if sect.segname != "__TEXT" && sect.segname != "__DATA" {
   565  			continue
   566  		}
   567  		if sect.name == "__eh_frame" {
   568  			continue
   569  		}
   570  		name = fmt.Sprintf("%s(%s/%s)", pkg, sect.segname, sect.name)
   571  		s = Linklookup(Ctxt, name, Ctxt.Version)
   572  		if s.Type != 0 {
   573  			err = fmt.Errorf("duplicate %s/%s", sect.segname, sect.name)
   574  			goto bad
   575  		}
   576  
   577  		if sect.flags&0xff == 1 { // S_ZEROFILL
   578  			s.P = make([]byte, sect.size)
   579  		} else {
   580  			s.P = dat[sect.addr-c.seg.vmaddr:][:sect.size]
   581  		}
   582  		s.Size = int64(len(s.P))
   583  
   584  		if sect.segname == "__TEXT" {
   585  			if sect.name == "__text" {
   586  				s.Type = STEXT
   587  			} else {
   588  				s.Type = SRODATA
   589  			}
   590  		} else {
   591  			if sect.name == "__bss" {
   592  				s.Type = SNOPTRBSS
   593  				s.P = s.P[:0]
   594  			} else {
   595  				s.Type = SNOPTRDATA
   596  			}
   597  		}
   598  
   599  		sect.sym = s
   600  	}
   601  
   602  	// enter sub-symbols into symbol table.
   603  	// have to guess sizes from next symbol.
   604  	for i := 0; uint32(i) < symtab.nsym; i++ {
   605  		sym = &symtab.sym[i]
   606  		if sym.type_&N_STAB != 0 {
   607  			continue
   608  		}
   609  
   610  		// TODO: check sym->type against outer->type.
   611  		name = sym.name
   612  
   613  		if name[0] == '_' && name[1] != '\x00' {
   614  			name = name[1:]
   615  		}
   616  		v := 0
   617  		if sym.type_&N_EXT == 0 {
   618  			v = Ctxt.Version
   619  		}
   620  		s = Linklookup(Ctxt, name, v)
   621  		if sym.type_&N_EXT == 0 {
   622  			s.Dupok = 1
   623  		}
   624  		sym.sym = s
   625  		if sym.sectnum == 0 { // undefined
   626  			continue
   627  		}
   628  		if uint32(sym.sectnum) > c.seg.nsect {
   629  			err = fmt.Errorf("reference to invalid section %d", sym.sectnum)
   630  			goto bad
   631  		}
   632  
   633  		sect = &c.seg.sect[sym.sectnum-1]
   634  		outer = sect.sym
   635  		if outer == nil {
   636  			err = fmt.Errorf("reference to invalid section %s/%s", sect.segname, sect.name)
   637  			continue
   638  		}
   639  
   640  		if s.Outer != nil {
   641  			if s.Dupok != 0 {
   642  				continue
   643  			}
   644  			Diag("%s: duplicate symbol reference: %s in both %s and %s", pn, s.Name, s.Outer.Name, sect.sym.Name)
   645  			Errorexit()
   646  		}
   647  
   648  		s.Type = outer.Type | 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 == 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 == 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 = 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  }