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