...

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

View as plain text