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