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