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