Black Lives Matter. Support the Equal Justice Initiative.

Source file src/cmd/link/internal/loadmacho/ldmacho.go

Documentation: cmd/link/internal/loadmacho

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

View as plain text