1
2
3
4
5 package ld
6
7 import (
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
25 type MachoHdr struct {
26 cpu uint32
27 subcpu uint32
28 }
29
30 type 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
44 type 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
59
60 type MachoPlatformLoad struct {
61 platform MachoPlatform
62 cmd MachoLoad
63 }
64
65 type MachoLoad struct {
66 type_ uint32
67 data []uint32
68 }
69
70 type MachoPlatform int
71
72
77 const (
78 INITIAL_MACHO_HEADR = 4 * 1024
79 )
80
81 const (
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
118 const (
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
130 const (
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
186 const (
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
197 const (
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
207 const (
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
226 const (
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
256 const machoHeaderSize64 = 8 * 4
257
258
259
260
261 var machohdr MachoHdr
262
263 var load []MachoLoad
264
265 var machoPlatform MachoPlatform
266
267 var seg [16]MachoSeg
268
269 var nseg int
270
271 var ndebug int
272
273 var nsect int
274
275 const (
276 SymKindLocal = 0 + iota
277 SymKindExtdef
278 SymKindUndef
279 NumSymKind
280 )
281
282 var nkind [NumSymKind]int
283
284 var sortsym []loader.Sym
285
286 var nsortsym int
287
288
289
290
291
292
293
294 var loadBudget = INITIAL_MACHO_HEADR - 2*1024
295
296 func getMachoHdr() *MachoHdr {
297 return &machohdr
298 }
299
300
301
302 func 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
314 func 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
327 func 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
341
342 var dylib []string
343
344 var linkoff int64
345
346 func 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)
370 } else {
371 out.Write32(MH_EXECUTE)
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)
383 if arch.PtrSize == 8 {
384 out.Write32(0)
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)
428 out.Write32(t.res2)
429 out.Write32(0)
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)
441 out.Write32(t.res2)
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
458 func (ctxt *Link) domacho() {
459 if *FlagD {
460 return
461 }
462
463
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
486
487
488
489 version = 11<<16 | 0<<8 | 0<<0
490 }
491 ml := newMachoLoad(ctxt.Arch, LC_BUILD_VERSION, 4)
492 ml.data[0] = uint32(machoPlatform)
493 ml.data[1] = version
494 ml.data[2] = version
495 ml.data[3] = 0
496 }
497 }
498
499
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)
515 sb = ctxt.loader.MakeSymbolUpdater(s)
516 sb.SetType(sym.SMACHOPLT)
517 sb.SetReachable(true)
518
519 s = ctxt.loader.LookupOrCreateSym(".got", 0)
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)
526 sb = ctxt.loader.MakeSymbolUpdater(s)
527 sb.SetType(sym.SMACHOINDIRECTPLT)
528 sb.SetReachable(true)
529
530 s = ctxt.loader.LookupOrCreateSym(".linkedit.got", 0)
531 sb = ctxt.loader.MakeSymbolUpdater(s)
532 sb.SetType(sym.SMACHOINDIRECTGOT)
533 sb.SetReachable(true)
534 }
535
536
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
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560 if ctxt.BuildMode == BuildModePlugin {
561 for _, name := range []string{"_cgo_topofstack", "__cgo_topofstack", "_cgo_panic", "crosscall2"} {
562
563
564 ver := 0
565
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
577 func machoadddynlib(lib string, linkmode LinkMode) {
578 if seenlib[lib] || linkmode == LinkExternal {
579 return
580 }
581 seenlib[lib] = true
582
583
584
585
586
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
598 func 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
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
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)
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
652
653
654
655
656
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
667 func 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
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
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
706 if ctxt.LinkMode != LinkExternal {
707 ms = newMachoSeg("__PAGEZERO", 0)
708 ms.vsize = uint64(va)
709 }
710
711
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
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
740 }
741
742 for _, sect := range Segrelrodata.Sections {
743 machoshbits(ctxt, ms, sect, "__DATA_CONST")
744 }
745
746
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
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
783 ml.data[1] = 42
784 ml.data[2+32] = uint32(Entryvalue(ctxt))
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
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)
820 ml.data[1] = uint32(s1)
821 ml.data[2] = uint32(linkoff + s1)
822 ml.data[3] = uint32(s2)
823 ml.data[4] = 0
824 ml.data[5] = 0
825 ml.data[6] = 0
826 ml.data[7] = 0
827 ml.data[8] = 0
828 ml.data[9] = 0
829 }
830
831 ml := newMachoLoad(ctxt.Arch, LC_SYMTAB, 4)
832 ml.data[0] = uint32(linkoff + s1 + s2)
833 ml.data[1] = uint32(nsortsym)
834 ml.data[2] = uint32(linkoff + s1 + s2 + s3 + s4 + s5)
835 ml.data[3] = uint32(s6)
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
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
847 ml.data[1] = 0
848 ml.data[2] = 0
849 ml.data[3] = 0
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
857 if len(buildinfo) < 16 {
858 buildinfo = append(buildinfo, make([]byte, 16)...)
859 }
860
861
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
881
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
894 func 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
904 func 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
913
914
915
916
917
918
919
920
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
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)
957 if name == "" || name[0] == '.' {
958 return false
959 }
960 return true
961 }
962
963
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 {
970 if t == sym.STLSBSS {
971
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
987 addsym(s)
988 }
989
990
991 if t == sym.SDYNIMPORT && ldr.SymDynimplib(s) == "/usr/lib/libSystem.B.dylib" {
992
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
1013 func machosymorder(ctxt *Link) {
1014 ldr := ctxt.loader
1015
1016
1017
1018
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)
1034 })
1035 for i, s := range sortsym {
1036 ldr.SetSymDynid(s, int32(i))
1037 }
1038 }
1039
1040
1041
1042 func 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
1050
1051
1052
1053 func 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
1066
1067
1068 return true
1069 }
1070 if strings.HasPrefix(name, "go:link.pkghash") {
1071 return true
1072 }
1073 return ldr.SymType(s) >= sym.SFirstWritable
1074 }
1075
1076 func 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
1087
1088
1089
1090 symstr.AddUint8('_')
1091
1092
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)
1100 symtab.AddUint8(0)
1101 symtab.AddUint16(ctxt.Arch, 0)
1102 symtab.AddUintXX(ctxt.Arch, 0, ctxt.Arch.PtrSize)
1103 } else {
1104 if export || ldr.AttrCgoExportDynamic(s) {
1105 symtab.AddUint8(0x0f)
1106 } else if ldr.AttrCgoExportStatic(s) {
1107
1108 symtab.AddUint8(0x1f)
1109 } else {
1110 symtab.AddUint8(0x0e)
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)
1123 symtab.AddUintXX(ctxt.Arch, uint64(ldr.SymAddr(s)), ctxt.Arch.PtrSize)
1124 }
1125 }
1126 }
1127
1128 func machodysymtab(ctxt *Link, base int64) {
1129 ml := newMachoLoad(ctxt.Arch, LC_DYSYMTAB, 18)
1130
1131 n := 0
1132 ml.data[0] = uint32(n)
1133 ml.data[1] = uint32(nkind[SymKindLocal])
1134 n += nkind[SymKindLocal]
1135
1136 ml.data[2] = uint32(n)
1137 ml.data[3] = uint32(nkind[SymKindExtdef])
1138 n += nkind[SymKindExtdef]
1139
1140 ml.data[4] = uint32(n)
1141 ml.data[5] = uint32(nkind[SymKindUndef])
1142
1143 ml.data[6] = 0
1144 ml.data[7] = 0
1145 ml.data[8] = 0
1146 ml.data[9] = 0
1147 ml.data[10] = 0
1148 ml.data[11] = 0
1149
1150 ldr := ctxt.loader
1151
1152
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)
1157 ml.data[13] = uint32((s2 + s3) / 4)
1158
1159 ml.data[14] = 0
1160 ml.data[15] = 0
1161 ml.data[16] = 0
1162 ml.data[17] = 0
1163 }
1164
1165 func doMachoLink(ctxt *Link) int64 {
1166 machosymtab(ctxt)
1167 machoDyldInfo(ctxt)
1168
1169 ldr := ctxt.loader
1170
1171
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
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
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
1218 s7 := machoCodeSigSym(ctxt, linkoff+size)
1219 size += ldr.SymSize(s7)
1220 }
1221
1222 return Rnd(size, *FlagRound)
1223 }
1224
1225 func machorelocsect(ctxt *Link, out *OutBuf, sect *sym.Section, syms []loader.Sym) {
1226
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
1252
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
1274 if uint64(out.Offset()) != sect.Reloff+sect.Rellen {
1275 panic("machorelocsect: size mismatch")
1276 }
1277 }
1278
1279 func 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
1314
1315 func 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
1325 return nil, nil
1326 }
1327 return peekMachoPlatform(m)
1328 }
1329
1330
1331
1332 func 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
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
1369
1370
1371
1372
1373
1374
1375 type machoRebaseRecord struct {
1376 sym loader.Sym
1377 off int64
1378 }
1379
1380 var machorebase []machoRebaseRecord
1381
1382 func MachoAddRebase(s loader.Sym, off int64) {
1383 machorebase = append(machorebase, machoRebaseRecord{s, off})
1384 }
1385
1386
1387
1388
1389
1390
1391
1392 type machoBindRecord struct {
1393 off int64
1394 targ loader.Sym
1395 }
1396
1397 var machobind []machoBindRecord
1398
1399 func MachoAddBind(off int64, targ loader.Sym) {
1400 machobind = append(machobind, machoBindRecord{off, targ})
1401 }
1402
1403
1404
1405
1406 func 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
1438 }
1439
1440
1441
1442
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
1458
1459
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 {
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
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)
1488 bind.Grow(sz)
1489 bind.SetSize(sz)
1490
1491
1492
1493
1494
1495
1496
1497 }
1498
1499
1500
1501
1502 func 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
1515
1516 func 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
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
1558
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
1568
1569 return fmt.Errorf("unexpected content after code signature")
1570 }
1571
1572 sz := codesign.Size(sigOff, "a.out")
1573 if sz != sigSz {
1574
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
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
View as plain text