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