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