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