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