1// Copyright 2009 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
5package ld
6
7import (
8	"bytes"
9	"cmd/internal/codesign"
10	"cmd/internal/objabi"
11	"cmd/internal/sys"
12	"cmd/link/internal/loader"
13	"cmd/link/internal/sym"
14	"debug/macho"
15	"encoding/binary"
16	"fmt"
17	"internal/buildcfg"
18	"io"
19	"os"
20	"sort"
21	"strings"
22	"unsafe"
23)
24
25type MachoHdr struct {
26	cpu    uint32
27	subcpu uint32
28}
29
30type MachoSect struct {
31	name    string
32	segname string
33	addr    uint64
34	size    uint64
35	off     uint32
36	align   uint32
37	reloc   uint32
38	nreloc  uint32
39	flag    uint32
40	res1    uint32
41	res2    uint32
42}
43
44type MachoSeg struct {
45	name       string
46	vsize      uint64
47	vaddr      uint64
48	fileoffset uint64
49	filesize   uint64
50	prot1      uint32
51	prot2      uint32
52	nsect      uint32
53	msect      uint32
54	sect       []MachoSect
55	flag       uint32
56}
57
58// MachoPlatformLoad represents a LC_VERSION_MIN_* or
59// LC_BUILD_VERSION load command.
60type MachoPlatformLoad struct {
61	platform MachoPlatform // One of PLATFORM_* constants.
62	cmd      MachoLoad
63}
64
65type MachoLoad struct {
66	type_ uint32
67	data  []uint32
68}
69
70type MachoPlatform int
71
72/*
73 * Total amount of space to reserve at the start of the file
74 * for Header, PHeaders, and SHeaders.
75 * May waste some.
76 */
77const (
78	INITIAL_MACHO_HEADR = 4 * 1024
79)
80
81const (
82	MACHO_CPU_AMD64                      = 1<<24 | 7
83	MACHO_CPU_386                        = 7
84	MACHO_SUBCPU_X86                     = 3
85	MACHO_CPU_ARM                        = 12
86	MACHO_SUBCPU_ARM                     = 0
87	MACHO_SUBCPU_ARMV7                   = 9
88	MACHO_CPU_ARM64                      = 1<<24 | 12
89	MACHO_SUBCPU_ARM64_ALL               = 0
90	MACHO_SUBCPU_ARM64_V8                = 1
91	MACHO_SUBCPU_ARM64E                  = 2
92	MACHO32SYMSIZE                       = 12
93	MACHO64SYMSIZE                       = 16
94	MACHO_X86_64_RELOC_UNSIGNED          = 0
95	MACHO_X86_64_RELOC_SIGNED            = 1
96	MACHO_X86_64_RELOC_BRANCH            = 2
97	MACHO_X86_64_RELOC_GOT_LOAD          = 3
98	MACHO_X86_64_RELOC_GOT               = 4
99	MACHO_X86_64_RELOC_SUBTRACTOR        = 5
100	MACHO_X86_64_RELOC_SIGNED_1          = 6
101	MACHO_X86_64_RELOC_SIGNED_2          = 7
102	MACHO_X86_64_RELOC_SIGNED_4          = 8
103	MACHO_ARM_RELOC_VANILLA              = 0
104	MACHO_ARM_RELOC_PAIR                 = 1
105	MACHO_ARM_RELOC_SECTDIFF             = 2
106	MACHO_ARM_RELOC_BR24                 = 5
107	MACHO_ARM64_RELOC_UNSIGNED           = 0
108	MACHO_ARM64_RELOC_BRANCH26           = 2
109	MACHO_ARM64_RELOC_PAGE21             = 3
110	MACHO_ARM64_RELOC_PAGEOFF12          = 4
111	MACHO_ARM64_RELOC_GOT_LOAD_PAGE21    = 5
112	MACHO_ARM64_RELOC_GOT_LOAD_PAGEOFF12 = 6
113	MACHO_ARM64_RELOC_ADDEND             = 10
114	MACHO_GENERIC_RELOC_VANILLA          = 0
115	MACHO_FAKE_GOTPCREL                  = 100
116)
117
118const (
119	MH_MAGIC    = 0xfeedface
120	MH_MAGIC_64 = 0xfeedfacf
121
122	MH_OBJECT  = 0x1
123	MH_EXECUTE = 0x2
124
125	MH_NOUNDEFS = 0x1
126	MH_DYLDLINK = 0x4
127	MH_PIE      = 0x200000
128)
129
130const (
131	LC_SEGMENT                  = 0x1
132	LC_SYMTAB                   = 0x2
133	LC_SYMSEG                   = 0x3
134	LC_THREAD                   = 0x4
135	LC_UNIXTHREAD               = 0x5
136	LC_LOADFVMLIB               = 0x6
137	LC_IDFVMLIB                 = 0x7
138	LC_IDENT                    = 0x8
139	LC_FVMFILE                  = 0x9
140	LC_PREPAGE                  = 0xa
141	LC_DYSYMTAB                 = 0xb
142	LC_LOAD_DYLIB               = 0xc
143	LC_ID_DYLIB                 = 0xd
144	LC_LOAD_DYLINKER            = 0xe
145	LC_ID_DYLINKER              = 0xf
146	LC_PREBOUND_DYLIB           = 0x10
147	LC_ROUTINES                 = 0x11
148	LC_SUB_FRAMEWORK            = 0x12
149	LC_SUB_UMBRELLA             = 0x13
150	LC_SUB_CLIENT               = 0x14
151	LC_SUB_LIBRARY              = 0x15
152	LC_TWOLEVEL_HINTS           = 0x16
153	LC_PREBIND_CKSUM            = 0x17
154	LC_LOAD_WEAK_DYLIB          = 0x80000018
155	LC_SEGMENT_64               = 0x19
156	LC_ROUTINES_64              = 0x1a
157	LC_UUID                     = 0x1b
158	LC_RPATH                    = 0x8000001c
159	LC_CODE_SIGNATURE           = 0x1d
160	LC_SEGMENT_SPLIT_INFO       = 0x1e
161	LC_REEXPORT_DYLIB           = 0x8000001f
162	LC_LAZY_LOAD_DYLIB          = 0x20
163	LC_ENCRYPTION_INFO          = 0x21
164	LC_DYLD_INFO                = 0x22
165	LC_DYLD_INFO_ONLY           = 0x80000022
166	LC_LOAD_UPWARD_DYLIB        = 0x80000023
167	LC_VERSION_MIN_MACOSX       = 0x24
168	LC_VERSION_MIN_IPHONEOS     = 0x25
169	LC_FUNCTION_STARTS          = 0x26
170	LC_DYLD_ENVIRONMENT         = 0x27
171	LC_MAIN                     = 0x80000028
172	LC_DATA_IN_CODE             = 0x29
173	LC_SOURCE_VERSION           = 0x2A
174	LC_DYLIB_CODE_SIGN_DRS      = 0x2B
175	LC_ENCRYPTION_INFO_64       = 0x2C
176	LC_LINKER_OPTION            = 0x2D
177	LC_LINKER_OPTIMIZATION_HINT = 0x2E
178	LC_VERSION_MIN_TVOS         = 0x2F
179	LC_VERSION_MIN_WATCHOS      = 0x30
180	LC_VERSION_NOTE             = 0x31
181	LC_BUILD_VERSION            = 0x32
182	LC_DYLD_EXPORTS_TRIE        = 0x80000033
183	LC_DYLD_CHAINED_FIXUPS      = 0x80000034
184)
185
186const (
187	S_REGULAR                  = 0x0
188	S_ZEROFILL                 = 0x1
189	S_NON_LAZY_SYMBOL_POINTERS = 0x6
190	S_SYMBOL_STUBS             = 0x8
191	S_MOD_INIT_FUNC_POINTERS   = 0x9
192	S_ATTR_PURE_INSTRUCTIONS   = 0x80000000
193	S_ATTR_DEBUG               = 0x02000000
194	S_ATTR_SOME_INSTRUCTIONS   = 0x00000400
195)
196
197const (
198	PLATFORM_MACOS       MachoPlatform = 1
199	PLATFORM_IOS         MachoPlatform = 2
200	PLATFORM_TVOS        MachoPlatform = 3
201	PLATFORM_WATCHOS     MachoPlatform = 4
202	PLATFORM_BRIDGEOS    MachoPlatform = 5
203	PLATFORM_MACCATALYST MachoPlatform = 6
204)
205
206// rebase table opcode
207const (
208	REBASE_TYPE_POINTER         = 1
209	REBASE_TYPE_TEXT_ABSOLUTE32 = 2
210	REBASE_TYPE_TEXT_PCREL32    = 3
211
212	REBASE_OPCODE_MASK                               = 0xF0
213	REBASE_IMMEDIATE_MASK                            = 0x0F
214	REBASE_OPCODE_DONE                               = 0x00
215	REBASE_OPCODE_SET_TYPE_IMM                       = 0x10
216	REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB        = 0x20
217	REBASE_OPCODE_ADD_ADDR_ULEB                      = 0x30
218	REBASE_OPCODE_ADD_ADDR_IMM_SCALED                = 0x40
219	REBASE_OPCODE_DO_REBASE_IMM_TIMES                = 0x50
220	REBASE_OPCODE_DO_REBASE_ULEB_TIMES               = 0x60
221	REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB            = 0x70
222	REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB = 0x80
223)
224
225// bind table opcode
226const (
227	BIND_TYPE_POINTER         = 1
228	BIND_TYPE_TEXT_ABSOLUTE32 = 2
229	BIND_TYPE_TEXT_PCREL32    = 3
230
231	BIND_SPECIAL_DYLIB_SELF            = 0
232	BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE = -1
233	BIND_SPECIAL_DYLIB_FLAT_LOOKUP     = -2
234	BIND_SPECIAL_DYLIB_WEAK_LOOKUP     = -3
235
236	BIND_OPCODE_MASK                                         = 0xF0
237	BIND_IMMEDIATE_MASK                                      = 0x0F
238	BIND_OPCODE_DONE                                         = 0x00
239	BIND_OPCODE_SET_DYLIB_ORDINAL_IMM                        = 0x10
240	BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB                       = 0x20
241	BIND_OPCODE_SET_DYLIB_SPECIAL_IMM                        = 0x30
242	BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM                = 0x40
243	BIND_OPCODE_SET_TYPE_IMM                                 = 0x50
244	BIND_OPCODE_SET_ADDEND_SLEB                              = 0x60
245	BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB                  = 0x70
246	BIND_OPCODE_ADD_ADDR_ULEB                                = 0x80
247	BIND_OPCODE_DO_BIND                                      = 0x90
248	BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB                        = 0xA0
249	BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED                  = 0xB0
250	BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB             = 0xC0
251	BIND_OPCODE_THREADED                                     = 0xD0
252	BIND_SUBOPCODE_THREADED_SET_BIND_ORDINAL_TABLE_SIZE_ULEB = 0x00
253	BIND_SUBOPCODE_THREADED_APPLY                            = 0x01
254)
255
256const machoHeaderSize64 = 8 * 4 // size of 64-bit Mach-O header
257
258// Mach-O file writing
259// https://developer.apple.com/mac/library/DOCUMENTATION/DeveloperTools/Conceptual/MachORuntime/Reference/reference.html
260
261var machohdr MachoHdr
262
263var load []MachoLoad
264
265var machoPlatform MachoPlatform
266
267var seg [16]MachoSeg
268
269var nseg int
270
271var ndebug int
272
273var nsect int
274
275const (
276	SymKindLocal = 0 + iota
277	SymKindExtdef
278	SymKindUndef
279	NumSymKind
280)
281
282var nkind [NumSymKind]int
283
284var sortsym []loader.Sym
285
286var nsortsym int
287
288// Amount of space left for adding load commands
289// that refer to dynamic libraries. Because these have
290// to go in the Mach-O header, we can't just pick a
291// "big enough" header size. The initial header is
292// one page, the non-dynamic library stuff takes
293// up about 1300 bytes; we overestimate that as 2k.
294var loadBudget = INITIAL_MACHO_HEADR - 2*1024
295
296func getMachoHdr() *MachoHdr {
297	return &machohdr
298}
299
300func newMachoLoad(arch *sys.Arch, type_ uint32, ndata uint32) *MachoLoad {
301	if arch.PtrSize == 8 && (ndata&1 != 0) {
302		ndata++
303	}
304
305	load = append(load, MachoLoad{})
306	l := &load[len(load)-1]
307	l.type_ = type_
308	l.data = make([]uint32, ndata)
309	return l
310}
311
312func newMachoSeg(name string, msect int) *MachoSeg {
313	if nseg >= len(seg) {
314		Exitf("too many segs")
315	}
316
317	s := &seg[nseg]
318	nseg++
319	s.name = name
320	s.msect = uint32(msect)
321	s.sect = make([]MachoSect, msect)
322	return s
323}
324
325func newMachoSect(seg *MachoSeg, name string, segname string) *MachoSect {
326	if seg.nsect >= seg.msect {
327		Exitf("too many sects in segment %s", seg.name)
328	}
329
330	s := &seg.sect[seg.nsect]
331	seg.nsect++
332	s.name = name
333	s.segname = segname
334	nsect++
335	return s
336}
337
338// Generic linking code.
339
340var dylib []string
341
342var linkoff int64
343
344func machowrite(ctxt *Link, arch *sys.Arch, out *OutBuf, linkmode LinkMode) int {
345	o1 := out.Offset()
346
347	loadsize := 4 * 4 * ndebug
348	for i := range load {
349		loadsize += 4 * (len(load[i].data) + 2)
350	}
351	if arch.PtrSize == 8 {
352		loadsize += 18 * 4 * nseg
353		loadsize += 20 * 4 * nsect
354	} else {
355		loadsize += 14 * 4 * nseg
356		loadsize += 17 * 4 * nsect
357	}
358
359	if arch.PtrSize == 8 {
360		out.Write32(MH_MAGIC_64)
361	} else {
362		out.Write32(MH_MAGIC)
363	}
364	out.Write32(machohdr.cpu)
365	out.Write32(machohdr.subcpu)
366	if linkmode == LinkExternal {
367		out.Write32(MH_OBJECT) /* file type - mach object */
368	} else {
369		out.Write32(MH_EXECUTE) /* file type - mach executable */
370	}
371	out.Write32(uint32(len(load)) + uint32(nseg) + uint32(ndebug))
372	out.Write32(uint32(loadsize))
373	flags := uint32(0)
374	if nkind[SymKindUndef] == 0 {
375		flags |= MH_NOUNDEFS
376	}
377	if ctxt.IsPIE() && linkmode == LinkInternal {
378		flags |= MH_PIE | MH_DYLDLINK
379	}
380	out.Write32(flags) /* flags */
381	if arch.PtrSize == 8 {
382		out.Write32(0) /* reserved */
383	}
384
385	for i := 0; i < nseg; i++ {
386		s := &seg[i]
387		if arch.PtrSize == 8 {
388			out.Write32(LC_SEGMENT_64)
389			out.Write32(72 + 80*s.nsect)
390			out.WriteStringN(s.name, 16)
391			out.Write64(s.vaddr)
392			out.Write64(s.vsize)
393			out.Write64(s.fileoffset)
394			out.Write64(s.filesize)
395			out.Write32(s.prot1)
396			out.Write32(s.prot2)
397			out.Write32(s.nsect)
398			out.Write32(s.flag)
399		} else {
400			out.Write32(LC_SEGMENT)
401			out.Write32(56 + 68*s.nsect)
402			out.WriteStringN(s.name, 16)
403			out.Write32(uint32(s.vaddr))
404			out.Write32(uint32(s.vsize))
405			out.Write32(uint32(s.fileoffset))
406			out.Write32(uint32(s.filesize))
407			out.Write32(s.prot1)
408			out.Write32(s.prot2)
409			out.Write32(s.nsect)
410			out.Write32(s.flag)
411		}
412
413		for j := uint32(0); j < s.nsect; j++ {
414			t := &s.sect[j]
415			if arch.PtrSize == 8 {
416				out.WriteStringN(t.name, 16)
417				out.WriteStringN(t.segname, 16)
418				out.Write64(t.addr)
419				out.Write64(t.size)
420				out.Write32(t.off)
421				out.Write32(t.align)
422				out.Write32(t.reloc)
423				out.Write32(t.nreloc)
424				out.Write32(t.flag)
425				out.Write32(t.res1) /* reserved */
426				out.Write32(t.res2) /* reserved */
427				out.Write32(0)      /* reserved */
428			} else {
429				out.WriteStringN(t.name, 16)
430				out.WriteStringN(t.segname, 16)
431				out.Write32(uint32(t.addr))
432				out.Write32(uint32(t.size))
433				out.Write32(t.off)
434				out.Write32(t.align)
435				out.Write32(t.reloc)
436				out.Write32(t.nreloc)
437				out.Write32(t.flag)
438				out.Write32(t.res1) /* reserved */
439				out.Write32(t.res2) /* reserved */
440			}
441		}
442	}
443
444	for i := range load {
445		l := &load[i]
446		out.Write32(l.type_)
447		out.Write32(4 * (uint32(len(l.data)) + 2))
448		for j := 0; j < len(l.data); j++ {
449			out.Write32(l.data[j])
450		}
451	}
452
453	return int(out.Offset() - o1)
454}
455
456func (ctxt *Link) domacho() {
457	if *FlagD {
458		return
459	}
460
461	// Copy platform load command.
462	for _, h := range hostobj {
463		load, err := hostobjMachoPlatform(&h)
464		if err != nil {
465			Exitf("%v", err)
466		}
467		if load != nil {
468			machoPlatform = load.platform
469			ml := newMachoLoad(ctxt.Arch, load.cmd.type_, uint32(len(load.cmd.data)))
470			copy(ml.data, load.cmd.data)
471			break
472		}
473	}
474	if machoPlatform == 0 {
475		machoPlatform = PLATFORM_MACOS
476		if buildcfg.GOOS == "ios" {
477			machoPlatform = PLATFORM_IOS
478		}
479		if ctxt.LinkMode == LinkInternal && machoPlatform == PLATFORM_MACOS {
480			var version uint32
481			switch ctxt.Arch.Family {
482			case sys.ARM64, sys.AMD64:
483				// This must be fairly recent for Apple signing (go.dev/issue/30488).
484				// Having too old a version here was also implicated in some problems
485				// calling into macOS libraries (go.dev/issue/56784).
486				// In general this can be the most recent supported macOS version.
487				version = 11<<16 | 0<<8 | 0<<0 // 11.0.0
488			}
489			ml := newMachoLoad(ctxt.Arch, LC_BUILD_VERSION, 4)
490			ml.data[0] = uint32(machoPlatform)
491			ml.data[1] = version // OS version
492			ml.data[2] = version // SDK version
493			ml.data[3] = 0       // ntools
494		}
495	}
496
497	// empirically, string table must begin with " \x00".
498	s := ctxt.loader.LookupOrCreateSym(".machosymstr", 0)
499	sb := ctxt.loader.MakeSymbolUpdater(s)
500
501	sb.SetType(sym.SMACHOSYMSTR)
502	sb.SetReachable(true)
503	sb.AddUint8(' ')
504	sb.AddUint8('\x00')
505
506	s = ctxt.loader.LookupOrCreateSym(".machosymtab", 0)
507	sb = ctxt.loader.MakeSymbolUpdater(s)
508	sb.SetType(sym.SMACHOSYMTAB)
509	sb.SetReachable(true)
510
511	if ctxt.IsInternal() {
512		s = ctxt.loader.LookupOrCreateSym(".plt", 0) // will be __symbol_stub
513		sb = ctxt.loader.MakeSymbolUpdater(s)
514		sb.SetType(sym.SMACHOPLT)
515		sb.SetReachable(true)
516
517		s = ctxt.loader.LookupOrCreateSym(".got", 0) // will be __nl_symbol_ptr
518		sb = ctxt.loader.MakeSymbolUpdater(s)
519		sb.SetType(sym.SMACHOGOT)
520		sb.SetReachable(true)
521		sb.SetAlign(4)
522
523		s = ctxt.loader.LookupOrCreateSym(".linkedit.plt", 0) // indirect table for .plt
524		sb = ctxt.loader.MakeSymbolUpdater(s)
525		sb.SetType(sym.SMACHOINDIRECTPLT)
526		sb.SetReachable(true)
527
528		s = ctxt.loader.LookupOrCreateSym(".linkedit.got", 0) // indirect table for .got
529		sb = ctxt.loader.MakeSymbolUpdater(s)
530		sb.SetType(sym.SMACHOINDIRECTGOT)
531		sb.SetReachable(true)
532	}
533
534	// Add a dummy symbol that will become the __asm marker section.
535	if ctxt.IsExternal() {
536		s = ctxt.loader.LookupOrCreateSym(".llvmasm", 0)
537		sb = ctxt.loader.MakeSymbolUpdater(s)
538		sb.SetType(sym.SMACHO)
539		sb.SetReachable(true)
540		sb.AddUint8(0)
541	}
542
543	// Un-export runtime symbols from plugins. Since the runtime
544	// is included in both the main binary and each plugin, these
545	// symbols appear in both images. If we leave them exported in
546	// the plugin, then the dynamic linker will resolve
547	// relocations to these functions in the plugin's functab to
548	// point to the main image, causing the runtime to think the
549	// plugin's functab is corrupted. By unexporting them, these
550	// become static references, which are resolved to the
551	// plugin's text.
552	//
553	// It would be better to omit the runtime from plugins. (Using
554	// relative PCs in the functab instead of relocations would
555	// also address this.)
556	//
557	// See issue #18190.
558	if ctxt.BuildMode == BuildModePlugin {
559		for _, name := range []string{"_cgo_topofstack", "__cgo_topofstack", "_cgo_panic", "crosscall2"} {
560			// Most of these are data symbols or C
561			// symbols, so they have symbol version 0.
562			ver := 0
563			// _cgo_panic is a Go function, so it uses ABIInternal.
564			if name == "_cgo_panic" {
565				ver = abiInternalVer
566			}
567			s := ctxt.loader.Lookup(name, ver)
568			if s != 0 {
569				ctxt.loader.SetAttrCgoExportDynamic(s, false)
570			}
571		}
572	}
573}
574
575func machoadddynlib(lib string, linkmode LinkMode) {
576	if seenlib[lib] || linkmode == LinkExternal {
577		return
578	}
579	seenlib[lib] = true
580
581	// Will need to store the library name rounded up
582	// and 24 bytes of header metadata. If not enough
583	// space, grab another page of initial space at the
584	// beginning of the output file.
585	loadBudget -= (len(lib)+7)/8*8 + 24
586
587	if loadBudget < 0 {
588		HEADR += 4096
589		*FlagTextAddr += 4096
590		loadBudget += 4096
591	}
592
593	dylib = append(dylib, lib)
594}
595
596func machoshbits(ctxt *Link, mseg *MachoSeg, sect *sym.Section, segname string) {
597	buf := "__" + strings.Replace(sect.Name[1:], ".", "_", -1)
598
599	msect := newMachoSect(mseg, buf, segname)
600
601	if sect.Rellen > 0 {
602		msect.reloc = uint32(sect.Reloff)
603		msect.nreloc = uint32(sect.Rellen / 8)
604	}
605
606	for 1<<msect.align < sect.Align {
607		msect.align++
608	}
609	msect.addr = sect.Vaddr
610	msect.size = sect.Length
611
612	if sect.Vaddr < sect.Seg.Vaddr+sect.Seg.Filelen {
613		// data in file
614		if sect.Length > sect.Seg.Vaddr+sect.Seg.Filelen-sect.Vaddr {
615			Errorf(nil, "macho cannot represent section %s crossing data and bss", sect.Name)
616		}
617		msect.off = uint32(sect.Seg.Fileoff + sect.Vaddr - sect.Seg.Vaddr)
618	} else {
619		msect.off = 0
620		msect.flag |= S_ZEROFILL
621	}
622
623	if sect.Rwx&1 != 0 {
624		msect.flag |= S_ATTR_SOME_INSTRUCTIONS
625	}
626
627	if sect.Name == ".text" {
628		msect.flag |= S_ATTR_PURE_INSTRUCTIONS
629	}
630
631	if sect.Name == ".plt" {
632		msect.name = "__symbol_stub1"
633		msect.flag = S_ATTR_PURE_INSTRUCTIONS | S_ATTR_SOME_INSTRUCTIONS | S_SYMBOL_STUBS
634		msect.res1 = 0 //nkind[SymKindLocal];
635		msect.res2 = 6
636	}
637
638	if sect.Name == ".got" {
639		msect.name = "__nl_symbol_ptr"
640		msect.flag = S_NON_LAZY_SYMBOL_POINTERS
641		msect.res1 = uint32(ctxt.loader.SymSize(ctxt.ArchSyms.LinkEditPLT) / 4) /* offset into indirect symbol table */
642	}
643
644	if sect.Name == ".init_array" {
645		msect.name = "__mod_init_func"
646		msect.flag = S_MOD_INIT_FUNC_POINTERS
647	}
648
649	// Some platforms such as watchOS and tvOS require binaries with
650	// bitcode enabled. The Go toolchain can't output bitcode, so use
651	// a marker section in the __LLVM segment, "__asm", to tell the Apple
652	// toolchain that the Go text came from assembler and thus has no
653	// bitcode. This is not true, but Kotlin/Native, Rust and Flutter
654	// are also using this trick.
655	if sect.Name == ".llvmasm" {
656		msect.name = "__asm"
657		msect.segname = "__LLVM"
658	}
659
660	if segname == "__DWARF" {
661		msect.flag |= S_ATTR_DEBUG
662	}
663}
664
665func asmbMacho(ctxt *Link) {
666	machlink := doMachoLink(ctxt)
667	if ctxt.IsExternal() {
668		symo := int64(Segdwarf.Fileoff + uint64(Rnd(int64(Segdwarf.Filelen), *FlagRound)) + uint64(machlink))
669		ctxt.Out.SeekSet(symo)
670		machoEmitReloc(ctxt)
671	}
672	ctxt.Out.SeekSet(0)
673
674	ldr := ctxt.loader
675
676	/* apple MACH */
677	va := *FlagTextAddr - int64(HEADR)
678
679	mh := getMachoHdr()
680	switch ctxt.Arch.Family {
681	default:
682		Exitf("unknown macho architecture: %v", ctxt.Arch.Family)
683
684	case sys.AMD64:
685		mh.cpu = MACHO_CPU_AMD64
686		mh.subcpu = MACHO_SUBCPU_X86
687
688	case sys.ARM64:
689		mh.cpu = MACHO_CPU_ARM64
690		mh.subcpu = MACHO_SUBCPU_ARM64_ALL
691	}
692
693	var ms *MachoSeg
694	if ctxt.LinkMode == LinkExternal {
695		/* segment for entire file */
696		ms = newMachoSeg("", 40)
697
698		ms.fileoffset = Segtext.Fileoff
699		ms.filesize = Segdwarf.Fileoff + Segdwarf.Filelen - Segtext.Fileoff
700		ms.vsize = Segdwarf.Vaddr + Segdwarf.Length - Segtext.Vaddr
701	}
702
703	/* segment for zero page */
704	if ctxt.LinkMode != LinkExternal {
705		ms = newMachoSeg("__PAGEZERO", 0)
706		ms.vsize = uint64(va)
707	}
708
709	/* text */
710	v := Rnd(int64(uint64(HEADR)+Segtext.Length), *FlagRound)
711
712	var mstext *MachoSeg
713	if ctxt.LinkMode != LinkExternal {
714		ms = newMachoSeg("__TEXT", 20)
715		ms.vaddr = uint64(va)
716		ms.vsize = uint64(v)
717		ms.fileoffset = 0
718		ms.filesize = uint64(v)
719		ms.prot1 = 7
720		ms.prot2 = 5
721		mstext = ms
722	}
723
724	for _, sect := range Segtext.Sections {
725		machoshbits(ctxt, ms, sect, "__TEXT")
726	}
727
728	/* rodata */
729	if ctxt.LinkMode != LinkExternal && Segrelrodata.Length > 0 {
730		ms = newMachoSeg("__DATA_CONST", 20)
731		ms.vaddr = Segrelrodata.Vaddr
732		ms.vsize = Segrelrodata.Length
733		ms.fileoffset = Segrelrodata.Fileoff
734		ms.filesize = Segrelrodata.Filelen
735		ms.prot1 = 3
736		ms.prot2 = 3
737		ms.flag = 0x10 // SG_READ_ONLY
738	}
739
740	for _, sect := range Segrelrodata.Sections {
741		machoshbits(ctxt, ms, sect, "__DATA_CONST")
742	}
743
744	/* data */
745	if ctxt.LinkMode != LinkExternal {
746		ms = newMachoSeg("__DATA", 20)
747		ms.vaddr = Segdata.Vaddr
748		ms.vsize = Segdata.Length
749		ms.fileoffset = Segdata.Fileoff
750		ms.filesize = Segdata.Filelen
751		ms.prot1 = 3
752		ms.prot2 = 3
753	}
754
755	for _, sect := range Segdata.Sections {
756		machoshbits(ctxt, ms, sect, "__DATA")
757	}
758
759	/* dwarf */
760	if !*FlagW {
761		if ctxt.LinkMode != LinkExternal {
762			ms = newMachoSeg("__DWARF", 20)
763			ms.vaddr = Segdwarf.Vaddr
764			ms.vsize = 0
765			ms.fileoffset = Segdwarf.Fileoff
766			ms.filesize = Segdwarf.Filelen
767		}
768		for _, sect := range Segdwarf.Sections {
769			machoshbits(ctxt, ms, sect, "__DWARF")
770		}
771	}
772
773	if ctxt.LinkMode != LinkExternal {
774		switch ctxt.Arch.Family {
775		default:
776			Exitf("unknown macho architecture: %v", ctxt.Arch.Family)
777
778		case sys.AMD64:
779			ml := newMachoLoad(ctxt.Arch, LC_UNIXTHREAD, 42+2)
780			ml.data[0] = 4                           /* thread type */
781			ml.data[1] = 42                          /* word count */
782			ml.data[2+32] = uint32(Entryvalue(ctxt)) /* start pc */
783			ml.data[2+32+1] = uint32(Entryvalue(ctxt) >> 32)
784
785		case sys.ARM64:
786			ml := newMachoLoad(ctxt.Arch, LC_MAIN, 4)
787			ml.data[0] = uint32(uint64(Entryvalue(ctxt)) - (Segtext.Vaddr - uint64(HEADR)))
788			ml.data[1] = uint32((uint64(Entryvalue(ctxt)) - (Segtext.Vaddr - uint64(HEADR))) >> 32)
789		}
790	}
791
792	var codesigOff int64
793	if !*FlagD {
794		// must match doMachoLink below
795		s1 := ldr.SymSize(ldr.Lookup(".machorebase", 0))
796		s2 := ldr.SymSize(ldr.Lookup(".machobind", 0))
797		s3 := ldr.SymSize(ldr.Lookup(".machosymtab", 0))
798		s4 := ldr.SymSize(ctxt.ArchSyms.LinkEditPLT)
799		s5 := ldr.SymSize(ctxt.ArchSyms.LinkEditGOT)
800		s6 := ldr.SymSize(ldr.Lookup(".machosymstr", 0))
801		s7 := ldr.SymSize(ldr.Lookup(".machocodesig", 0))
802
803		if ctxt.LinkMode != LinkExternal {
804			ms := newMachoSeg("__LINKEDIT", 0)
805			ms.vaddr = uint64(Rnd(int64(Segdata.Vaddr+Segdata.Length), *FlagRound))
806			ms.vsize = uint64(s1 + s2 + s3 + s4 + s5 + s6 + s7)
807			ms.fileoffset = uint64(linkoff)
808			ms.filesize = ms.vsize
809			ms.prot1 = 1
810			ms.prot2 = 1
811
812			codesigOff = linkoff + s1 + s2 + s3 + s4 + s5 + s6
813		}
814
815		if ctxt.LinkMode != LinkExternal && ctxt.IsPIE() {
816			ml := newMachoLoad(ctxt.Arch, LC_DYLD_INFO_ONLY, 10)
817			ml.data[0] = uint32(linkoff)      // rebase off
818			ml.data[1] = uint32(s1)           // rebase size
819			ml.data[2] = uint32(linkoff + s1) // bind off
820			ml.data[3] = uint32(s2)           // bind size
821			ml.data[4] = 0                    // weak bind off
822			ml.data[5] = 0                    // weak bind size
823			ml.data[6] = 0                    // lazy bind off
824			ml.data[7] = 0                    // lazy bind size
825			ml.data[8] = 0                    // export
826			ml.data[9] = 0                    // export size
827		}
828
829		ml := newMachoLoad(ctxt.Arch, LC_SYMTAB, 4)
830		ml.data[0] = uint32(linkoff + s1 + s2)                /* symoff */
831		ml.data[1] = uint32(nsortsym)                         /* nsyms */
832		ml.data[2] = uint32(linkoff + s1 + s2 + s3 + s4 + s5) /* stroff */
833		ml.data[3] = uint32(s6)                               /* strsize */
834
835		if ctxt.LinkMode != LinkExternal {
836			machodysymtab(ctxt, linkoff+s1+s2)
837
838			ml := newMachoLoad(ctxt.Arch, LC_LOAD_DYLINKER, 6)
839			ml.data[0] = 12 /* offset to string */
840			stringtouint32(ml.data[1:], "/usr/lib/dyld")
841
842			for _, lib := range dylib {
843				ml = newMachoLoad(ctxt.Arch, LC_LOAD_DYLIB, 4+(uint32(len(lib))+1+7)/8*2)
844				ml.data[0] = 24 /* offset of string from beginning of load */
845				ml.data[1] = 0  /* time stamp */
846				ml.data[2] = 0  /* version */
847				ml.data[3] = 0  /* compatibility version */
848				stringtouint32(ml.data[4:], lib)
849			}
850		}
851
852		if ctxt.IsInternal() && ctxt.NeedCodeSign() {
853			ml := newMachoLoad(ctxt.Arch, LC_CODE_SIGNATURE, 2)
854			ml.data[0] = uint32(codesigOff)
855			ml.data[1] = uint32(s7)
856		}
857	}
858
859	a := machowrite(ctxt, ctxt.Arch, ctxt.Out, ctxt.LinkMode)
860	if int32(a) > HEADR {
861		Exitf("HEADR too small: %d > %d", a, HEADR)
862	}
863
864	// Now we have written everything. Compute the code signature (which
865	// is a hash of the file content, so it must be done at last.)
866	if ctxt.IsInternal() && ctxt.NeedCodeSign() {
867		cs := ldr.Lookup(".machocodesig", 0)
868		data := ctxt.Out.Data()
869		if int64(len(data)) != codesigOff {
870			panic("wrong size")
871		}
872		codesign.Sign(ldr.Data(cs), bytes.NewReader(data), "a.out", codesigOff, int64(mstext.fileoffset), int64(mstext.filesize), ctxt.IsExe() || ctxt.IsPIE())
873		ctxt.Out.SeekSet(codesigOff)
874		ctxt.Out.Write(ldr.Data(cs))
875	}
876}
877
878func symkind(ldr *loader.Loader, s loader.Sym) int {
879	if t := ldr.SymType(s); t == sym.SDYNIMPORT || t == sym.SHOSTOBJ || t == sym.SUNDEFEXT {
880		return SymKindUndef
881	}
882	if ldr.AttrCgoExport(s) {
883		return SymKindExtdef
884	}
885	return SymKindLocal
886}
887
888func collectmachosyms(ctxt *Link) {
889	ldr := ctxt.loader
890
891	addsym := func(s loader.Sym) {
892		sortsym = append(sortsym, s)
893		nkind[symkind(ldr, s)]++
894	}
895
896	// On Mach-O, even with -s, we still need to keep dynamically exported and
897	// referenced symbols. We can strip defined local text and data symbols.
898	// So *FlagS is applied based on symbol type.
899
900	// Add special runtime.text and runtime.etext symbols (which are local).
901	// We've already included this symbol in Textp on darwin if ctxt.DynlinkingGo().
902	// See data.go:/textaddress
903	// NOTE: runtime.text.N symbols (if we split text sections) are not added, though,
904	// so we handle them here.
905	if !*FlagS {
906		if !ctxt.DynlinkingGo() {
907			s := ldr.Lookup("runtime.text", 0)
908			if ldr.SymType(s) == sym.STEXT {
909				addsym(s)
910			}
911		}
912		for n := range Segtext.Sections[1:] {
913			s := ldr.Lookup(fmt.Sprintf("runtime.text.%d", n+1), 0)
914			if s != 0 {
915				addsym(s)
916			} else {
917				break
918			}
919		}
920		if !ctxt.DynlinkingGo() {
921			s := ldr.Lookup("runtime.etext", 0)
922			if ldr.SymType(s) == sym.STEXT {
923				addsym(s)
924			}
925		}
926	}
927
928	// Add text symbols.
929	for _, s := range ctxt.Textp {
930		if *FlagS && !ldr.AttrCgoExportDynamic(s) {
931			continue
932		}
933		addsym(s)
934	}
935
936	shouldBeInSymbolTable := func(s loader.Sym) bool {
937		if ldr.AttrNotInSymbolTable(s) {
938			return false
939		}
940		name := ldr.SymName(s) // TODO: try not to read the name
941		if name == "" || name[0] == '.' {
942			return false
943		}
944		return true
945	}
946
947	// Add data symbols and external references.
948	for s := loader.Sym(1); s < loader.Sym(ldr.NSym()); s++ {
949		if !ldr.AttrReachable(s) {
950			continue
951		}
952		t := ldr.SymType(s)
953		if t >= sym.SELFRXSECT && t < sym.SXREF { // data sections handled in dodata
954			if t == sym.STLSBSS {
955				// TLSBSS is not used on darwin. See data.go:allocateDataSections
956				continue
957			}
958			if !shouldBeInSymbolTable(s) {
959				continue
960			}
961			if *FlagS && !ldr.AttrCgoExportDynamic(s) {
962				continue
963			}
964			addsym(s)
965			continue
966		}
967
968		switch t {
969		case sym.SDYNIMPORT, sym.SHOSTOBJ, sym.SUNDEFEXT:
970			// Keep dynamic symbol references even if *FlagS.
971			addsym(s)
972		}
973
974		// Some 64-bit functions have a "$INODE64" or "$INODE64$UNIX2003" suffix.
975		if t == sym.SDYNIMPORT && ldr.SymDynimplib(s) == "/usr/lib/libSystem.B.dylib" {
976			// But only on macOS.
977			if machoPlatform == PLATFORM_MACOS || machoPlatform == PLATFORM_MACCATALYST {
978				switch n := ldr.SymExtname(s); n {
979				case "fdopendir":
980					switch buildcfg.GOARCH {
981					case "amd64":
982						ldr.SetSymExtname(s, n+"$INODE64")
983					}
984				case "readdir_r", "getfsstat":
985					switch buildcfg.GOARCH {
986					case "amd64":
987						ldr.SetSymExtname(s, n+"$INODE64")
988					}
989				}
990			}
991		}
992	}
993
994	nsortsym = len(sortsym)
995}
996
997func machosymorder(ctxt *Link) {
998	ldr := ctxt.loader
999
1000	// On Mac OS X Mountain Lion, we must sort exported symbols
1001	// So we sort them here and pre-allocate dynid for them
1002	// See https://golang.org/issue/4029
1003	for _, s := range ctxt.dynexp {
1004		if !ldr.AttrReachable(s) {
1005			panic("dynexp symbol is not reachable")
1006		}
1007	}
1008	collectmachosyms(ctxt)
1009	sort.Slice(sortsym[:nsortsym], func(i, j int) bool {
1010		s1 := sortsym[i]
1011		s2 := sortsym[j]
1012		k1 := symkind(ldr, s1)
1013		k2 := symkind(ldr, s2)
1014		if k1 != k2 {
1015			return k1 < k2
1016		}
1017		return ldr.SymExtname(s1) < ldr.SymExtname(s2) // Note: unnamed symbols are not added in collectmachosyms
1018	})
1019	for i, s := range sortsym {
1020		ldr.SetSymDynid(s, int32(i))
1021	}
1022}
1023
1024// AddMachoSym adds s to Mach-O symbol table, used in GenSymLate.
1025// Currently only used on ARM64 when external linking.
1026func AddMachoSym(ldr *loader.Loader, s loader.Sym) {
1027	ldr.SetSymDynid(s, int32(nsortsym))
1028	sortsym = append(sortsym, s)
1029	nsortsym++
1030	nkind[symkind(ldr, s)]++
1031}
1032
1033// machoShouldExport reports whether a symbol needs to be exported.
1034//
1035// When dynamically linking, all non-local variables and plugin-exported
1036// symbols need to be exported.
1037func machoShouldExport(ctxt *Link, ldr *loader.Loader, s loader.Sym) bool {
1038	if !ctxt.DynlinkingGo() || ldr.AttrLocal(s) {
1039		return false
1040	}
1041	if ctxt.BuildMode == BuildModePlugin && strings.HasPrefix(ldr.SymExtname(s), objabi.PathToPrefix(*flagPluginPath)) {
1042		return true
1043	}
1044	name := ldr.SymName(s)
1045	if strings.HasPrefix(name, "go:itab.") {
1046		return true
1047	}
1048	if strings.HasPrefix(name, "type:") && !strings.HasPrefix(name, "type:.") {
1049		// reduce runtime typemap pressure, but do not
1050		// export alg functions (type:.*), as these
1051		// appear in pclntable.
1052		return true
1053	}
1054	if strings.HasPrefix(name, "go:link.pkghash") {
1055		return true
1056	}
1057	return ldr.SymType(s) >= sym.SFirstWritable // only writable sections
1058}
1059
1060func machosymtab(ctxt *Link) {
1061	ldr := ctxt.loader
1062	symtab := ldr.CreateSymForUpdate(".machosymtab", 0)
1063	symstr := ldr.CreateSymForUpdate(".machosymstr", 0)
1064
1065	for _, s := range sortsym[:nsortsym] {
1066		symtab.AddUint32(ctxt.Arch, uint32(symstr.Size()))
1067
1068		export := machoShouldExport(ctxt, ldr, s)
1069
1070		// Prefix symbol names with "_" to match the system toolchain.
1071		// (We used to only prefix C symbols, which is all required for the build.
1072		// But some tools don't recognize Go symbols as symbols, so we prefix them
1073		// as well.)
1074		symstr.AddUint8('_')
1075
1076		// replace "·" as ".", because DTrace cannot handle it.
1077		name := strings.Replace(ldr.SymExtname(s), "·", ".", -1)
1078
1079		name = mangleABIName(ctxt, ldr, s, name)
1080		symstr.Addstring(name)
1081
1082		if t := ldr.SymType(s); t == sym.SDYNIMPORT || t == sym.SHOSTOBJ || t == sym.SUNDEFEXT {
1083			symtab.AddUint8(0x01)                             // type N_EXT, external symbol
1084			symtab.AddUint8(0)                                // no section
1085			symtab.AddUint16(ctxt.Arch, 0)                    // desc
1086			symtab.AddUintXX(ctxt.Arch, 0, ctxt.Arch.PtrSize) // no value
1087		} else {
1088			if export || ldr.AttrCgoExportDynamic(s) {
1089				symtab.AddUint8(0x0f) // N_SECT | N_EXT
1090			} else if ldr.AttrCgoExportStatic(s) {
1091				// Only export statically, not dynamically. (N_PEXT is like hidden visibility)
1092				symtab.AddUint8(0x1f) // N_SECT | N_EXT | N_PEXT
1093			} else {
1094				symtab.AddUint8(0x0e) // N_SECT
1095			}
1096			o := s
1097			if outer := ldr.OuterSym(o); outer != 0 {
1098				o = outer
1099			}
1100			if ldr.SymSect(o) == nil {
1101				ldr.Errorf(s, "missing section for symbol")
1102				symtab.AddUint8(0)
1103			} else {
1104				symtab.AddUint8(uint8(ldr.SymSect(o).Extnum))
1105			}
1106			symtab.AddUint16(ctxt.Arch, 0) // desc
1107			symtab.AddUintXX(ctxt.Arch, uint64(ldr.SymAddr(s)), ctxt.Arch.PtrSize)
1108		}
1109	}
1110}
1111
1112func machodysymtab(ctxt *Link, base int64) {
1113	ml := newMachoLoad(ctxt.Arch, LC_DYSYMTAB, 18)
1114
1115	n := 0
1116	ml.data[0] = uint32(n)                   /* ilocalsym */
1117	ml.data[1] = uint32(nkind[SymKindLocal]) /* nlocalsym */
1118	n += nkind[SymKindLocal]
1119
1120	ml.data[2] = uint32(n)                    /* iextdefsym */
1121	ml.data[3] = uint32(nkind[SymKindExtdef]) /* nextdefsym */
1122	n += nkind[SymKindExtdef]
1123
1124	ml.data[4] = uint32(n)                   /* iundefsym */
1125	ml.data[5] = uint32(nkind[SymKindUndef]) /* nundefsym */
1126
1127	ml.data[6] = 0  /* tocoffset */
1128	ml.data[7] = 0  /* ntoc */
1129	ml.data[8] = 0  /* modtaboff */
1130	ml.data[9] = 0  /* nmodtab */
1131	ml.data[10] = 0 /* extrefsymoff */
1132	ml.data[11] = 0 /* nextrefsyms */
1133
1134	ldr := ctxt.loader
1135
1136	// must match domacholink below
1137	s1 := ldr.SymSize(ldr.Lookup(".machosymtab", 0))
1138	s2 := ldr.SymSize(ctxt.ArchSyms.LinkEditPLT)
1139	s3 := ldr.SymSize(ctxt.ArchSyms.LinkEditGOT)
1140	ml.data[12] = uint32(base + s1)     /* indirectsymoff */
1141	ml.data[13] = uint32((s2 + s3) / 4) /* nindirectsyms */
1142
1143	ml.data[14] = 0 /* extreloff */
1144	ml.data[15] = 0 /* nextrel */
1145	ml.data[16] = 0 /* locreloff */
1146	ml.data[17] = 0 /* nlocrel */
1147}
1148
1149func doMachoLink(ctxt *Link) int64 {
1150	machosymtab(ctxt)
1151	machoDyldInfo(ctxt)
1152
1153	ldr := ctxt.loader
1154
1155	// write data that will be linkedit section
1156	s1 := ldr.Lookup(".machorebase", 0)
1157	s2 := ldr.Lookup(".machobind", 0)
1158	s3 := ldr.Lookup(".machosymtab", 0)
1159	s4 := ctxt.ArchSyms.LinkEditPLT
1160	s5 := ctxt.ArchSyms.LinkEditGOT
1161	s6 := ldr.Lookup(".machosymstr", 0)
1162
1163	size := ldr.SymSize(s1) + ldr.SymSize(s2) + ldr.SymSize(s3) + ldr.SymSize(s4) + ldr.SymSize(s5) + ldr.SymSize(s6)
1164
1165	// Force the linkedit section to end on a 16-byte
1166	// boundary. This allows pure (non-cgo) Go binaries
1167	// to be code signed correctly.
1168	//
1169	// Apple's codesign_allocate (a helper utility for
1170	// the codesign utility) can do this fine itself if
1171	// it is run on a dynamic Mach-O binary. However,
1172	// when it is run on a pure (non-cgo) Go binary, where
1173	// the linkedit section is mostly empty, it fails to
1174	// account for the extra padding that it itself adds
1175	// when adding the LC_CODE_SIGNATURE load command
1176	// (which must be aligned on a 16-byte boundary).
1177	//
1178	// By forcing the linkedit section to end on a 16-byte
1179	// boundary, codesign_allocate will not need to apply
1180	// any alignment padding itself, working around the
1181	// issue.
1182	if size%16 != 0 {
1183		n := 16 - size%16
1184		s6b := ldr.MakeSymbolUpdater(s6)
1185		s6b.Grow(s6b.Size() + n)
1186		s6b.SetSize(s6b.Size() + n)
1187		size += n
1188	}
1189
1190	if size > 0 {
1191		linkoff = Rnd(int64(uint64(HEADR)+Segtext.Length), *FlagRound) + Rnd(int64(Segrelrodata.Filelen), *FlagRound) + Rnd(int64(Segdata.Filelen), *FlagRound) + Rnd(int64(Segdwarf.Filelen), *FlagRound)
1192		ctxt.Out.SeekSet(linkoff)
1193
1194		ctxt.Out.Write(ldr.Data(s1))
1195		ctxt.Out.Write(ldr.Data(s2))
1196		ctxt.Out.Write(ldr.Data(s3))
1197		ctxt.Out.Write(ldr.Data(s4))
1198		ctxt.Out.Write(ldr.Data(s5))
1199		ctxt.Out.Write(ldr.Data(s6))
1200
1201		// Add code signature if necessary. This must be the last.
1202		s7 := machoCodeSigSym(ctxt, linkoff+size)
1203		size += ldr.SymSize(s7)
1204	}
1205
1206	return Rnd(size, *FlagRound)
1207}
1208
1209func machorelocsect(ctxt *Link, out *OutBuf, sect *sym.Section, syms []loader.Sym) {
1210	// If main section has no bits, nothing to relocate.
1211	if sect.Vaddr >= sect.Seg.Vaddr+sect.Seg.Filelen {
1212		return
1213	}
1214	ldr := ctxt.loader
1215
1216	for i, s := range syms {
1217		if !ldr.AttrReachable(s) {
1218			continue
1219		}
1220		if uint64(ldr.SymValue(s)) >= sect.Vaddr {
1221			syms = syms[i:]
1222			break
1223		}
1224	}
1225
1226	eaddr := sect.Vaddr + sect.Length
1227	for _, s := range syms {
1228		if !ldr.AttrReachable(s) {
1229			continue
1230		}
1231		if ldr.SymValue(s) >= int64(eaddr) {
1232			break
1233		}
1234
1235		// Compute external relocations on the go, and pass to Machoreloc1
1236		// to stream out.
1237		relocs := ldr.Relocs(s)
1238		for ri := 0; ri < relocs.Count(); ri++ {
1239			r := relocs.At(ri)
1240			rr, ok := extreloc(ctxt, ldr, s, r)
1241			if !ok {
1242				continue
1243			}
1244			if rr.Xsym == 0 {
1245				ldr.Errorf(s, "missing xsym in relocation")
1246				continue
1247			}
1248			if !ldr.AttrReachable(rr.Xsym) {
1249				ldr.Errorf(s, "unreachable reloc %d (%s) target %v", r.Type(), sym.RelocName(ctxt.Arch, r.Type()), ldr.SymName(rr.Xsym))
1250			}
1251			if !thearch.Machoreloc1(ctxt.Arch, out, ldr, s, rr, int64(uint64(ldr.SymValue(s)+int64(r.Off()))-sect.Vaddr)) {
1252				ldr.Errorf(s, "unsupported obj reloc %d (%s)/%d to %s", r.Type(), sym.RelocName(ctxt.Arch, r.Type()), r.Siz(), ldr.SymName(r.Sym()))
1253			}
1254		}
1255	}
1256
1257	// sanity check
1258	if uint64(out.Offset()) != sect.Reloff+sect.Rellen {
1259		panic("machorelocsect: size mismatch")
1260	}
1261}
1262
1263func machoEmitReloc(ctxt *Link) {
1264	for ctxt.Out.Offset()&7 != 0 {
1265		ctxt.Out.Write8(0)
1266	}
1267
1268	sizeExtRelocs(ctxt, thearch.MachorelocSize)
1269	relocSect, wg := relocSectFn(ctxt, machorelocsect)
1270
1271	relocSect(ctxt, Segtext.Sections[0], ctxt.Textp)
1272	for _, sect := range Segtext.Sections[1:] {
1273		if sect.Name == ".text" {
1274			relocSect(ctxt, sect, ctxt.Textp)
1275		} else {
1276			relocSect(ctxt, sect, ctxt.datap)
1277		}
1278	}
1279	for _, sect := range Segrelrodata.Sections {
1280		relocSect(ctxt, sect, ctxt.datap)
1281	}
1282	for _, sect := range Segdata.Sections {
1283		relocSect(ctxt, sect, ctxt.datap)
1284	}
1285	for i := 0; i < len(Segdwarf.Sections); i++ {
1286		sect := Segdwarf.Sections[i]
1287		si := dwarfp[i]
1288		if si.secSym() != loader.Sym(sect.Sym) ||
1289			ctxt.loader.SymSect(si.secSym()) != sect {
1290			panic("inconsistency between dwarfp and Segdwarf")
1291		}
1292		relocSect(ctxt, sect, si.syms)
1293	}
1294	wg.Wait()
1295}
1296
1297// hostobjMachoPlatform returns the first platform load command found
1298// in the host object, if any.
1299func hostobjMachoPlatform(h *Hostobj) (*MachoPlatformLoad, error) {
1300	f, err := os.Open(h.file)
1301	if err != nil {
1302		return nil, fmt.Errorf("%s: failed to open host object: %v\n", h.file, err)
1303	}
1304	defer f.Close()
1305	sr := io.NewSectionReader(f, h.off, h.length)
1306	m, err := macho.NewFile(sr)
1307	if err != nil {
1308		// Not a valid Mach-O file.
1309		return nil, nil
1310	}
1311	return peekMachoPlatform(m)
1312}
1313
1314// peekMachoPlatform returns the first LC_VERSION_MIN_* or LC_BUILD_VERSION
1315// load command found in the Mach-O file, if any.
1316func peekMachoPlatform(m *macho.File) (*MachoPlatformLoad, error) {
1317	for _, cmd := range m.Loads {
1318		raw := cmd.Raw()
1319		ml := MachoLoad{
1320			type_: m.ByteOrder.Uint32(raw),
1321		}
1322		// Skip the type and command length.
1323		data := raw[8:]
1324		var p MachoPlatform
1325		switch ml.type_ {
1326		case LC_VERSION_MIN_IPHONEOS:
1327			p = PLATFORM_IOS
1328		case LC_VERSION_MIN_MACOSX:
1329			p = PLATFORM_MACOS
1330		case LC_VERSION_MIN_WATCHOS:
1331			p = PLATFORM_WATCHOS
1332		case LC_VERSION_MIN_TVOS:
1333			p = PLATFORM_TVOS
1334		case LC_BUILD_VERSION:
1335			p = MachoPlatform(m.ByteOrder.Uint32(data))
1336		default:
1337			continue
1338		}
1339		ml.data = make([]uint32, len(data)/4)
1340		r := bytes.NewReader(data)
1341		if err := binary.Read(r, m.ByteOrder, &ml.data); err != nil {
1342			return nil, err
1343		}
1344		return &MachoPlatformLoad{
1345			platform: p,
1346			cmd:      ml,
1347		}, nil
1348	}
1349	return nil, nil
1350}
1351
1352// A rebase entry tells the dynamic linker the data at sym+off needs to be
1353// relocated when the in-memory image moves. (This is somewhat like, say,
1354// ELF R_X86_64_RELATIVE).
1355// For now, the only kind of entry we support is that the data is an absolute
1356// address. That seems all we need.
1357// In the binary it uses a compact stateful bytecode encoding. So we record
1358// entries as we go and build the table at the end.
1359type machoRebaseRecord struct {
1360	sym loader.Sym
1361	off int64
1362}
1363
1364var machorebase []machoRebaseRecord
1365
1366func MachoAddRebase(s loader.Sym, off int64) {
1367	machorebase = append(machorebase, machoRebaseRecord{s, off})
1368}
1369
1370// A bind entry tells the dynamic linker the data at GOT+off should be bound
1371// to the address of the target symbol, which is a dynamic import.
1372// For now, the only kind of entry we support is that the data is an absolute
1373// address, and the source symbol is always the GOT. That seems all we need.
1374// In the binary it uses a compact stateful bytecode encoding. So we record
1375// entries as we go and build the table at the end.
1376type machoBindRecord struct {
1377	off  int64
1378	targ loader.Sym
1379}
1380
1381var machobind []machoBindRecord
1382
1383func MachoAddBind(off int64, targ loader.Sym) {
1384	machobind = append(machobind, machoBindRecord{off, targ})
1385}
1386
1387// Generate data for the dynamic linker, used in LC_DYLD_INFO_ONLY load command.
1388// See mach-o/loader.h, struct dyld_info_command, for the encoding.
1389// e.g. https://opensource.apple.com/source/xnu/xnu-6153.81.5/EXTERNAL_HEADERS/mach-o/loader.h
1390func machoDyldInfo(ctxt *Link) {
1391	ldr := ctxt.loader
1392	rebase := ldr.CreateSymForUpdate(".machorebase", 0)
1393	bind := ldr.CreateSymForUpdate(".machobind", 0)
1394
1395	if !(ctxt.IsPIE() && ctxt.IsInternal()) {
1396		return
1397	}
1398
1399	segId := func(seg *sym.Segment) uint8 {
1400		switch seg {
1401		case &Segtext:
1402			return 1
1403		case &Segrelrodata:
1404			return 2
1405		case &Segdata:
1406			if Segrelrodata.Length > 0 {
1407				return 3
1408			}
1409			return 2
1410		}
1411		panic("unknown segment")
1412	}
1413
1414	dylibId := func(s loader.Sym) int {
1415		slib := ldr.SymDynimplib(s)
1416		for i, lib := range dylib {
1417			if lib == slib {
1418				return i + 1
1419			}
1420		}
1421		return BIND_SPECIAL_DYLIB_FLAT_LOOKUP // don't know where it is from
1422	}
1423
1424	// Rebase table.
1425	// TODO: use more compact encoding. The encoding is stateful, and
1426	// we can use delta encoding.
1427	rebase.AddUint8(REBASE_OPCODE_SET_TYPE_IMM | REBASE_TYPE_POINTER)
1428	for _, r := range machorebase {
1429		seg := ldr.SymSect(r.sym).Seg
1430		off := uint64(ldr.SymValue(r.sym)+r.off) - seg.Vaddr
1431		rebase.AddUint8(REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | segId(seg))
1432		rebase.AddUleb(off)
1433
1434		rebase.AddUint8(REBASE_OPCODE_DO_REBASE_IMM_TIMES | 1)
1435	}
1436	rebase.AddUint8(REBASE_OPCODE_DONE)
1437	sz := Rnd(rebase.Size(), 8)
1438	rebase.Grow(sz)
1439	rebase.SetSize(sz)
1440
1441	// Bind table.
1442	// TODO: compact encoding, as above.
1443	// TODO: lazy binding?
1444	got := ctxt.GOT
1445	seg := ldr.SymSect(got).Seg
1446	gotAddr := ldr.SymValue(got)
1447	bind.AddUint8(BIND_OPCODE_SET_TYPE_IMM | BIND_TYPE_POINTER)
1448	for _, r := range machobind {
1449		off := uint64(gotAddr+r.off) - seg.Vaddr
1450		bind.AddUint8(BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | segId(seg))
1451		bind.AddUleb(off)
1452
1453		d := dylibId(r.targ)
1454		if d > 0 && d < 128 {
1455			bind.AddUint8(BIND_OPCODE_SET_DYLIB_ORDINAL_IMM | uint8(d)&0xf)
1456		} else if d >= 128 {
1457			bind.AddUint8(BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB)
1458			bind.AddUleb(uint64(d))
1459		} else { // d <= 0
1460			bind.AddUint8(BIND_OPCODE_SET_DYLIB_SPECIAL_IMM | uint8(d)&0xf)
1461		}
1462
1463		bind.AddUint8(BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM)
1464		// target symbol name as a C string, with _ prefix
1465		bind.AddUint8('_')
1466		bind.Addstring(ldr.SymExtname(r.targ))
1467
1468		bind.AddUint8(BIND_OPCODE_DO_BIND)
1469	}
1470	bind.AddUint8(BIND_OPCODE_DONE)
1471	sz = Rnd(bind.Size(), 16) // make it 16-byte aligned, see the comment in doMachoLink
1472	bind.Grow(sz)
1473	bind.SetSize(sz)
1474
1475	// TODO: export table.
1476	// The symbols names are encoded as a trie. I'm really too lazy to do that
1477	// for now.
1478	// Without it, the symbols are not dynamically exported, so they cannot be
1479	// e.g. dlsym'd. But internal linking is not the default in that case, so
1480	// it is fine.
1481}
1482
1483// machoCodeSigSym creates and returns a symbol for code signature.
1484// The symbol context is left as zeros, which will be generated at the end
1485// (as it depends on the rest of the file).
1486func machoCodeSigSym(ctxt *Link, codeSize int64) loader.Sym {
1487	ldr := ctxt.loader
1488	cs := ldr.CreateSymForUpdate(".machocodesig", 0)
1489	if !ctxt.NeedCodeSign() || ctxt.IsExternal() {
1490		return cs.Sym()
1491	}
1492	sz := codesign.Size(codeSize, "a.out")
1493	cs.Grow(sz)
1494	cs.SetSize(sz)
1495	return cs.Sym()
1496}
1497
1498// machoCodeSign code-signs Mach-O file fname with an ad-hoc signature.
1499// This is used for updating an external linker generated binary.
1500func machoCodeSign(ctxt *Link, fname string) error {
1501	f, err := os.OpenFile(fname, os.O_RDWR, 0)
1502	if err != nil {
1503		return err
1504	}
1505	defer f.Close()
1506
1507	mf, err := macho.NewFile(f)
1508	if err != nil {
1509		return err
1510	}
1511	if mf.Magic != macho.Magic64 {
1512		Exitf("not 64-bit Mach-O file: %s", fname)
1513	}
1514
1515	// Find existing LC_CODE_SIGNATURE and __LINKEDIT segment
1516	var sigOff, sigSz, csCmdOff, linkeditOff int64
1517	var linkeditSeg, textSeg *macho.Segment
1518	loadOff := int64(machoHeaderSize64)
1519	get32 := mf.ByteOrder.Uint32
1520	for _, l := range mf.Loads {
1521		data := l.Raw()
1522		cmd, sz := get32(data), get32(data[4:])
1523		if cmd == LC_CODE_SIGNATURE {
1524			sigOff = int64(get32(data[8:]))
1525			sigSz = int64(get32(data[12:]))
1526			csCmdOff = loadOff
1527		}
1528		if seg, ok := l.(*macho.Segment); ok {
1529			switch seg.Name {
1530			case "__LINKEDIT":
1531				linkeditSeg = seg
1532				linkeditOff = loadOff
1533			case "__TEXT":
1534				textSeg = seg
1535			}
1536		}
1537		loadOff += int64(sz)
1538	}
1539
1540	if sigOff == 0 {
1541		// The C linker doesn't generate a signed binary, for some reason.
1542		// Skip.
1543		return nil
1544	}
1545
1546	fi, err := f.Stat()
1547	if err != nil {
1548		return err
1549	}
1550	if sigOff+sigSz != fi.Size() {
1551		// We don't expect anything after the signature (this will invalidate
1552		// the signature anyway.)
1553		return fmt.Errorf("unexpected content after code signature")
1554	}
1555
1556	sz := codesign.Size(sigOff, "a.out")
1557	if sz != sigSz {
1558		// Update the load command,
1559		var tmp [8]byte
1560		mf.ByteOrder.PutUint32(tmp[:4], uint32(sz))
1561		_, err = f.WriteAt(tmp[:4], csCmdOff+12)
1562		if err != nil {
1563			return err
1564		}
1565
1566		// Uodate the __LINKEDIT segment.
1567		segSz := sigOff + sz - int64(linkeditSeg.Offset)
1568		mf.ByteOrder.PutUint64(tmp[:8], uint64(segSz))
1569		_, err = f.WriteAt(tmp[:8], int64(linkeditOff)+int64(unsafe.Offsetof(macho.Segment64{}.Memsz)))
1570		if err != nil {
1571			return err
1572		}
1573		_, err = f.WriteAt(tmp[:8], int64(linkeditOff)+int64(unsafe.Offsetof(macho.Segment64{}.Filesz)))
1574		if err != nil {
1575			return err
1576		}
1577	}
1578
1579	cs := make([]byte, sz)
1580	codesign.Sign(cs, f, "a.out", sigOff, int64(textSeg.Offset), int64(textSeg.Filesz), ctxt.IsExe() || ctxt.IsPIE())
1581	_, err = f.WriteAt(cs, sigOff)
1582	if err != nil {
1583		return err
1584	}
1585	err = f.Truncate(sigOff + sz)
1586	return err
1587}
1588