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 version = 11<<16 | 0<<8 | 0<<0
435 }
436 ml := newMachoLoad(ctxt.Arch, imacho.LC_BUILD_VERSION, 4)
437 ml.data[0] = uint32(machoPlatform)
438 ml.data[1] = version
439 ml.data[2] = version
440 ml.data[3] = 0
441 }
442 }
443
444
445 s := ctxt.loader.LookupOrCreateSym(".machosymstr", 0)
446 sb := ctxt.loader.MakeSymbolUpdater(s)
447
448 sb.SetType(sym.SMACHOSYMSTR)
449 sb.SetReachable(true)
450 sb.AddUint8(' ')
451 sb.AddUint8('\x00')
452
453 s = ctxt.loader.LookupOrCreateSym(".machosymtab", 0)
454 sb = ctxt.loader.MakeSymbolUpdater(s)
455 sb.SetType(sym.SMACHOSYMTAB)
456 sb.SetReachable(true)
457
458 if ctxt.IsInternal() {
459 s = ctxt.loader.LookupOrCreateSym(".plt", 0)
460 sb = ctxt.loader.MakeSymbolUpdater(s)
461 sb.SetType(sym.SMACHOPLT)
462 sb.SetReachable(true)
463
464 s = ctxt.loader.LookupOrCreateSym(".got", 0)
465 sb = ctxt.loader.MakeSymbolUpdater(s)
466 sb.SetType(sym.SMACHOGOT)
467 sb.SetReachable(true)
468 sb.SetAlign(4)
469
470 s = ctxt.loader.LookupOrCreateSym(".linkedit.plt", 0)
471 sb = ctxt.loader.MakeSymbolUpdater(s)
472 sb.SetType(sym.SMACHOINDIRECTPLT)
473 sb.SetReachable(true)
474
475 s = ctxt.loader.LookupOrCreateSym(".linkedit.got", 0)
476 sb = ctxt.loader.MakeSymbolUpdater(s)
477 sb.SetType(sym.SMACHOINDIRECTGOT)
478 sb.SetReachable(true)
479 }
480
481
482 if ctxt.IsExternal() {
483 s = ctxt.loader.LookupOrCreateSym(".llvmasm", 0)
484 sb = ctxt.loader.MakeSymbolUpdater(s)
485 sb.SetType(sym.SMACHO)
486 sb.SetReachable(true)
487 sb.AddUint8(0)
488 }
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505 if ctxt.BuildMode == BuildModePlugin {
506 for _, name := range []string{"_cgo_topofstack", "__cgo_topofstack", "_cgo_panic", "crosscall2"} {
507
508
509 ver := 0
510
511 if name == "_cgo_panic" {
512 ver = abiInternalVer
513 }
514 s := ctxt.loader.Lookup(name, ver)
515 if s != 0 {
516 ctxt.loader.SetAttrCgoExportDynamic(s, false)
517 }
518 }
519 }
520 }
521
522 func machoadddynlib(lib string, linkmode LinkMode) {
523 if seenlib[lib] || linkmode == LinkExternal {
524 return
525 }
526 seenlib[lib] = true
527
528
529
530
531
532 loadBudget -= (len(lib)+7)/8*8 + 24
533
534 if loadBudget < 0 {
535 HEADR += 4096
536 *FlagTextAddr += 4096
537 loadBudget += 4096
538 }
539
540 dylib = append(dylib, lib)
541 }
542
543 func machoshbits(ctxt *Link, mseg *MachoSeg, sect *sym.Section, segname string) {
544 buf := "__" + strings.Replace(sect.Name[1:], ".", "_", -1)
545
546 msect := newMachoSect(mseg, buf, segname)
547
548 if sect.Rellen > 0 {
549 msect.reloc = uint32(sect.Reloff)
550 msect.nreloc = uint32(sect.Rellen / 8)
551 }
552
553 for 1<<msect.align < sect.Align {
554 msect.align++
555 }
556 msect.addr = sect.Vaddr
557 msect.size = sect.Length
558
559 if sect.Vaddr < sect.Seg.Vaddr+sect.Seg.Filelen {
560
561 if sect.Length > sect.Seg.Vaddr+sect.Seg.Filelen-sect.Vaddr {
562 Errorf("macho cannot represent section %s crossing data and bss", sect.Name)
563 }
564 msect.off = uint32(sect.Seg.Fileoff + sect.Vaddr - sect.Seg.Vaddr)
565 } else {
566 msect.off = 0
567 msect.flag |= S_ZEROFILL
568 }
569
570 if sect.Rwx&1 != 0 {
571 msect.flag |= S_ATTR_SOME_INSTRUCTIONS
572 }
573
574 if sect.Name == ".text" {
575 msect.flag |= S_ATTR_PURE_INSTRUCTIONS
576 }
577
578 if sect.Name == ".plt" {
579 msect.name = "__symbol_stub1"
580 msect.flag = S_ATTR_PURE_INSTRUCTIONS | S_ATTR_SOME_INSTRUCTIONS | S_SYMBOL_STUBS
581 msect.res1 = 0
582 msect.res2 = 6
583 }
584
585 if sect.Name == ".got" {
586 msect.name = "__nl_symbol_ptr"
587 msect.flag = S_NON_LAZY_SYMBOL_POINTERS
588 msect.res1 = uint32(ctxt.loader.SymSize(ctxt.ArchSyms.LinkEditPLT) / 4)
589 }
590
591 if sect.Name == ".init_array" {
592 msect.name = "__mod_init_func"
593 msect.flag = S_MOD_INIT_FUNC_POINTERS
594 }
595
596
597
598
599
600
601
602 if sect.Name == ".llvmasm" {
603 msect.name = "__asm"
604 msect.segname = "__LLVM"
605 }
606
607 if segname == "__DWARF" {
608 msect.flag |= S_ATTR_DEBUG
609 }
610 }
611
612 func asmbMacho(ctxt *Link) {
613 machlink := doMachoLink(ctxt)
614 if ctxt.IsExternal() {
615 symo := int64(Segdwarf.Fileoff + uint64(Rnd(int64(Segdwarf.Filelen), *FlagRound)) + uint64(machlink))
616 ctxt.Out.SeekSet(symo)
617 machoEmitReloc(ctxt)
618 }
619 ctxt.Out.SeekSet(0)
620
621 ldr := ctxt.loader
622
623
624 va := *FlagTextAddr - int64(HEADR)
625
626 mh := getMachoHdr()
627 switch ctxt.Arch.Family {
628 default:
629 Exitf("unknown macho architecture: %v", ctxt.Arch.Family)
630
631 case sys.AMD64:
632 mh.cpu = MACHO_CPU_AMD64
633 mh.subcpu = MACHO_SUBCPU_X86
634
635 case sys.ARM64:
636 mh.cpu = MACHO_CPU_ARM64
637 mh.subcpu = MACHO_SUBCPU_ARM64_ALL
638 }
639
640 var ms *MachoSeg
641 if ctxt.LinkMode == LinkExternal {
642
643 ms = newMachoSeg("", 40)
644
645 ms.fileoffset = Segtext.Fileoff
646 ms.filesize = Segdwarf.Fileoff + Segdwarf.Filelen - Segtext.Fileoff
647 ms.vsize = Segdwarf.Vaddr + Segdwarf.Length - Segtext.Vaddr
648 }
649
650
651 if ctxt.LinkMode != LinkExternal {
652 ms = newMachoSeg("__PAGEZERO", 0)
653 ms.vsize = uint64(va)
654 }
655
656
657 v := Rnd(int64(uint64(HEADR)+Segtext.Length), *FlagRound)
658
659 var mstext *MachoSeg
660 if ctxt.LinkMode != LinkExternal {
661 ms = newMachoSeg("__TEXT", 20)
662 ms.vaddr = uint64(va)
663 ms.vsize = uint64(v)
664 ms.fileoffset = 0
665 ms.filesize = uint64(v)
666 ms.prot1 = 7
667 ms.prot2 = 5
668 mstext = ms
669 }
670
671 for _, sect := range Segtext.Sections {
672 machoshbits(ctxt, ms, sect, "__TEXT")
673 }
674
675
676 if ctxt.LinkMode != LinkExternal && Segrelrodata.Length > 0 {
677 ms = newMachoSeg("__DATA_CONST", 20)
678 ms.vaddr = Segrelrodata.Vaddr
679 ms.vsize = Segrelrodata.Length
680 ms.fileoffset = Segrelrodata.Fileoff
681 ms.filesize = Segrelrodata.Filelen
682 ms.prot1 = 3
683 ms.prot2 = 3
684 ms.flag = 0x10
685 }
686
687 for _, sect := range Segrelrodata.Sections {
688 machoshbits(ctxt, ms, sect, "__DATA_CONST")
689 }
690
691
692 if ctxt.LinkMode != LinkExternal {
693 ms = newMachoSeg("__DATA", 20)
694 ms.vaddr = Segdata.Vaddr
695 ms.vsize = Segdata.Length
696 ms.fileoffset = Segdata.Fileoff
697 ms.filesize = Segdata.Filelen
698 ms.prot1 = 3
699 ms.prot2 = 3
700 }
701
702 for _, sect := range Segdata.Sections {
703 machoshbits(ctxt, ms, sect, "__DATA")
704 }
705
706
707 if !*FlagW {
708 if ctxt.LinkMode != LinkExternal {
709 ms = newMachoSeg("__DWARF", 20)
710 ms.vaddr = Segdwarf.Vaddr
711 ms.vsize = 0
712 ms.fileoffset = Segdwarf.Fileoff
713 ms.filesize = Segdwarf.Filelen
714 }
715 for _, sect := range Segdwarf.Sections {
716 machoshbits(ctxt, ms, sect, "__DWARF")
717 }
718 }
719
720 if ctxt.LinkMode != LinkExternal {
721 switch ctxt.Arch.Family {
722 default:
723 Exitf("unknown macho architecture: %v", ctxt.Arch.Family)
724
725 case sys.AMD64:
726 ml := newMachoLoad(ctxt.Arch, imacho.LC_UNIXTHREAD, 42+2)
727 ml.data[0] = 4
728 ml.data[1] = 42
729 ml.data[2+32] = uint32(Entryvalue(ctxt))
730 ml.data[2+32+1] = uint32(Entryvalue(ctxt) >> 32)
731
732 case sys.ARM64:
733 ml := newMachoLoad(ctxt.Arch, imacho.LC_MAIN, 4)
734 ml.data[0] = uint32(uint64(Entryvalue(ctxt)) - (Segtext.Vaddr - uint64(HEADR)))
735 ml.data[1] = uint32((uint64(Entryvalue(ctxt)) - (Segtext.Vaddr - uint64(HEADR))) >> 32)
736 }
737 }
738
739 var codesigOff int64
740 if !*FlagD {
741
742 s1 := ldr.SymSize(ldr.Lookup(".machorebase", 0))
743 s2 := ldr.SymSize(ldr.Lookup(".machobind", 0))
744 s3 := ldr.SymSize(ldr.Lookup(".machosymtab", 0))
745 s4 := ldr.SymSize(ctxt.ArchSyms.LinkEditPLT)
746 s5 := ldr.SymSize(ctxt.ArchSyms.LinkEditGOT)
747 s6 := ldr.SymSize(ldr.Lookup(".machosymstr", 0))
748 s7 := ldr.SymSize(ldr.Lookup(".machocodesig", 0))
749
750 if ctxt.LinkMode != LinkExternal {
751 ms := newMachoSeg("__LINKEDIT", 0)
752 ms.vaddr = uint64(Rnd(int64(Segdata.Vaddr+Segdata.Length), *FlagRound))
753 ms.vsize = uint64(s1 + s2 + s3 + s4 + s5 + s6 + s7)
754 ms.fileoffset = uint64(linkoff)
755 ms.filesize = ms.vsize
756 ms.prot1 = 1
757 ms.prot2 = 1
758
759 codesigOff = linkoff + s1 + s2 + s3 + s4 + s5 + s6
760 }
761
762 if ctxt.LinkMode != LinkExternal && ctxt.IsPIE() {
763 ml := newMachoLoad(ctxt.Arch, imacho.LC_DYLD_INFO_ONLY, 10)
764 ml.data[0] = uint32(linkoff)
765 ml.data[1] = uint32(s1)
766 ml.data[2] = uint32(linkoff + s1)
767 ml.data[3] = uint32(s2)
768 ml.data[4] = 0
769 ml.data[5] = 0
770 ml.data[6] = 0
771 ml.data[7] = 0
772 ml.data[8] = 0
773 ml.data[9] = 0
774 }
775
776 ml := newMachoLoad(ctxt.Arch, imacho.LC_SYMTAB, 4)
777 ml.data[0] = uint32(linkoff + s1 + s2)
778 ml.data[1] = uint32(nsortsym)
779 ml.data[2] = uint32(linkoff + s1 + s2 + s3 + s4 + s5)
780 ml.data[3] = uint32(s6)
781
782 if ctxt.LinkMode != LinkExternal {
783 machodysymtab(ctxt, linkoff+s1+s2)
784
785 ml := newMachoLoad(ctxt.Arch, imacho.LC_LOAD_DYLINKER, 6)
786 ml.data[0] = 12
787 stringtouint32(ml.data[1:], "/usr/lib/dyld")
788
789 for _, lib := range dylib {
790 ml = newMachoLoad(ctxt.Arch, imacho.LC_LOAD_DYLIB, 4+(uint32(len(lib))+1+7)/8*2)
791 ml.data[0] = 24
792 ml.data[1] = 0
793 ml.data[2] = 0
794 ml.data[3] = 0
795 stringtouint32(ml.data[4:], lib)
796 }
797 }
798
799 if ctxt.IsInternal() && len(buildinfo) > 0 {
800 ml := newMachoLoad(ctxt.Arch, imacho.LC_UUID, 4)
801
802 if len(buildinfo) < 16 {
803 buildinfo = append(buildinfo, make([]byte, 16)...)
804 }
805
806
807 ml.data[0] = ctxt.Arch.ByteOrder.Uint32(buildinfo)
808 ml.data[1] = ctxt.Arch.ByteOrder.Uint32(buildinfo[4:])
809 ml.data[2] = ctxt.Arch.ByteOrder.Uint32(buildinfo[8:])
810 ml.data[3] = ctxt.Arch.ByteOrder.Uint32(buildinfo[12:])
811 }
812
813 if ctxt.IsInternal() && ctxt.NeedCodeSign() {
814 ml := newMachoLoad(ctxt.Arch, imacho.LC_CODE_SIGNATURE, 2)
815 ml.data[0] = uint32(codesigOff)
816 ml.data[1] = uint32(s7)
817 }
818 }
819
820 a := machowrite(ctxt, ctxt.Arch, ctxt.Out, ctxt.LinkMode)
821 if int32(a) > HEADR {
822 Exitf("HEADR too small: %d > %d", a, HEADR)
823 }
824
825
826
827 if ctxt.IsInternal() && ctxt.NeedCodeSign() {
828 cs := ldr.Lookup(".machocodesig", 0)
829 data := ctxt.Out.Data()
830 if int64(len(data)) != codesigOff {
831 panic("wrong size")
832 }
833 codesign.Sign(ldr.Data(cs), bytes.NewReader(data), "a.out", codesigOff, int64(mstext.fileoffset), int64(mstext.filesize), ctxt.IsExe() || ctxt.IsPIE())
834 ctxt.Out.SeekSet(codesigOff)
835 ctxt.Out.Write(ldr.Data(cs))
836 }
837 }
838
839 func symkind(ldr *loader.Loader, s loader.Sym) int {
840 if t := ldr.SymType(s); t == sym.SDYNIMPORT || t == sym.SHOSTOBJ || t == sym.SUNDEFEXT {
841 return SymKindUndef
842 }
843 if ldr.AttrCgoExport(s) {
844 return SymKindExtdef
845 }
846 return SymKindLocal
847 }
848
849 func collectmachosyms(ctxt *Link) {
850 ldr := ctxt.loader
851
852 addsym := func(s loader.Sym) {
853 sortsym = append(sortsym, s)
854 nkind[symkind(ldr, s)]++
855 }
856
857
858
859
860
861
862
863
864
865
866 if !*FlagS {
867 if !ctxt.DynlinkingGo() {
868 s := ldr.Lookup("runtime.text", 0)
869 if ldr.SymType(s).IsText() {
870 addsym(s)
871 }
872 }
873 for n := range Segtext.Sections[1:] {
874 s := ldr.Lookup(fmt.Sprintf("runtime.text.%d", n+1), 0)
875 if s != 0 {
876 addsym(s)
877 } else {
878 break
879 }
880 }
881 if !ctxt.DynlinkingGo() {
882 s := ldr.Lookup("runtime.etext", 0)
883 if ldr.SymType(s).IsText() {
884 addsym(s)
885 }
886 }
887 }
888
889
890 for _, s := range ctxt.Textp {
891 if *FlagS && !ldr.AttrCgoExportDynamic(s) {
892 continue
893 }
894 addsym(s)
895 }
896
897 shouldBeInSymbolTable := func(s loader.Sym) bool {
898 if ldr.AttrNotInSymbolTable(s) {
899 return false
900 }
901 name := ldr.SymName(s)
902 if name == "" || name[0] == '.' {
903 return false
904 }
905 return true
906 }
907
908
909 for s := loader.Sym(1); s < loader.Sym(ldr.NSym()); s++ {
910 if !ldr.AttrReachable(s) {
911 continue
912 }
913 t := ldr.SymType(s)
914 if t >= sym.SELFRXSECT && t < sym.SXREF {
915 if t == sym.STLSBSS {
916
917 continue
918 }
919 if !shouldBeInSymbolTable(s) {
920 continue
921 }
922 if *FlagS && !ldr.AttrCgoExportDynamic(s) {
923 continue
924 }
925 addsym(s)
926 continue
927 }
928
929 switch t {
930 case sym.SDYNIMPORT, sym.SHOSTOBJ, sym.SUNDEFEXT:
931
932 addsym(s)
933 }
934
935
936 if t == sym.SDYNIMPORT && ldr.SymDynimplib(s) == "/usr/lib/libSystem.B.dylib" {
937
938 if machoPlatform == PLATFORM_MACOS || machoPlatform == PLATFORM_MACCATALYST {
939 switch n := ldr.SymExtname(s); n {
940 case "fdopendir":
941 switch buildcfg.GOARCH {
942 case "amd64":
943 ldr.SetSymExtname(s, n+"$INODE64")
944 }
945 case "readdir_r", "getfsstat":
946 switch buildcfg.GOARCH {
947 case "amd64":
948 ldr.SetSymExtname(s, n+"$INODE64")
949 }
950 }
951 }
952 }
953 }
954
955 nsortsym = len(sortsym)
956 }
957
958 func machosymorder(ctxt *Link) {
959 ldr := ctxt.loader
960
961
962
963
964 for _, s := range ctxt.dynexp {
965 if !ldr.AttrReachable(s) {
966 panic("dynexp symbol is not reachable")
967 }
968 }
969 collectmachosyms(ctxt)
970 sort.Slice(sortsym[:nsortsym], func(i, j int) bool {
971 s1 := sortsym[i]
972 s2 := sortsym[j]
973 k1 := symkind(ldr, s1)
974 k2 := symkind(ldr, s2)
975 if k1 != k2 {
976 return k1 < k2
977 }
978 return ldr.SymExtname(s1) < ldr.SymExtname(s2)
979 })
980 for i, s := range sortsym {
981 ldr.SetSymDynid(s, int32(i))
982 }
983 }
984
985
986
987 func AddMachoSym(ldr *loader.Loader, s loader.Sym) {
988 ldr.SetSymDynid(s, int32(nsortsym))
989 sortsym = append(sortsym, s)
990 nsortsym++
991 nkind[symkind(ldr, s)]++
992 }
993
994
995
996
997
998 func machoShouldExport(ctxt *Link, ldr *loader.Loader, s loader.Sym) bool {
999 if !ctxt.DynlinkingGo() || ldr.AttrLocal(s) {
1000 return false
1001 }
1002 if ctxt.BuildMode == BuildModePlugin && strings.HasPrefix(ldr.SymExtname(s), objabi.PathToPrefix(*flagPluginPath)) {
1003 return true
1004 }
1005 name := ldr.SymName(s)
1006 if strings.HasPrefix(name, "go:itab.") {
1007 return true
1008 }
1009 if strings.HasPrefix(name, "type:") && !strings.HasPrefix(name, "type:.") {
1010
1011
1012
1013 return true
1014 }
1015 if strings.HasPrefix(name, "go:link.pkghash") {
1016 return true
1017 }
1018 return ldr.SymType(s) >= sym.SFirstWritable
1019 }
1020
1021 func machosymtab(ctxt *Link) {
1022 ldr := ctxt.loader
1023 symtab := ldr.CreateSymForUpdate(".machosymtab", 0)
1024 symstr := ldr.CreateSymForUpdate(".machosymstr", 0)
1025
1026 for _, s := range sortsym[:nsortsym] {
1027 symtab.AddUint32(ctxt.Arch, uint32(symstr.Size()))
1028
1029 export := machoShouldExport(ctxt, ldr, s)
1030
1031
1032
1033
1034
1035 symstr.AddUint8('_')
1036
1037
1038 name := strings.Replace(ldr.SymExtname(s), "·", ".", -1)
1039
1040 name = mangleABIName(ctxt, ldr, s, name)
1041 symstr.Addstring(name)
1042
1043 if t := ldr.SymType(s); t == sym.SDYNIMPORT || t == sym.SHOSTOBJ || t == sym.SUNDEFEXT {
1044 symtab.AddUint8(0x01)
1045 symtab.AddUint8(0)
1046 symtab.AddUint16(ctxt.Arch, 0)
1047 symtab.AddUintXX(ctxt.Arch, 0, ctxt.Arch.PtrSize)
1048 } else {
1049 if export || ldr.AttrCgoExportDynamic(s) {
1050 symtab.AddUint8(0x0f)
1051 } else if ldr.AttrCgoExportStatic(s) {
1052
1053 symtab.AddUint8(0x1f)
1054 } else {
1055 symtab.AddUint8(0x0e)
1056 }
1057 o := s
1058 if outer := ldr.OuterSym(o); outer != 0 {
1059 o = outer
1060 }
1061 if ldr.SymSect(o) == nil {
1062 ldr.Errorf(s, "missing section for symbol")
1063 symtab.AddUint8(0)
1064 } else {
1065 symtab.AddUint8(uint8(ldr.SymSect(o).Extnum))
1066 }
1067 symtab.AddUint16(ctxt.Arch, 0)
1068 symtab.AddUintXX(ctxt.Arch, uint64(ldr.SymAddr(s)), ctxt.Arch.PtrSize)
1069 }
1070 }
1071 }
1072
1073 func machodysymtab(ctxt *Link, base int64) {
1074 ml := newMachoLoad(ctxt.Arch, imacho.LC_DYSYMTAB, 18)
1075
1076 n := 0
1077 ml.data[0] = uint32(n)
1078 ml.data[1] = uint32(nkind[SymKindLocal])
1079 n += nkind[SymKindLocal]
1080
1081 ml.data[2] = uint32(n)
1082 ml.data[3] = uint32(nkind[SymKindExtdef])
1083 n += nkind[SymKindExtdef]
1084
1085 ml.data[4] = uint32(n)
1086 ml.data[5] = uint32(nkind[SymKindUndef])
1087
1088 ml.data[6] = 0
1089 ml.data[7] = 0
1090 ml.data[8] = 0
1091 ml.data[9] = 0
1092 ml.data[10] = 0
1093 ml.data[11] = 0
1094
1095 ldr := ctxt.loader
1096
1097
1098 s1 := ldr.SymSize(ldr.Lookup(".machosymtab", 0))
1099 s2 := ldr.SymSize(ctxt.ArchSyms.LinkEditPLT)
1100 s3 := ldr.SymSize(ctxt.ArchSyms.LinkEditGOT)
1101 ml.data[12] = uint32(base + s1)
1102 ml.data[13] = uint32((s2 + s3) / 4)
1103
1104 ml.data[14] = 0
1105 ml.data[15] = 0
1106 ml.data[16] = 0
1107 ml.data[17] = 0
1108 }
1109
1110 func doMachoLink(ctxt *Link) int64 {
1111 machosymtab(ctxt)
1112 machoDyldInfo(ctxt)
1113
1114 ldr := ctxt.loader
1115
1116
1117 s1 := ldr.Lookup(".machorebase", 0)
1118 s2 := ldr.Lookup(".machobind", 0)
1119 s3 := ldr.Lookup(".machosymtab", 0)
1120 s4 := ctxt.ArchSyms.LinkEditPLT
1121 s5 := ctxt.ArchSyms.LinkEditGOT
1122 s6 := ldr.Lookup(".machosymstr", 0)
1123
1124 size := ldr.SymSize(s1) + ldr.SymSize(s2) + ldr.SymSize(s3) + ldr.SymSize(s4) + ldr.SymSize(s5) + ldr.SymSize(s6)
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143 if size%16 != 0 {
1144 n := 16 - size%16
1145 s6b := ldr.MakeSymbolUpdater(s6)
1146 s6b.Grow(s6b.Size() + n)
1147 s6b.SetSize(s6b.Size() + n)
1148 size += n
1149 }
1150
1151 if size > 0 {
1152 linkoff = Rnd(int64(uint64(HEADR)+Segtext.Length), *FlagRound) + Rnd(int64(Segrelrodata.Filelen), *FlagRound) + Rnd(int64(Segdata.Filelen), *FlagRound) + Rnd(int64(Segdwarf.Filelen), *FlagRound)
1153 ctxt.Out.SeekSet(linkoff)
1154
1155 ctxt.Out.Write(ldr.Data(s1))
1156 ctxt.Out.Write(ldr.Data(s2))
1157 ctxt.Out.Write(ldr.Data(s3))
1158 ctxt.Out.Write(ldr.Data(s4))
1159 ctxt.Out.Write(ldr.Data(s5))
1160 ctxt.Out.Write(ldr.Data(s6))
1161
1162
1163 s7 := machoCodeSigSym(ctxt, linkoff+size)
1164 size += ldr.SymSize(s7)
1165 }
1166
1167 return Rnd(size, *FlagRound)
1168 }
1169
1170 func machorelocsect(ctxt *Link, out *OutBuf, sect *sym.Section, syms []loader.Sym) {
1171
1172 if sect.Vaddr >= sect.Seg.Vaddr+sect.Seg.Filelen {
1173 return
1174 }
1175 ldr := ctxt.loader
1176
1177 for i, s := range syms {
1178 if !ldr.AttrReachable(s) {
1179 continue
1180 }
1181 if uint64(ldr.SymValue(s)) >= sect.Vaddr {
1182 syms = syms[i:]
1183 break
1184 }
1185 }
1186
1187 eaddr := sect.Vaddr + sect.Length
1188 for _, s := range syms {
1189 if !ldr.AttrReachable(s) {
1190 continue
1191 }
1192 if ldr.SymValue(s) >= int64(eaddr) {
1193 break
1194 }
1195
1196
1197
1198 relocs := ldr.Relocs(s)
1199 for ri := 0; ri < relocs.Count(); ri++ {
1200 r := relocs.At(ri)
1201 rr, ok := extreloc(ctxt, ldr, s, r)
1202 if !ok {
1203 continue
1204 }
1205 if rr.Xsym == 0 {
1206 ldr.Errorf(s, "missing xsym in relocation")
1207 continue
1208 }
1209 if !ldr.AttrReachable(rr.Xsym) {
1210 ldr.Errorf(s, "unreachable reloc %d (%s) target %v", r.Type(), sym.RelocName(ctxt.Arch, r.Type()), ldr.SymName(rr.Xsym))
1211 }
1212 if !thearch.Machoreloc1(ctxt.Arch, out, ldr, s, rr, int64(uint64(ldr.SymValue(s)+int64(r.Off()))-sect.Vaddr)) {
1213 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()))
1214 }
1215 }
1216 }
1217
1218
1219 if uint64(out.Offset()) != sect.Reloff+sect.Rellen {
1220 panic("machorelocsect: size mismatch")
1221 }
1222 }
1223
1224 func machoEmitReloc(ctxt *Link) {
1225 for ctxt.Out.Offset()&7 != 0 {
1226 ctxt.Out.Write8(0)
1227 }
1228
1229 sizeExtRelocs(ctxt, thearch.MachorelocSize)
1230 relocSect, wg := relocSectFn(ctxt, machorelocsect)
1231
1232 relocSect(ctxt, Segtext.Sections[0], ctxt.Textp)
1233 for _, sect := range Segtext.Sections[1:] {
1234 if sect.Name == ".text" {
1235 relocSect(ctxt, sect, ctxt.Textp)
1236 } else {
1237 relocSect(ctxt, sect, ctxt.datap)
1238 }
1239 }
1240 for _, sect := range Segrelrodata.Sections {
1241 relocSect(ctxt, sect, ctxt.datap)
1242 }
1243 for _, sect := range Segdata.Sections {
1244 relocSect(ctxt, sect, ctxt.datap)
1245 }
1246 for i := 0; i < len(Segdwarf.Sections); i++ {
1247 sect := Segdwarf.Sections[i]
1248 si := dwarfp[i]
1249 if si.secSym() != loader.Sym(sect.Sym) ||
1250 ctxt.loader.SymSect(si.secSym()) != sect {
1251 panic("inconsistency between dwarfp and Segdwarf")
1252 }
1253 relocSect(ctxt, sect, si.syms)
1254 }
1255 wg.Wait()
1256 }
1257
1258
1259
1260 func hostobjMachoPlatform(h *Hostobj) (*MachoPlatformLoad, error) {
1261 f, err := os.Open(h.file)
1262 if err != nil {
1263 return nil, fmt.Errorf("%s: failed to open host object: %v\n", h.file, err)
1264 }
1265 defer f.Close()
1266 sr := io.NewSectionReader(f, h.off, h.length)
1267 m, err := macho.NewFile(sr)
1268 if err != nil {
1269
1270 return nil, nil
1271 }
1272 return peekMachoPlatform(m)
1273 }
1274
1275
1276
1277 func peekMachoPlatform(m *macho.File) (*MachoPlatformLoad, error) {
1278 for _, cmd := range m.Loads {
1279 raw := cmd.Raw()
1280 ml := MachoLoad{
1281 type_: m.ByteOrder.Uint32(raw),
1282 }
1283
1284 data := raw[8:]
1285 var p MachoPlatform
1286 switch ml.type_ {
1287 case imacho.LC_VERSION_MIN_IPHONEOS:
1288 p = PLATFORM_IOS
1289 case imacho.LC_VERSION_MIN_MACOSX:
1290 p = PLATFORM_MACOS
1291 case imacho.LC_VERSION_MIN_WATCHOS:
1292 p = PLATFORM_WATCHOS
1293 case imacho.LC_VERSION_MIN_TVOS:
1294 p = PLATFORM_TVOS
1295 case imacho.LC_BUILD_VERSION:
1296 p = MachoPlatform(m.ByteOrder.Uint32(data))
1297 default:
1298 continue
1299 }
1300 ml.data = make([]uint32, len(data)/4)
1301 r := bytes.NewReader(data)
1302 if err := binary.Read(r, m.ByteOrder, &ml.data); err != nil {
1303 return nil, err
1304 }
1305 return &MachoPlatformLoad{
1306 platform: p,
1307 cmd: ml,
1308 }, nil
1309 }
1310 return nil, nil
1311 }
1312
1313
1314
1315
1316
1317
1318
1319
1320 type machoRebaseRecord struct {
1321 sym loader.Sym
1322 off int64
1323 }
1324
1325 var machorebase []machoRebaseRecord
1326
1327 func MachoAddRebase(s loader.Sym, off int64) {
1328 machorebase = append(machorebase, machoRebaseRecord{s, off})
1329 }
1330
1331
1332
1333
1334
1335
1336
1337 type machoBindRecord struct {
1338 off int64
1339 targ loader.Sym
1340 }
1341
1342 var machobind []machoBindRecord
1343
1344 func MachoAddBind(off int64, targ loader.Sym) {
1345 machobind = append(machobind, machoBindRecord{off, targ})
1346 }
1347
1348
1349
1350
1351 func machoDyldInfo(ctxt *Link) {
1352 ldr := ctxt.loader
1353 rebase := ldr.CreateSymForUpdate(".machorebase", 0)
1354 bind := ldr.CreateSymForUpdate(".machobind", 0)
1355
1356 if !(ctxt.IsPIE() && ctxt.IsInternal()) {
1357 return
1358 }
1359
1360 segId := func(seg *sym.Segment) uint8 {
1361 switch seg {
1362 case &Segtext:
1363 return 1
1364 case &Segrelrodata:
1365 return 2
1366 case &Segdata:
1367 if Segrelrodata.Length > 0 {
1368 return 3
1369 }
1370 return 2
1371 }
1372 panic("unknown segment")
1373 }
1374
1375 dylibId := func(s loader.Sym) int {
1376 slib := ldr.SymDynimplib(s)
1377 for i, lib := range dylib {
1378 if lib == slib {
1379 return i + 1
1380 }
1381 }
1382 return BIND_SPECIAL_DYLIB_FLAT_LOOKUP
1383 }
1384
1385
1386
1387
1388 rebase.AddUint8(REBASE_OPCODE_SET_TYPE_IMM | REBASE_TYPE_POINTER)
1389 for _, r := range machorebase {
1390 seg := ldr.SymSect(r.sym).Seg
1391 off := uint64(ldr.SymValue(r.sym)+r.off) - seg.Vaddr
1392 rebase.AddUint8(REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | segId(seg))
1393 rebase.AddUleb(off)
1394
1395 rebase.AddUint8(REBASE_OPCODE_DO_REBASE_IMM_TIMES | 1)
1396 }
1397 rebase.AddUint8(REBASE_OPCODE_DONE)
1398 sz := Rnd(rebase.Size(), 8)
1399 rebase.Grow(sz)
1400 rebase.SetSize(sz)
1401
1402
1403
1404
1405 got := ctxt.GOT
1406 seg := ldr.SymSect(got).Seg
1407 gotAddr := ldr.SymValue(got)
1408 bind.AddUint8(BIND_OPCODE_SET_TYPE_IMM | BIND_TYPE_POINTER)
1409 for _, r := range machobind {
1410 off := uint64(gotAddr+r.off) - seg.Vaddr
1411 bind.AddUint8(BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | segId(seg))
1412 bind.AddUleb(off)
1413
1414 d := dylibId(r.targ)
1415 if d > 0 && d < 128 {
1416 bind.AddUint8(BIND_OPCODE_SET_DYLIB_ORDINAL_IMM | uint8(d)&0xf)
1417 } else if d >= 128 {
1418 bind.AddUint8(BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB)
1419 bind.AddUleb(uint64(d))
1420 } else {
1421 bind.AddUint8(BIND_OPCODE_SET_DYLIB_SPECIAL_IMM | uint8(d)&0xf)
1422 }
1423
1424 bind.AddUint8(BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM)
1425
1426 bind.AddUint8('_')
1427 bind.Addstring(ldr.SymExtname(r.targ))
1428
1429 bind.AddUint8(BIND_OPCODE_DO_BIND)
1430 }
1431 bind.AddUint8(BIND_OPCODE_DONE)
1432 sz = Rnd(bind.Size(), 16)
1433 bind.Grow(sz)
1434 bind.SetSize(sz)
1435
1436
1437
1438
1439
1440
1441
1442 }
1443
1444
1445
1446
1447 func machoCodeSigSym(ctxt *Link, codeSize int64) loader.Sym {
1448 ldr := ctxt.loader
1449 cs := ldr.CreateSymForUpdate(".machocodesig", 0)
1450 if !ctxt.NeedCodeSign() || ctxt.IsExternal() {
1451 return cs.Sym()
1452 }
1453 sz := codesign.Size(codeSize, "a.out")
1454 cs.Grow(sz)
1455 cs.SetSize(sz)
1456 return cs.Sym()
1457 }
1458
1459
1460
1461 func machoCodeSign(ctxt *Link, fname string) error {
1462 f, err := os.OpenFile(fname, os.O_RDWR, 0)
1463 if err != nil {
1464 return err
1465 }
1466 defer f.Close()
1467
1468 mf, err := macho.NewFile(f)
1469 if err != nil {
1470 return err
1471 }
1472 if mf.Magic != macho.Magic64 {
1473 Exitf("not 64-bit Mach-O file: %s", fname)
1474 }
1475
1476
1477 var sigOff, sigSz, csCmdOff, linkeditOff int64
1478 var linkeditSeg, textSeg *macho.Segment
1479 loadOff := int64(machoHeaderSize64)
1480 get32 := mf.ByteOrder.Uint32
1481 for _, l := range mf.Loads {
1482 data := l.Raw()
1483 cmd, sz := get32(data), get32(data[4:])
1484 if cmd == imacho.LC_CODE_SIGNATURE {
1485 sigOff = int64(get32(data[8:]))
1486 sigSz = int64(get32(data[12:]))
1487 csCmdOff = loadOff
1488 }
1489 if seg, ok := l.(*macho.Segment); ok {
1490 switch seg.Name {
1491 case "__LINKEDIT":
1492 linkeditSeg = seg
1493 linkeditOff = loadOff
1494 case "__TEXT":
1495 textSeg = seg
1496 }
1497 }
1498 loadOff += int64(sz)
1499 }
1500
1501 if sigOff == 0 {
1502
1503
1504 return nil
1505 }
1506
1507 fi, err := f.Stat()
1508 if err != nil {
1509 return err
1510 }
1511 if sigOff+sigSz != fi.Size() {
1512
1513
1514 return fmt.Errorf("unexpected content after code signature")
1515 }
1516
1517 sz := codesign.Size(sigOff, "a.out")
1518 if sz != sigSz {
1519
1520 var tmp [8]byte
1521 mf.ByteOrder.PutUint32(tmp[:4], uint32(sz))
1522 _, err = f.WriteAt(tmp[:4], csCmdOff+12)
1523 if err != nil {
1524 return err
1525 }
1526
1527
1528 segSz := sigOff + sz - int64(linkeditSeg.Offset)
1529 mf.ByteOrder.PutUint64(tmp[:8], uint64(segSz))
1530 _, err = f.WriteAt(tmp[:8], int64(linkeditOff)+int64(unsafe.Offsetof(macho.Segment64{}.Memsz)))
1531 if err != nil {
1532 return err
1533 }
1534 _, err = f.WriteAt(tmp[:8], int64(linkeditOff)+int64(unsafe.Offsetof(macho.Segment64{}.Filesz)))
1535 if err != nil {
1536 return err
1537 }
1538 }
1539
1540 cs := make([]byte, sz)
1541 codesign.Sign(cs, f, "a.out", sigOff, int64(textSeg.Offset), int64(textSeg.Filesz), ctxt.IsExe() || ctxt.IsPIE())
1542 _, err = f.WriteAt(cs, sigOff)
1543 if err != nil {
1544 return err
1545 }
1546 err = f.Truncate(sigOff + sz)
1547 return err
1548 }
1549
View as plain text