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