1
2
3
4
5 package ld
6
7 import (
8 "bytes"
9 "cmd/internal/codesign"
10 "cmd/internal/hash"
11 imacho "cmd/internal/macho"
12 "cmd/internal/objabi"
13 "cmd/internal/sys"
14 "cmd/link/internal/loader"
15 "cmd/link/internal/sym"
16 "debug/macho"
17 "encoding/binary"
18 "fmt"
19 "internal/buildcfg"
20 "io"
21 "os"
22 "slices"
23 "sort"
24 "strconv"
25 "strings"
26 "unsafe"
27 )
28
29 type MachoHdr struct {
30 cpu uint32
31 subcpu uint32
32 }
33
34 type MachoSect struct {
35 name string
36 segname string
37 addr uint64
38 size uint64
39 off uint32
40 align uint32
41 reloc uint32
42 nreloc uint32
43 flag uint32
44 res1 uint32
45 res2 uint32
46 }
47
48 type MachoSeg struct {
49 name string
50 vsize uint64
51 vaddr uint64
52 fileoffset uint64
53 filesize uint64
54 prot1 uint32
55 prot2 uint32
56 nsect uint32
57 msect uint32
58 sect []MachoSect
59 flag uint32
60 }
61
62
63
64 type MachoPlatformLoad struct {
65 platform MachoPlatform
66 cmd MachoLoad
67 }
68
69 type MachoLoad struct {
70 type_ uint32
71 data []uint32
72 }
73
74 type MachoPlatform int
75
76
81 const (
82 INITIAL_MACHO_HEADR = 4 * 1024
83 )
84
85 const (
86 MACHO_CPU_AMD64 = 1<<24 | 7
87 MACHO_CPU_386 = 7
88 MACHO_SUBCPU_X86 = 3
89 MACHO_CPU_ARM = 12
90 MACHO_SUBCPU_ARM = 0
91 MACHO_SUBCPU_ARMV7 = 9
92 MACHO_CPU_ARM64 = 1<<24 | 12
93 MACHO_SUBCPU_ARM64_ALL = 0
94 MACHO_SUBCPU_ARM64_V8 = 1
95 MACHO_SUBCPU_ARM64E = 2
96 MACHO32SYMSIZE = 12
97 MACHO64SYMSIZE = 16
98 MACHO_X86_64_RELOC_UNSIGNED = 0
99 MACHO_X86_64_RELOC_SIGNED = 1
100 MACHO_X86_64_RELOC_BRANCH = 2
101 MACHO_X86_64_RELOC_GOT_LOAD = 3
102 MACHO_X86_64_RELOC_GOT = 4
103 MACHO_X86_64_RELOC_SUBTRACTOR = 5
104 MACHO_X86_64_RELOC_SIGNED_1 = 6
105 MACHO_X86_64_RELOC_SIGNED_2 = 7
106 MACHO_X86_64_RELOC_SIGNED_4 = 8
107 MACHO_ARM_RELOC_VANILLA = 0
108 MACHO_ARM_RELOC_PAIR = 1
109 MACHO_ARM_RELOC_SECTDIFF = 2
110 MACHO_ARM_RELOC_BR24 = 5
111 MACHO_ARM64_RELOC_UNSIGNED = 0
112 MACHO_ARM64_RELOC_SUBTRACTOR = 1
113 MACHO_ARM64_RELOC_BRANCH26 = 2
114 MACHO_ARM64_RELOC_PAGE21 = 3
115 MACHO_ARM64_RELOC_PAGEOFF12 = 4
116 MACHO_ARM64_RELOC_GOT_LOAD_PAGE21 = 5
117 MACHO_ARM64_RELOC_GOT_LOAD_PAGEOFF12 = 6
118 MACHO_ARM64_RELOC_POINTER_TO_GOT = 7
119 MACHO_ARM64_RELOC_ADDEND = 10
120 MACHO_GENERIC_RELOC_VANILLA = 0
121 MACHO_FAKE_GOTPCREL = 100
122 )
123
124 const (
125 MH_MAGIC = 0xfeedface
126 MH_MAGIC_64 = 0xfeedfacf
127
128 MH_OBJECT = 0x1
129 MH_EXECUTE = 0x2
130 MH_DSYM = 0xa
131
132 MH_NOUNDEFS = 0x1
133 MH_DYLDLINK = 0x4
134 MH_PIE = 0x200000
135 )
136
137 const (
138 S_REGULAR = 0x0
139 S_ZEROFILL = 0x1
140 S_NON_LAZY_SYMBOL_POINTERS = 0x6
141 S_SYMBOL_STUBS = 0x8
142 S_MOD_INIT_FUNC_POINTERS = 0x9
143 S_ATTR_PURE_INSTRUCTIONS = 0x80000000
144 S_ATTR_DEBUG = 0x02000000
145 S_ATTR_SOME_INSTRUCTIONS = 0x00000400
146 )
147
148 const (
149 PLATFORM_MACOS MachoPlatform = 1
150 PLATFORM_IOS MachoPlatform = 2
151 PLATFORM_TVOS MachoPlatform = 3
152 PLATFORM_WATCHOS MachoPlatform = 4
153 PLATFORM_BRIDGEOS MachoPlatform = 5
154 PLATFORM_MACCATALYST MachoPlatform = 6
155 )
156
157
158 const (
159 REBASE_TYPE_POINTER = 1
160 REBASE_TYPE_TEXT_ABSOLUTE32 = 2
161 REBASE_TYPE_TEXT_PCREL32 = 3
162
163 REBASE_OPCODE_MASK = 0xF0
164 REBASE_IMMEDIATE_MASK = 0x0F
165 REBASE_OPCODE_DONE = 0x00
166 REBASE_OPCODE_SET_TYPE_IMM = 0x10
167 REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB = 0x20
168 REBASE_OPCODE_ADD_ADDR_ULEB = 0x30
169 REBASE_OPCODE_ADD_ADDR_IMM_SCALED = 0x40
170 REBASE_OPCODE_DO_REBASE_IMM_TIMES = 0x50
171 REBASE_OPCODE_DO_REBASE_ULEB_TIMES = 0x60
172 REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB = 0x70
173 REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB = 0x80
174 )
175
176
177 const (
178 BIND_TYPE_POINTER = 1
179 BIND_TYPE_TEXT_ABSOLUTE32 = 2
180 BIND_TYPE_TEXT_PCREL32 = 3
181
182 BIND_SPECIAL_DYLIB_SELF = 0
183 BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE = -1
184 BIND_SPECIAL_DYLIB_FLAT_LOOKUP = -2
185 BIND_SPECIAL_DYLIB_WEAK_LOOKUP = -3
186
187 BIND_SYMBOL_FLAGS_WEAK_IMPORT = 0x1
188
189 BIND_OPCODE_MASK = 0xF0
190 BIND_IMMEDIATE_MASK = 0x0F
191 BIND_OPCODE_DONE = 0x00
192 BIND_OPCODE_SET_DYLIB_ORDINAL_IMM = 0x10
193 BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB = 0x20
194 BIND_OPCODE_SET_DYLIB_SPECIAL_IMM = 0x30
195 BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM = 0x40
196 BIND_OPCODE_SET_TYPE_IMM = 0x50
197 BIND_OPCODE_SET_ADDEND_SLEB = 0x60
198 BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB = 0x70
199 BIND_OPCODE_ADD_ADDR_ULEB = 0x80
200 BIND_OPCODE_DO_BIND = 0x90
201 BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB = 0xA0
202 BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED = 0xB0
203 BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB = 0xC0
204 BIND_OPCODE_THREADED = 0xD0
205 BIND_SUBOPCODE_THREADED_SET_BIND_ORDINAL_TABLE_SIZE_ULEB = 0x00
206 BIND_SUBOPCODE_THREADED_APPLY = 0x01
207 )
208
209 const machoHeaderSize64 = 8 * 4
210
211
212
213
214 var machohdr MachoHdr
215
216 var load []MachoLoad
217
218 var machoPlatform MachoPlatform
219
220 var seg [16]MachoSeg
221
222 var nseg int
223
224 var ndebug int
225
226 var nsect int
227
228 const (
229 SymKindLocal = 0 + iota
230 SymKindExtdef
231 SymKindUndef
232 NumSymKind
233 )
234
235 var nkind [NumSymKind]int
236
237 var sortsym []loader.Sym
238
239 var nsortsym int
240
241
242
243
244
245
246
247 var loadBudget = INITIAL_MACHO_HEADR - 2*1024
248
249 func getMachoHdr() *MachoHdr {
250 return &machohdr
251 }
252
253
254
255 func newMachoLoad(arch *sys.Arch, type_ uint32, ndata uint32) *MachoLoad {
256 if ndata&1 != 0 {
257 ndata++
258 }
259
260 load = append(load, MachoLoad{})
261 l := &load[len(load)-1]
262 l.type_ = type_
263 l.data = make([]uint32, ndata)
264 return l
265 }
266
267 func newMachoSeg(name string, msect int) *MachoSeg {
268 if nseg >= len(seg) {
269 Exitf("too many segs")
270 }
271
272 s := &seg[nseg]
273 nseg++
274 s.name = name
275 s.msect = uint32(msect)
276 s.sect = make([]MachoSect, msect)
277 return s
278 }
279
280 func newMachoSect(seg *MachoSeg, name string, segname string) *MachoSect {
281 if seg.nsect >= seg.msect {
282 Exitf("too many sects in segment %s", seg.name)
283 }
284
285 s := &seg.sect[seg.nsect]
286 seg.nsect++
287 s.name = name
288 s.segname = segname
289 nsect++
290 return s
291 }
292
293
294
295 var dylib []string
296
297 var linkoff int64
298
299 func machowrite(ctxt *Link, arch *sys.Arch, out *OutBuf, linkmode LinkMode) int {
300 o1 := out.Offset()
301
302 loadsize := 4 * 4 * ndebug
303 for i := range load {
304 loadsize += 4 * (len(load[i].data) + 2)
305 }
306 loadsize += 18 * 4 * nseg
307 loadsize += 20 * 4 * nsect
308
309 out.Write32(MH_MAGIC_64)
310 out.Write32(machohdr.cpu)
311 out.Write32(machohdr.subcpu)
312 if out == ctxt.OutDWARF {
313 out.Write32(MH_DSYM)
314 } else if linkmode == LinkExternal {
315 out.Write32(MH_OBJECT)
316 } else {
317 out.Write32(MH_EXECUTE)
318 }
319 out.Write32(uint32(len(load)) + uint32(nseg) + uint32(ndebug))
320 out.Write32(uint32(loadsize))
321 flags := uint32(0)
322 if out != ctxt.OutDWARF {
323 if nkind[SymKindUndef] == 0 {
324 flags |= MH_NOUNDEFS
325 }
326 if ctxt.IsPIE() && linkmode == LinkInternal {
327 flags |= MH_PIE | MH_DYLDLINK
328 }
329 }
330 out.Write32(flags)
331 out.Write32(0)
332
333 for i := 0; i < nseg; i++ {
334 s := &seg[i]
335 out.Write32(imacho.LC_SEGMENT_64)
336 out.Write32(72 + 80*s.nsect)
337 out.WriteStringN(s.name, 16)
338 out.Write64(s.vaddr)
339 out.Write64(s.vsize)
340 out.Write64(s.fileoffset)
341 out.Write64(s.filesize)
342 out.Write32(s.prot1)
343 out.Write32(s.prot2)
344 out.Write32(s.nsect)
345 out.Write32(s.flag)
346
347 for j := uint32(0); j < s.nsect; j++ {
348 t := &s.sect[j]
349 out.WriteStringN(t.name, 16)
350 out.WriteStringN(t.segname, 16)
351 out.Write64(t.addr)
352 out.Write64(t.size)
353 out.Write32(t.off)
354 out.Write32(t.align)
355 out.Write32(t.reloc)
356 out.Write32(t.nreloc)
357 out.Write32(t.flag)
358 out.Write32(t.res1)
359 out.Write32(t.res2)
360 out.Write32(0)
361 }
362 }
363
364 for i := range load {
365 l := &load[i]
366 out.Write32(l.type_)
367 out.Write32(4 * (uint32(len(l.data)) + 2))
368 for j := 0; j < len(l.data); j++ {
369 out.Write32(l.data[j])
370 }
371 }
372
373 return int(out.Offset() - o1)
374 }
375
376 type macVersionFlag [3]byte
377
378 func (f *macVersionFlag) String() string {
379 return fmt.Sprintf("%d.%d.%d", f[0], f[1], f[2])
380 }
381
382 func (f *macVersionFlag) Set(s string) error {
383 var parsed macVersionFlag
384 nums := strings.Split(s, ".")
385 if len(nums) > 3 {
386 goto Error
387 }
388 for i, num := range nums {
389 n, err := strconv.Atoi(num)
390 if err != nil || n < 0 || n > 0xFF {
391 goto Error
392 }
393 parsed[i] = byte(n)
394 }
395
396 *f = parsed
397 return nil
398
399 Error:
400 return fmt.Errorf("invalid version %q", s)
401 }
402
403 func (f *macVersionFlag) version() uint32 {
404 return uint32(f[0])<<16 | uint32(f[1])<<8 | uint32(f[2])
405 }
406
407 var (
408
409
410
411
412
413
414
415
416 macOS = macVersionFlag{13, 0, 0}
417 macSDK = macVersionFlag{26, 2, 0}
418 )
419
420 func (ctxt *Link) domacho() {
421
422 for _, h := range hostobj {
423 load, err := hostobjMachoPlatform(&h)
424 if err != nil {
425 Exitf("%v", err)
426 }
427 if load != nil && load.platform != PLATFORM_MACOS {
428 ml := newMachoLoad(ctxt.Arch, load.cmd.type_, uint32(len(load.cmd.data)))
429 copy(ml.data, load.cmd.data)
430 break
431 }
432 }
433 if machoPlatform == 0 {
434 machoPlatform = PLATFORM_MACOS
435 if buildcfg.GOOS == "ios" {
436 machoPlatform = PLATFORM_IOS
437 }
438 if load == nil && machoPlatform == PLATFORM_MACOS {
439 ml := newMachoLoad(ctxt.Arch, imacho.LC_BUILD_VERSION, 4)
440 ml.data[0] = uint32(machoPlatform)
441 ml.data[1] = macOS.version()
442 ml.data[2] = macSDK.version()
443 ml.data[3] = 0
444 }
445 }
446
447
448 s := ctxt.loader.LookupOrCreateSym(".machosymstr", 0)
449 sb := ctxt.loader.MakeSymbolUpdater(s)
450
451 sb.SetType(sym.SMACHOSYMSTR)
452 sb.SetReachable(true)
453 sb.AddUint8(' ')
454 sb.AddUint8('\x00')
455
456 s = ctxt.loader.LookupOrCreateSym(".machosymtab", 0)
457 sb = ctxt.loader.MakeSymbolUpdater(s)
458 sb.SetType(sym.SMACHOSYMTAB)
459 sb.SetReachable(true)
460
461 if ctxt.IsInternal() {
462 s = ctxt.loader.LookupOrCreateSym(".plt", 0)
463 sb = ctxt.loader.MakeSymbolUpdater(s)
464 sb.SetType(sym.SMACHOPLT)
465 sb.SetReachable(true)
466
467 s = ctxt.loader.LookupOrCreateSym(".got", 0)
468 sb = ctxt.loader.MakeSymbolUpdater(s)
469 if ctxt.UseRelro() {
470 sb.SetType(sym.SMACHORELROSECT)
471 } else {
472 sb.SetType(sym.SMACHOGOT)
473 }
474 sb.SetReachable(true)
475 sb.SetAlign(4)
476
477 s = ctxt.loader.LookupOrCreateSym(".linkedit.plt", 0)
478 sb = ctxt.loader.MakeSymbolUpdater(s)
479 sb.SetType(sym.SMACHOINDIRECTPLT)
480 sb.SetReachable(true)
481
482 s = ctxt.loader.LookupOrCreateSym(".linkedit.got", 0)
483 sb = ctxt.loader.MakeSymbolUpdater(s)
484 sb.SetType(sym.SMACHOINDIRECTGOT)
485 sb.SetReachable(true)
486 }
487
488
489 if ctxt.IsExternal() {
490 s = ctxt.loader.LookupOrCreateSym(".llvmasm", 0)
491 sb = ctxt.loader.MakeSymbolUpdater(s)
492 sb.SetType(sym.SMACHO)
493 sb.SetReachable(true)
494 sb.AddUint8(0)
495 }
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512 if ctxt.BuildMode == BuildModePlugin {
513 for _, name := range []string{"_cgo_topofstack", "__cgo_topofstack", "_cgo_panic", "crosscall2"} {
514
515
516 ver := 0
517
518 if name == "_cgo_panic" {
519 ver = abiInternalVer
520 }
521 s := ctxt.loader.Lookup(name, ver)
522 if s != 0 {
523 ctxt.loader.SetAttrCgoExportDynamic(s, false)
524 }
525 }
526 }
527 }
528
529 func machoadddynlib(lib string, linkmode LinkMode) {
530 if seenlib[lib] || linkmode == LinkExternal {
531 return
532 }
533 seenlib[lib] = true
534
535
536
537
538
539 loadBudget -= (len(lib)+7)/8*8 + 24
540
541 if loadBudget < 0 {
542 HEADR += 4096
543 *FlagTextAddr += 4096
544 loadBudget += 4096
545 }
546
547 dylib = append(dylib, lib)
548 }
549
550 func machoshbits(ctxt *Link, mseg *MachoSeg, sect *sym.Section, segname string) {
551 buf := "__" + strings.ReplaceAll(sect.Name[1:], ".", "_")
552
553 msect := newMachoSect(mseg, buf, segname)
554
555 if sect.Rellen > 0 {
556 msect.reloc = uint32(sect.Reloff)
557 msect.nreloc = uint32(sect.Rellen / 8)
558 }
559
560 for 1<<msect.align < sect.Align {
561 msect.align++
562 }
563 msect.addr = sect.Vaddr
564 msect.size = sect.Length
565
566 if sect.Vaddr < sect.Seg.Vaddr+sect.Seg.Filelen {
567
568 if sect.Length > sect.Seg.Vaddr+sect.Seg.Filelen-sect.Vaddr {
569 Errorf("macho cannot represent section %s crossing data and bss", sect.Name)
570 }
571 msect.off = uint32(sect.Seg.Fileoff + sect.Vaddr - sect.Seg.Vaddr)
572 } else {
573 msect.off = 0
574 msect.flag |= S_ZEROFILL
575 }
576
577 if sect.Rwx&1 != 0 {
578 msect.flag |= S_ATTR_SOME_INSTRUCTIONS
579 }
580
581 if sect.Name == ".text" {
582 msect.flag |= S_ATTR_PURE_INSTRUCTIONS
583 }
584
585 if sect.Name == ".plt" {
586 msect.name = "__symbol_stub1"
587 msect.flag = S_ATTR_PURE_INSTRUCTIONS | S_ATTR_SOME_INSTRUCTIONS | S_SYMBOL_STUBS
588 msect.res1 = 0
589 msect.res2 = 6
590 }
591
592 if sect.Name == ".got" {
593 msect.name = "__got"
594 msect.flag = S_NON_LAZY_SYMBOL_POINTERS
595 msect.res1 = uint32(ctxt.loader.SymSize(ctxt.ArchSyms.LinkEditPLT) / 4)
596 }
597
598 if sect.Name == ".init_array" {
599 msect.name = "__mod_init_func"
600 msect.flag = S_MOD_INIT_FUNC_POINTERS
601 }
602
603
604
605
606
607
608
609 if sect.Name == ".llvmasm" {
610 msect.name = "__asm"
611 msect.segname = "__LLVM"
612 }
613
614 if segname == "__DWARF" {
615 msect.flag |= S_ATTR_DEBUG
616 }
617 }
618
619 func asmbMacho(ctxt *Link) {
620 machlink := doMachoLink(ctxt)
621 if ctxt.IsExternal() {
622 symo := int64(Segdwarf.Fileoff + uint64(Rnd(int64(Segdwarf.Filelen), *FlagRound)) + uint64(machlink))
623 ctxt.Out.SeekSet(symo)
624 machoEmitReloc(ctxt)
625 }
626 ctxt.Out.SeekSet(0)
627
628 ldr := ctxt.loader
629
630
631 va := *FlagTextAddr - int64(HEADR)
632
633 mh := getMachoHdr()
634 switch ctxt.Arch.Family {
635 default:
636 Exitf("unknown macho architecture: %v", ctxt.Arch.Family)
637
638 case sys.AMD64:
639 mh.cpu = MACHO_CPU_AMD64
640 mh.subcpu = MACHO_SUBCPU_X86
641
642 case sys.ARM64:
643 mh.cpu = MACHO_CPU_ARM64
644 mh.subcpu = MACHO_SUBCPU_ARM64_ALL
645 }
646
647 var ms *MachoSeg
648 if ctxt.LinkMode == LinkExternal {
649
650 ms = newMachoSeg("", 40)
651
652 ms.fileoffset = Segtext.Fileoff
653 ms.filesize = Segdwarf.Fileoff + Segdwarf.Filelen - Segtext.Fileoff
654 ms.vsize = Segdwarf.Vaddr + Segdwarf.Length - Segtext.Vaddr
655 }
656
657
658 if ctxt.LinkMode != LinkExternal {
659 ms = newMachoSeg("__PAGEZERO", 0)
660 ms.vsize = uint64(va)
661 }
662
663
664 v := Rnd(int64(uint64(HEADR)+Segtext.Length), *FlagRound)
665
666 var mstext *MachoSeg
667 if ctxt.LinkMode != LinkExternal {
668 ms = newMachoSeg("__TEXT", 20)
669 ms.vaddr = uint64(va)
670 ms.vsize = uint64(v)
671 ms.fileoffset = 0
672 ms.filesize = uint64(v)
673 ms.prot1 = 7
674 ms.prot2 = 5
675 mstext = ms
676 }
677
678 for _, sect := range Segtext.Sections {
679 machoshbits(ctxt, ms, sect, "__TEXT")
680 }
681
682
683 if ctxt.LinkMode != LinkExternal && Segrelrodata.Length > 0 {
684 ms = newMachoSeg("__DATA_CONST", 20)
685 ms.vaddr = Segrelrodata.Vaddr
686 ms.vsize = Segrelrodata.Length
687 ms.fileoffset = Segrelrodata.Fileoff
688 ms.filesize = Segrelrodata.Filelen
689 ms.prot1 = 3
690 ms.prot2 = 3
691 ms.flag = 0x10
692 }
693
694 for _, sect := range Segrelrodata.Sections {
695 machoshbits(ctxt, ms, sect, "__DATA_CONST")
696 }
697
698
699 if ctxt.LinkMode != LinkExternal {
700 ms = newMachoSeg("__DATA", 20)
701 ms.vaddr = Segdata.Vaddr
702 ms.vsize = Segdata.Length
703 ms.fileoffset = Segdata.Fileoff
704 ms.filesize = Segdata.Filelen
705 ms.prot1 = 3
706 ms.prot2 = 3
707 }
708
709 for _, sect := range Segdata.Sections {
710 machoshbits(ctxt, ms, sect, "__DATA")
711 }
712
713
714 if !*FlagW && !(*FlagSplitDWARF && ctxt.IsInternal()) {
715 if ctxt.LinkMode != LinkExternal {
716 ms = newMachoSeg("__DWARF", 20)
717 ms.vaddr = Segdwarf.Vaddr
718 ms.vsize = 0
719 ms.fileoffset = Segdwarf.Fileoff
720 ms.filesize = Segdwarf.Filelen
721 }
722 for _, sect := range Segdwarf.Sections {
723 machoshbits(ctxt, ms, sect, "__DWARF")
724 }
725 }
726
727 if ctxt.LinkMode != LinkExternal {
728 switch ctxt.Arch.Family {
729 default:
730 Exitf("unknown macho architecture: %v", ctxt.Arch.Family)
731
732 case sys.AMD64:
733 ml := newMachoLoad(ctxt.Arch, imacho.LC_UNIXTHREAD, 42+2)
734 ml.data[0] = 4
735 ml.data[1] = 42
736 ml.data[2+32] = uint32(Entryvalue(ctxt))
737 ml.data[2+32+1] = uint32(Entryvalue(ctxt) >> 32)
738
739 case sys.ARM64:
740 ml := newMachoLoad(ctxt.Arch, imacho.LC_MAIN, 4)
741 ml.data[0] = uint32(uint64(Entryvalue(ctxt)) - (Segtext.Vaddr - uint64(HEADR)))
742 ml.data[1] = uint32((uint64(Entryvalue(ctxt)) - (Segtext.Vaddr - uint64(HEADR))) >> 32)
743 }
744 }
745
746 var codesigOff int64
747
748 s1 := ldr.SymSize(ldr.Lookup(".machorebase", 0))
749 s2 := ldr.SymSize(ldr.Lookup(".machobind", 0))
750 s3 := ldr.SymSize(ldr.Lookup(".machosymtab", 0))
751 s4 := ldr.SymSize(ctxt.ArchSyms.LinkEditPLT)
752 s5 := ldr.SymSize(ctxt.ArchSyms.LinkEditGOT)
753 s6 := ldr.SymSize(ldr.Lookup(".machosymstr", 0))
754 padding := Rnd(s1+s2+s3+s4+s5+s6, 16) - (s1 + s2 + s3 + s4 + s5 + s6)
755 s7 := ldr.SymSize(ldr.Lookup(".machocodesig", 0))
756
757 if ctxt.LinkMode != LinkExternal {
758 ms := newMachoSeg("__LINKEDIT", 0)
759 ms.vaddr = uint64(Rnd(int64(Segdata.Vaddr+Segdata.Length), *FlagRound))
760 ms.vsize = uint64(s1 + s2 + s3 + s4 + s5 + s6 + padding + s7)
761 ms.fileoffset = uint64(linkoff)
762 ms.filesize = ms.vsize
763 ms.prot1 = 1
764 ms.prot2 = 1
765
766 codesigOff = linkoff + s1 + s2 + s3 + s4 + s5 + s6 + padding
767 }
768
769 if ctxt.LinkMode != LinkExternal && ctxt.IsPIE() {
770 ml := newMachoLoad(ctxt.Arch, imacho.LC_DYLD_INFO_ONLY, 10)
771 ml.data[0] = uint32(linkoff)
772 ml.data[1] = uint32(s1)
773 ml.data[2] = uint32(linkoff + s1)
774 ml.data[3] = uint32(s2)
775 ml.data[4] = 0
776 ml.data[5] = 0
777 ml.data[6] = 0
778 ml.data[7] = 0
779 ml.data[8] = 0
780 ml.data[9] = 0
781 }
782
783 ml := newMachoLoad(ctxt.Arch, imacho.LC_SYMTAB, 4)
784 ml.data[0] = uint32(linkoff + s1 + s2)
785 ml.data[1] = uint32(nsortsym)
786 ml.data[2] = uint32(linkoff + s1 + s2 + s3 + s4 + s5)
787 ml.data[3] = uint32(s6)
788
789 if ctxt.LinkMode != LinkExternal {
790 machodysymtab(ctxt, linkoff+s1+s2)
791
792 ml := newMachoLoad(ctxt.Arch, imacho.LC_LOAD_DYLINKER, 6)
793 ml.data[0] = 12
794 stringtouint32(ml.data[1:], "/usr/lib/dyld")
795
796 for _, lib := range dylib {
797 ml = newMachoLoad(ctxt.Arch, imacho.LC_LOAD_DYLIB, 4+(uint32(len(lib))+1+7)/8*2)
798 ml.data[0] = 24
799 ml.data[1] = 0
800 ml.data[2] = 0
801 ml.data[3] = 0
802 stringtouint32(ml.data[4:], lib)
803 }
804 }
805
806 if ctxt.IsInternal() && *flagHostBuildid != "none" {
807 ml := newMachoLoad(ctxt.Arch, imacho.LC_UUID, 4)
808 var uuid [16]byte
809 if len(buildinfo) >= 16 {
810 copy(uuid[:], buildinfo)
811 } else {
812
813
814
815
816
817
818 copy(uuid[:], uuidFromHash(hash.Sum32(ctxt.Out.Data())))
819 }
820 ml.data[0] = ctxt.Arch.ByteOrder.Uint32(uuid[0:])
821 ml.data[1] = ctxt.Arch.ByteOrder.Uint32(uuid[4:])
822 ml.data[2] = ctxt.Arch.ByteOrder.Uint32(uuid[8:])
823 ml.data[3] = ctxt.Arch.ByteOrder.Uint32(uuid[12:])
824 }
825
826 if ctxt.IsInternal() && ctxt.NeedCodeSign() {
827 ml := newMachoLoad(ctxt.Arch, imacho.LC_CODE_SIGNATURE, 2)
828 ml.data[0] = uint32(codesigOff)
829 ml.data[1] = uint32(s7)
830 }
831
832 a := machowrite(ctxt, ctxt.Arch, ctxt.Out, ctxt.LinkMode)
833 if int32(a) > HEADR {
834 Exitf("HEADR too small: %d > %d", a, HEADR)
835 }
836
837
838
839 if ctxt.IsInternal() && ctxt.NeedCodeSign() {
840 cs := ldr.Lookup(".machocodesig", 0)
841 data := ctxt.Out.Data()
842 if int64(len(data)) != codesigOff {
843 panic("wrong size")
844 }
845 codesign.Sign(ldr.Data(cs), bytes.NewBuffer(data), "a.out", codesigOff, int64(mstext.fileoffset), int64(mstext.filesize), ctxt.IsExe() || ctxt.IsPIE())
846 ctxt.Out.SeekSet(codesigOff)
847 ctxt.Out.Write(ldr.Data(cs))
848 }
849
850 if *FlagSplitDWARF && ctxt.IsInternal() {
851
852
853
854
855
856
857
858
859
860
861
862
863
864 symtab := ldr.Lookup(".machosymtab", 0)
865 symstr := ldr.Lookup(".machosymstr", 0)
866 symtabSz := ldr.SymSize(symtab)
867 symstrSz := ldr.SymSize(symstr)
868 linkeditOff := Rnd(int64(HEADR), *FlagRound)
869 ctxt.OutDWARF.SeekSet(linkeditOff)
870 ctxt.OutDWARF.Write(ldr.Data(symtab))
871 ctxt.OutDWARF.Write(ldr.Data(symstr))
872 if Rnd(ctxt.OutDWARF.Offset(), *FlagRound) != int64(Segdwarf.Fileoff) {
873 panic("splitdwarf __LINKEDIT size mismatch")
874 }
875 ctxt.OutDWARF.SeekSet(0)
876
877 for i := range seg[:nseg] {
878 s := &seg[i]
879 if s.name == "__LINKEDIT" {
880 s.vsize = uint64(symtabSz + symstrSz)
881 s.fileoffset = uint64(linkeditOff)
882 s.filesize = s.vsize
883 continue
884 }
885
886 s.fileoffset = 0
887 s.filesize = 0
888 for j := range s.nsect {
889 s.sect[j].off = 0
890 }
891 }
892
893 ms := newMachoSeg("__DWARF", 20)
894 ms.vaddr = Segdwarf.Vaddr
895 ms.vsize = Segdwarf.Length
896 ms.fileoffset = Segdwarf.Fileoff
897 ms.filesize = Segdwarf.Filelen
898 ms.prot1 = 7
899 ms.prot2 = 3
900 for _, sect := range Segdwarf.Sections {
901 machoshbits(ctxt, ms, sect, "__DWARF")
902 }
903
904
905
906 load = slices.DeleteFunc(load, func(l MachoLoad) bool {
907 return l.type_ != imacho.LC_BUILD_VERSION && l.type_ != imacho.LC_UUID && l.type_ != imacho.LC_SYMTAB
908 })
909 for i := range load {
910 if load[i].type_ == imacho.LC_SYMTAB {
911 load[i].data[0] = uint32(linkeditOff)
912 load[i].data[1] = uint32(nsortsym)
913 load[i].data[2] = uint32(linkeditOff + symtabSz)
914 load[i].data[3] = uint32(symstrSz)
915 }
916 }
917
918 a := machowrite(ctxt, ctxt.Arch, ctxt.OutDWARF, ctxt.LinkMode)
919 if int32(a) > HEADR {
920 Exitf("HEADR too small: %d > %d", a, HEADR)
921 }
922 }
923 }
924
925 func symkind(ldr *loader.Loader, s loader.Sym) int {
926 if t := ldr.SymType(s); t == sym.SDYNIMPORT || t == sym.SHOSTOBJ || t == sym.SUNDEFEXT {
927 return SymKindUndef
928 }
929 if ldr.AttrCgoExport(s) {
930 return SymKindExtdef
931 }
932 return SymKindLocal
933 }
934
935 func collectmachosyms(ctxt *Link) {
936 ldr := ctxt.loader
937
938 addsym := func(s loader.Sym) {
939 sortsym = append(sortsym, s)
940 nkind[symkind(ldr, s)]++
941 }
942
943
944
945
946
947
948
949
950
951
952 if !*FlagS {
953 if !ctxt.DynlinkingGo() {
954 s := ldr.Lookup("runtime.text", 0)
955 if ldr.SymType(s).IsText() {
956 addsym(s)
957 }
958 }
959 for n := range Segtext.Sections[1:] {
960 s := ldr.Lookup(fmt.Sprintf("runtime.text.%d", n+1), 0)
961 if s != 0 {
962 addsym(s)
963 } else {
964 break
965 }
966 }
967 if !ctxt.DynlinkingGo() {
968 s := ldr.Lookup("runtime.etext", 0)
969 if ldr.SymType(s).IsText() {
970 addsym(s)
971 }
972 }
973 }
974
975
976 for _, s := range ctxt.Textp {
977 if *FlagS && !ldr.AttrCgoExportDynamic(s) {
978 continue
979 }
980 addsym(s)
981 }
982
983 shouldBeInSymbolTable := func(s loader.Sym) bool {
984 if ldr.AttrNotInSymbolTable(s) {
985 return false
986 }
987 name := ldr.SymName(s)
988 if name == "" || name[0] == '.' {
989 return false
990 }
991 return true
992 }
993
994
995 for s := loader.Sym(1); s < loader.Sym(ldr.NSym()); s++ {
996 if !ldr.AttrReachable(s) {
997 continue
998 }
999 t := ldr.SymType(s)
1000 if t >= sym.SELFRXSECT && t < sym.SFirstUnallocated {
1001 if t == sym.STLSBSS {
1002
1003 continue
1004 }
1005 if !shouldBeInSymbolTable(s) {
1006 continue
1007 }
1008 if *FlagS && !ldr.AttrCgoExportDynamic(s) {
1009 continue
1010 }
1011 addsym(s)
1012 continue
1013 }
1014
1015 switch t {
1016 case sym.SDYNIMPORT, sym.SHOSTOBJ, sym.SUNDEFEXT:
1017
1018 addsym(s)
1019 }
1020
1021
1022 if t == sym.SDYNIMPORT && ldr.SymDynimplib(s) == "/usr/lib/libSystem.B.dylib" {
1023
1024 if machoPlatform == PLATFORM_MACOS || machoPlatform == PLATFORM_MACCATALYST {
1025 switch n := ldr.SymExtname(s); n {
1026 case "fdopendir":
1027 switch buildcfg.GOARCH {
1028 case "amd64":
1029 ldr.SetSymExtname(s, n+"$INODE64")
1030 }
1031 case "readdir_r", "getfsstat":
1032 switch buildcfg.GOARCH {
1033 case "amd64":
1034 ldr.SetSymExtname(s, n+"$INODE64")
1035 }
1036 }
1037 }
1038 }
1039 }
1040
1041 nsortsym = len(sortsym)
1042 }
1043
1044 func machosymorder(ctxt *Link) {
1045 ldr := ctxt.loader
1046
1047
1048
1049
1050 for _, s := range ctxt.dynexp {
1051 if !ldr.AttrReachable(s) {
1052 panic("dynexp symbol is not reachable")
1053 }
1054 }
1055 collectmachosyms(ctxt)
1056 sort.Slice(sortsym[:nsortsym], func(i, j int) bool {
1057 s1 := sortsym[i]
1058 s2 := sortsym[j]
1059 k1 := symkind(ldr, s1)
1060 k2 := symkind(ldr, s2)
1061 if k1 != k2 {
1062 return k1 < k2
1063 }
1064 return ldr.SymExtname(s1) < ldr.SymExtname(s2)
1065 })
1066 for i, s := range sortsym {
1067 ldr.SetSymDynid(s, int32(i))
1068 }
1069 }
1070
1071
1072
1073 func AddMachoSym(ctxt *Link, s loader.Sym) {
1074 ldr := ctxt.loader
1075 ldr.SetSymDynid(s, int32(nsortsym))
1076 sortsym = append(sortsym, s)
1077 nsortsym++
1078 nkind[symkind(ldr, s)]++
1079 symtab := ldr.CreateSymForUpdate(".machosymtab", 0)
1080 symstr := ldr.CreateSymForUpdate(".machosymstr", 0)
1081 machosymtab1(ctxt, symtab, symstr, s)
1082 }
1083
1084
1085
1086
1087
1088 func machoShouldExport(ctxt *Link, ldr *loader.Loader, s loader.Sym) bool {
1089 if !ctxt.DynlinkingGo() || ldr.AttrLocal(s) || (ldr.IsContentHashed(s) && ldr.SymType(s).IsText()) {
1090 return false
1091 }
1092 if ctxt.BuildMode == BuildModePlugin && strings.HasPrefix(ldr.SymExtname(s), objabi.PathToPrefix(*flagPluginPath)) {
1093 return true
1094 }
1095 name := ldr.SymName(s)
1096 if strings.HasPrefix(name, "go:itab.") {
1097 return true
1098 }
1099 if strings.HasPrefix(name, "type:") && !strings.HasPrefix(name, "type:.") {
1100
1101
1102
1103 return true
1104 }
1105 if strings.HasPrefix(name, "go:link.pkghash") {
1106 return true
1107 }
1108 return ldr.SymType(s) >= sym.SFirstWritable
1109 }
1110
1111 func machosymtab(ctxt *Link) {
1112 ldr := ctxt.loader
1113 symtab := ldr.CreateSymForUpdate(".machosymtab", 0)
1114 symstr := ldr.CreateSymForUpdate(".machosymstr", 0)
1115
1116 for _, s := range sortsym[:nsortsym] {
1117 machosymtab1(ctxt, symtab, symstr, s)
1118 }
1119 }
1120
1121 func machosymtab1(ctxt *Link, symtab, symstr *loader.SymbolBuilder, s loader.Sym) {
1122 ldr := ctxt.loader
1123 symtab.AddUint32(ctxt.Arch, uint32(symstr.Size()))
1124
1125 export := machoShouldExport(ctxt, ldr, s)
1126
1127
1128
1129
1130
1131 symstr.AddUint8('_')
1132
1133
1134 name := strings.ReplaceAll(ldr.SymExtname(s), "·", ".")
1135
1136 name = mangleABIName(ctxt, ldr, s, name)
1137 symstr.Addstring(name)
1138
1139 if t := ldr.SymType(s); t == sym.SDYNIMPORT || t == sym.SHOSTOBJ || t == sym.SUNDEFEXT {
1140 symtab.AddUint8(0x01)
1141 symtab.AddUint8(0)
1142 symtab.AddUint16(ctxt.Arch, 0)
1143 symtab.AddUintXX(ctxt.Arch, 0, ctxt.Arch.PtrSize)
1144 } else {
1145 if export || ldr.AttrCgoExportDynamic(s) {
1146 symtab.AddUint8(0x0f)
1147 } else if ldr.AttrCgoExportStatic(s) {
1148
1149 symtab.AddUint8(0x1f)
1150 } else {
1151 symtab.AddUint8(0x0e)
1152 }
1153 o := s
1154 if outer := ldr.OuterSym(o); outer != 0 {
1155 o = outer
1156 }
1157 if ldr.SymSect(o) == nil {
1158 ldr.Errorf(s, "missing section for symbol")
1159 symtab.AddUint8(0)
1160 } else {
1161 symtab.AddUint8(uint8(ldr.SymSect(o).Extnum))
1162 }
1163 symtab.AddUint16(ctxt.Arch, 0)
1164 symtab.AddUintXX(ctxt.Arch, uint64(ldr.SymAddr(s)), ctxt.Arch.PtrSize)
1165 }
1166 }
1167
1168 func machodysymtab(ctxt *Link, base int64) {
1169 ml := newMachoLoad(ctxt.Arch, imacho.LC_DYSYMTAB, 18)
1170
1171 n := 0
1172 ml.data[0] = uint32(n)
1173 ml.data[1] = uint32(nkind[SymKindLocal])
1174 n += nkind[SymKindLocal]
1175
1176 ml.data[2] = uint32(n)
1177 ml.data[3] = uint32(nkind[SymKindExtdef])
1178 n += nkind[SymKindExtdef]
1179
1180 ml.data[4] = uint32(n)
1181 ml.data[5] = uint32(nkind[SymKindUndef])
1182
1183 ml.data[6] = 0
1184 ml.data[7] = 0
1185 ml.data[8] = 0
1186 ml.data[9] = 0
1187 ml.data[10] = 0
1188 ml.data[11] = 0
1189
1190 ldr := ctxt.loader
1191
1192
1193 s1 := ldr.SymSize(ldr.Lookup(".machosymtab", 0))
1194 s2 := ldr.SymSize(ctxt.ArchSyms.LinkEditPLT)
1195 s3 := ldr.SymSize(ctxt.ArchSyms.LinkEditGOT)
1196 ml.data[12] = uint32(base + s1)
1197 ml.data[13] = uint32((s2 + s3) / 4)
1198
1199 ml.data[14] = 0
1200 ml.data[15] = 0
1201 ml.data[16] = 0
1202 ml.data[17] = 0
1203 }
1204
1205 func doMachoLink(ctxt *Link) int64 {
1206 machoDyldInfo(ctxt)
1207
1208 ldr := ctxt.loader
1209
1210
1211 s1 := ldr.Lookup(".machorebase", 0)
1212 s2 := ldr.Lookup(".machobind", 0)
1213 s3 := ldr.Lookup(".machosymtab", 0)
1214 s4 := ctxt.ArchSyms.LinkEditPLT
1215 s5 := ctxt.ArchSyms.LinkEditGOT
1216 s6 := ldr.Lookup(".machosymstr", 0)
1217
1218 size := ldr.SymSize(s1) + ldr.SymSize(s2) + ldr.SymSize(s3) + ldr.SymSize(s4) + ldr.SymSize(s5) + ldr.SymSize(s6)
1219
1220 if size > 0 {
1221 linkoff = Rnd(int64(uint64(HEADR)+Segtext.Length), *FlagRound) + Rnd(int64(Segrelrodata.Filelen), *FlagRound) + Rnd(int64(Segdata.Filelen), *FlagRound)
1222 if !(*FlagSplitDWARF && ctxt.IsInternal()) {
1223 linkoff += Rnd(int64(Segdwarf.Filelen), *FlagRound)
1224 }
1225 ctxt.Out.SeekSet(linkoff)
1226
1227 ctxt.Out.Write(ldr.Data(s1))
1228 ctxt.Out.Write(ldr.Data(s2))
1229 ctxt.Out.Write(ldr.Data(s3))
1230 ctxt.Out.Write(ldr.Data(s4))
1231 ctxt.Out.Write(ldr.Data(s5))
1232 ctxt.Out.Write(ldr.Data(s6))
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251 if size%16 != 0 {
1252 n := 16 - size%16
1253 ctxt.Out.Write(zeros[:n])
1254 size += n
1255 }
1256
1257
1258 s7 := machoCodeSigSym(ctxt, linkoff+size)
1259 size += ldr.SymSize(s7)
1260 }
1261
1262 return Rnd(size, *FlagRound)
1263 }
1264
1265 func machorelocsect(ctxt *Link, out *OutBuf, sect *sym.Section, syms []loader.Sym) {
1266
1267 if sect.Vaddr >= sect.Seg.Vaddr+sect.Seg.Filelen {
1268 return
1269 }
1270 ldr := ctxt.loader
1271
1272 for i, s := range syms {
1273 if !ldr.AttrReachable(s) {
1274 continue
1275 }
1276 if uint64(ldr.SymValue(s)) >= sect.Vaddr {
1277 syms = syms[i:]
1278 break
1279 }
1280 }
1281
1282 eaddr := sect.Vaddr + sect.Length
1283 for _, s := range syms {
1284 if !ldr.AttrReachable(s) {
1285 continue
1286 }
1287 if ldr.SymValue(s) >= int64(eaddr) {
1288 break
1289 }
1290
1291
1292
1293 relocs := ldr.Relocs(s)
1294 for ri := 0; ri < relocs.Count(); ri++ {
1295 r := relocs.At(ri)
1296 rr, ok := extreloc(ctxt, ldr, s, r)
1297 if !ok {
1298 continue
1299 }
1300 if rr.Xsym == 0 {
1301 ldr.Errorf(s, "missing xsym in relocation")
1302 continue
1303 }
1304 if !ldr.AttrReachable(rr.Xsym) {
1305 ldr.Errorf(s, "unreachable reloc %d (%s) target %v", r.Type(), sym.RelocName(ctxt.Arch, r.Type()), ldr.SymName(rr.Xsym))
1306 }
1307 if !thearch.Machoreloc1(ctxt.Arch, out, ldr, s, rr, int64(uint64(ldr.SymValue(s)+int64(r.Off()))-sect.Vaddr)) {
1308 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()))
1309 }
1310 }
1311 }
1312
1313
1314 if uint64(out.Offset()) != sect.Reloff+sect.Rellen {
1315 panic("machorelocsect: size mismatch")
1316 }
1317 }
1318
1319 func machoEmitReloc(ctxt *Link) {
1320 for ctxt.Out.Offset()&7 != 0 {
1321 ctxt.Out.Write8(0)
1322 }
1323
1324 sizeExtRelocs(ctxt, thearch.MachorelocSize)
1325 relocSect, wg := relocSectFn(ctxt, machorelocsect)
1326
1327 relocSect(ctxt, Segtext.Sections[0], ctxt.Textp)
1328 for _, sect := range Segtext.Sections[1:] {
1329 if sect.Name == ".text" {
1330 relocSect(ctxt, sect, ctxt.Textp)
1331 } else {
1332 relocSect(ctxt, sect, ctxt.datap)
1333 }
1334 }
1335 for _, sect := range Segrelrodata.Sections {
1336 relocSect(ctxt, sect, ctxt.datap)
1337 }
1338 for _, sect := range Segdata.Sections {
1339 relocSect(ctxt, sect, ctxt.datap)
1340 }
1341 for i := 0; i < len(Segdwarf.Sections); i++ {
1342 sect := Segdwarf.Sections[i]
1343 si := dwarfp[i]
1344 if si.secSym() != sect.Sym ||
1345 ctxt.loader.SymSect(si.secSym()) != sect {
1346 panic("inconsistency between dwarfp and Segdwarf")
1347 }
1348 relocSect(ctxt, sect, si.syms)
1349 }
1350 wg.Wait()
1351 }
1352
1353
1354
1355 func hostobjMachoPlatform(h *Hostobj) (*MachoPlatformLoad, error) {
1356 f, err := os.Open(h.file)
1357 if err != nil {
1358 return nil, fmt.Errorf("%s: failed to open host object: %v\n", h.file, err)
1359 }
1360 defer f.Close()
1361 sr := io.NewSectionReader(f, h.off, h.length)
1362 m, err := macho.NewFile(sr)
1363 if err != nil {
1364
1365 return nil, nil
1366 }
1367 return peekMachoPlatform(m)
1368 }
1369
1370
1371
1372 func peekMachoPlatform(m *macho.File) (*MachoPlatformLoad, error) {
1373 for _, cmd := range m.Loads {
1374 raw := cmd.Raw()
1375 ml := MachoLoad{
1376 type_: m.ByteOrder.Uint32(raw),
1377 }
1378
1379 data := raw[8:]
1380 var p MachoPlatform
1381 switch ml.type_ {
1382 case imacho.LC_VERSION_MIN_IPHONEOS:
1383 p = PLATFORM_IOS
1384 case imacho.LC_VERSION_MIN_MACOSX:
1385 p = PLATFORM_MACOS
1386 case imacho.LC_VERSION_MIN_WATCHOS:
1387 p = PLATFORM_WATCHOS
1388 case imacho.LC_VERSION_MIN_TVOS:
1389 p = PLATFORM_TVOS
1390 case imacho.LC_BUILD_VERSION:
1391 p = MachoPlatform(m.ByteOrder.Uint32(data))
1392 default:
1393 continue
1394 }
1395 ml.data = make([]uint32, len(data)/4)
1396 r := bytes.NewReader(data)
1397 if err := binary.Read(r, m.ByteOrder, &ml.data); err != nil {
1398 return nil, err
1399 }
1400 return &MachoPlatformLoad{
1401 platform: p,
1402 cmd: ml,
1403 }, nil
1404 }
1405 return nil, nil
1406 }
1407
1408
1409
1410
1411
1412
1413
1414
1415 type machoRebaseRecord struct {
1416 sym loader.Sym
1417 off int64
1418 }
1419
1420 var machorebase []machoRebaseRecord
1421
1422 func MachoAddRebase(s loader.Sym, off int64) {
1423 machorebase = append(machorebase, machoRebaseRecord{s, off})
1424 }
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434 type machoBindRecord struct {
1435 sym loader.Sym
1436 off int64
1437 targ loader.Sym
1438 }
1439
1440 var machobind []machoBindRecord
1441
1442 func MachoAddBind(sym loader.Sym, off int64, targ loader.Sym) {
1443 machobind = append(machobind, machoBindRecord{sym, off, targ})
1444 }
1445
1446
1447
1448
1449 func machoDyldInfo(ctxt *Link) {
1450 ldr := ctxt.loader
1451 rebase := ldr.CreateSymForUpdate(".machorebase", 0)
1452 bind := ldr.CreateSymForUpdate(".machobind", 0)
1453
1454 if !(ctxt.IsPIE() && ctxt.IsInternal()) {
1455 return
1456 }
1457
1458 segId := func(seg *sym.Segment) uint8 {
1459 switch seg {
1460 case &Segtext:
1461 return 1
1462 case &Segrelrodata:
1463 return 2
1464 case &Segdata:
1465 if Segrelrodata.Length > 0 {
1466 return 3
1467 }
1468 return 2
1469 }
1470 panic("unknown segment")
1471 }
1472
1473 dylibId := func(s loader.Sym) int {
1474 slib := ldr.SymDynimplib(s)
1475 for i, lib := range dylib {
1476 if lib == slib {
1477 return i + 1
1478 }
1479 }
1480 return BIND_SPECIAL_DYLIB_FLAT_LOOKUP
1481 }
1482
1483
1484
1485
1486 rebase.AddUint8(REBASE_OPCODE_SET_TYPE_IMM | REBASE_TYPE_POINTER)
1487 for _, r := range machorebase {
1488 seg := ldr.SymSect(r.sym).Seg
1489 off := uint64(ldr.SymValue(r.sym)+r.off) - seg.Vaddr
1490 rebase.AddUint8(REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | segId(seg))
1491 rebase.AddUleb(off)
1492
1493 rebase.AddUint8(REBASE_OPCODE_DO_REBASE_IMM_TIMES | 1)
1494 }
1495 rebase.AddUint8(REBASE_OPCODE_DONE)
1496 sz := Rnd(rebase.Size(), 8)
1497 rebase.Grow(sz)
1498 rebase.SetSize(sz)
1499
1500
1501
1502
1503 bind.AddUint8(BIND_OPCODE_SET_TYPE_IMM | BIND_TYPE_POINTER)
1504 for _, r := range machobind {
1505 seg := ldr.SymSect(r.sym).Seg
1506 off := uint64(ldr.SymValue(r.sym)+r.off) - seg.Vaddr
1507 bind.AddUint8(BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | segId(seg))
1508 bind.AddUleb(off)
1509
1510 d := dylibId(r.targ)
1511 if d > 0 && d < 128 {
1512 bind.AddUint8(BIND_OPCODE_SET_DYLIB_ORDINAL_IMM | uint8(d)&0xf)
1513 } else if d >= 128 {
1514 bind.AddUint8(BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB)
1515 bind.AddUleb(uint64(d))
1516 } else {
1517 bind.AddUint8(BIND_OPCODE_SET_DYLIB_SPECIAL_IMM | uint8(d)&0xf)
1518 }
1519
1520 flags := uint8(0)
1521 if ldr.SymWeakBinding(r.targ) {
1522 flags |= BIND_SYMBOL_FLAGS_WEAK_IMPORT
1523 }
1524 bind.AddUint8(BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM | flags)
1525
1526 bind.AddUint8('_')
1527 bind.Addstring(ldr.SymExtname(r.targ))
1528
1529 bind.AddUint8(BIND_OPCODE_DO_BIND)
1530 }
1531 bind.AddUint8(BIND_OPCODE_DONE)
1532 sz = Rnd(bind.Size(), 16)
1533 bind.Grow(sz)
1534 bind.SetSize(sz)
1535
1536
1537
1538
1539
1540
1541
1542 }
1543
1544
1545
1546
1547 func machoCodeSigSym(ctxt *Link, codeSize int64) loader.Sym {
1548 ldr := ctxt.loader
1549 cs := ldr.CreateSymForUpdate(".machocodesig", 0)
1550 if !ctxt.NeedCodeSign() || ctxt.IsExternal() {
1551 return cs.Sym()
1552 }
1553 sz := codesign.Size(codeSize, "a.out")
1554 cs.Grow(sz)
1555 cs.SetSize(sz)
1556 return cs.Sym()
1557 }
1558
1559
1560
1561 func machoCodeSign(ctxt *Link, fname string) error {
1562 f, err := os.OpenFile(fname, os.O_RDWR, 0)
1563 if err != nil {
1564 return err
1565 }
1566 defer f.Close()
1567
1568 mf, err := macho.NewFile(f)
1569 if err != nil {
1570 return err
1571 }
1572 if mf.Magic != macho.Magic64 {
1573 Exitf("not 64-bit Mach-O file: %s", fname)
1574 }
1575
1576
1577 var sigOff, sigSz, csCmdOff, linkeditOff int64
1578 var linkeditSeg, textSeg *macho.Segment
1579 loadOff := int64(machoHeaderSize64)
1580 get32 := mf.ByteOrder.Uint32
1581 for _, l := range mf.Loads {
1582 data := l.Raw()
1583 cmd, sz := get32(data), get32(data[4:])
1584 if cmd == imacho.LC_CODE_SIGNATURE {
1585 sigOff = int64(get32(data[8:]))
1586 sigSz = int64(get32(data[12:]))
1587 csCmdOff = loadOff
1588 }
1589 if seg, ok := l.(*macho.Segment); ok {
1590 switch seg.Name {
1591 case "__LINKEDIT":
1592 linkeditSeg = seg
1593 linkeditOff = loadOff
1594 case "__TEXT":
1595 textSeg = seg
1596 }
1597 }
1598 loadOff += int64(sz)
1599 }
1600
1601 if sigOff == 0 {
1602
1603
1604 return nil
1605 }
1606
1607 fi, err := f.Stat()
1608 if err != nil {
1609 return err
1610 }
1611 if sigOff+sigSz != fi.Size() {
1612
1613
1614 return fmt.Errorf("unexpected content after code signature")
1615 }
1616
1617 sz := codesign.Size(sigOff, "a.out")
1618 if sz != sigSz {
1619
1620 var tmp [8]byte
1621 mf.ByteOrder.PutUint32(tmp[:4], uint32(sz))
1622 _, err = f.WriteAt(tmp[:4], csCmdOff+12)
1623 if err != nil {
1624 return err
1625 }
1626
1627
1628 segSz := sigOff + sz - int64(linkeditSeg.Offset)
1629 mf.ByteOrder.PutUint64(tmp[:8], uint64(segSz))
1630 _, err = f.WriteAt(tmp[:8], linkeditOff+int64(unsafe.Offsetof(macho.Segment64{}.Memsz)))
1631 if err != nil {
1632 return err
1633 }
1634 _, err = f.WriteAt(tmp[:8], linkeditOff+int64(unsafe.Offsetof(macho.Segment64{}.Filesz)))
1635 if err != nil {
1636 return err
1637 }
1638 }
1639
1640 cs := make([]byte, sz)
1641 codesign.Sign(cs, f, "a.out", sigOff, int64(textSeg.Offset), int64(textSeg.Filesz), ctxt.IsExe() || ctxt.IsPIE())
1642 _, err = f.WriteAt(cs, sigOff)
1643 if err != nil {
1644 return err
1645 }
1646 err = f.Truncate(sigOff + sz)
1647 return err
1648 }
1649
View as plain text