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