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

     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  https://github.com/9fans/plan9port/tree/master/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 ...any) ([]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.LookupOrCreateCgoExport(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  			if machsym.desc&N_WEAK_REF != 0 {
   617  				l.SetSymWeakBinding(s, true)
   618  			}
   619  		}
   620  		machsym.sym = s
   621  		if machsym.sectnum == 0 { // undefined
   622  			continue
   623  		}
   624  		if uint32(machsym.sectnum) > c.seg.nsect {
   625  			return errorf("reference to invalid section %d", machsym.sectnum)
   626  		}
   627  
   628  		sect := &c.seg.sect[machsym.sectnum-1]
   629  		bld := l.MakeSymbolUpdater(s)
   630  		outer := sect.sym
   631  		if outer == 0 {
   632  			continue // ignore reference to invalid section
   633  		}
   634  
   635  		if osym := l.OuterSym(s); osym != 0 {
   636  			if l.AttrDuplicateOK(s) {
   637  				continue
   638  			}
   639  			return errorf("duplicate symbol reference: %s in both %s and %s", l.SymName(s), l.SymName(osym), l.SymName(sect.sym))
   640  		}
   641  
   642  		bld.SetType(l.SymType(outer))
   643  		if l.SymSize(outer) != 0 { // skip empty section (0-sized symbol)
   644  			l.AddInteriorSym(outer, s)
   645  		}
   646  
   647  		bld.SetValue(int64(machsym.value - sect.addr))
   648  		if !l.AttrCgoExportDynamic(s) {
   649  			bld.SetDynimplib("") // satisfy dynimport
   650  		}
   651  		if l.SymType(outer).IsText() {
   652  			if bld.External() && !bld.DuplicateOK() {
   653  				return errorf("%v: duplicate symbol definition", s)
   654  			}
   655  			bld.SetExternal(true)
   656  		}
   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 == 0 {
   665  			continue
   666  		}
   667  		bld := l.MakeSymbolUpdater(s)
   668  		if bld.SubSym() != 0 {
   669  
   670  			bld.SortSub()
   671  
   672  			// assign sizes, now that we know symbols in sorted order.
   673  			for s1 := bld.Sub(); s1 != 0; s1 = l.SubSym(s1) {
   674  				s1Bld := l.MakeSymbolUpdater(s1)
   675  				if sub := l.SubSym(s1); sub != 0 {
   676  					s1Bld.SetSize(l.SymValue(sub) - l.SymValue(s1))
   677  				} else {
   678  					dlen := int64(len(l.Data(s)))
   679  					s1Bld.SetSize(l.SymValue(s) + dlen - l.SymValue(s1))
   680  				}
   681  			}
   682  		}
   683  
   684  		if bld.Type().IsText() {
   685  			if bld.OnList() {
   686  				return errorf("symbol %s listed multiple times", bld.Name())
   687  			}
   688  			bld.SetOnList(true)
   689  			textp = append(textp, s)
   690  			for s1 := bld.Sub(); s1 != 0; s1 = l.SubSym(s1) {
   691  				if l.AttrOnList(s1) {
   692  					return errorf("symbol %s listed multiple times", l.SymName(s1))
   693  				}
   694  				l.SetAttrOnList(s1, true)
   695  				textp = append(textp, s1)
   696  			}
   697  		}
   698  	}
   699  
   700  	// load relocations
   701  	for i := 0; uint32(i) < c.seg.nsect; i++ {
   702  		sect := &c.seg.sect[i]
   703  		s := sect.sym
   704  		if s == 0 {
   705  			continue
   706  		}
   707  		macholoadrel(m, sect)
   708  		if sect.rel == nil {
   709  			continue
   710  		}
   711  
   712  		sb := l.MakeSymbolUpdater(sect.sym)
   713  		var rAdd int64
   714  		for j := uint32(0); j < sect.nreloc; j++ {
   715  			var (
   716  				rOff  int32
   717  				rSize uint8
   718  				rType objabi.RelocType
   719  				rSym  loader.Sym
   720  			)
   721  			rel := &sect.rel[j]
   722  			if rel.scattered != 0 {
   723  				// mach-o only uses scattered relocation on 32-bit platforms,
   724  				// which are no longer supported.
   725  				return errorf("%v: unexpected scattered relocation", s)
   726  			}
   727  
   728  			if arch.Family == sys.ARM64 && rel.type_ == MACHO_ARM64_RELOC_ADDEND {
   729  				// Two relocations. This addend will be applied to the next one.
   730  				rAdd = int64(rel.symnum) << 40 >> 40 // convert unsigned 24-bit to signed 24-bit
   731  				continue
   732  			}
   733  
   734  			rSize = rel.length
   735  			rType = objabi.MachoRelocOffset + (objabi.RelocType(rel.type_) << 1) + objabi.RelocType(rel.pcrel)
   736  			rOff = int32(rel.addr)
   737  
   738  			// Handle X86_64_RELOC_SIGNED referencing a section (rel.extrn == 0).
   739  			p := l.Data(s)
   740  			if arch.Family == sys.AMD64 {
   741  				if rel.extrn == 0 && rel.type_ == MACHO_X86_64_RELOC_SIGNED {
   742  					// Calculate the addend as the offset into the section.
   743  					//
   744  					// The rip-relative offset stored in the object file is encoded
   745  					// as follows:
   746  					//
   747  					//    movsd	0x00000360(%rip),%xmm0
   748  					//
   749  					// To get the absolute address of the value this rip-relative address is pointing
   750  					// to, we must add the address of the next instruction to it. This is done by
   751  					// taking the address of the relocation and adding 4 to it (since the rip-relative
   752  					// offset can at most be 32 bits long).  To calculate the offset into the section the
   753  					// relocation is referencing, we subtract the vaddr of the start of the referenced
   754  					// section found in the original object file.
   755  					//
   756  					// [For future reference, see Darwin's /usr/include/mach-o/x86_64/reloc.h]
   757  					secaddr := c.seg.sect[rel.symnum-1].addr
   758  					rAdd = int64(uint64(int64(int32(e.Uint32(p[rOff:])))+int64(rOff)+4) - secaddr)
   759  				} else {
   760  					rAdd = int64(int32(e.Uint32(p[rOff:])))
   761  				}
   762  			}
   763  
   764  			// An unsigned internal relocation has a value offset
   765  			// by the section address.
   766  			if arch.Family == sys.AMD64 && rel.extrn == 0 && rel.type_ == MACHO_X86_64_RELOC_UNSIGNED {
   767  				secaddr := c.seg.sect[rel.symnum-1].addr
   768  				rAdd -= int64(secaddr)
   769  			}
   770  
   771  			if rel.extrn == 0 {
   772  				if rel.symnum < 1 || rel.symnum > c.seg.nsect {
   773  					return errorf("invalid relocation: section reference out of range %d vs %d", rel.symnum, c.seg.nsect)
   774  				}
   775  
   776  				rSym = c.seg.sect[rel.symnum-1].sym
   777  				if rSym == 0 {
   778  					return errorf("invalid relocation: %s", c.seg.sect[rel.symnum-1].name)
   779  				}
   780  			} else {
   781  				if rel.symnum >= symtab.nsym {
   782  					return errorf("invalid relocation: symbol reference out of range")
   783  				}
   784  
   785  				rSym = symtab.sym[rel.symnum].sym
   786  			}
   787  
   788  			r, _ := sb.AddRel(rType)
   789  			r.SetOff(rOff)
   790  			r.SetSiz(rSize)
   791  			r.SetSym(rSym)
   792  			r.SetAdd(rAdd)
   793  
   794  			rAdd = 0 // clear rAdd for next iteration
   795  		}
   796  	}
   797  
   798  	return textp, nil
   799  }
   800  
   801  func cstring(x []byte) string {
   802  	i := bytes.IndexByte(x, '\x00')
   803  	if i >= 0 {
   804  		x = x[:i]
   805  	}
   806  	return string(x)
   807  }
   808  

View as plain text