Source file src/pkg/cmd/link/internal/ld/macho.go
1
2
3
4
5 package ld
6
7 import (
8 "bytes"
9 "cmd/internal/objabi"
10 "cmd/internal/sys"
11 "cmd/link/internal/sym"
12 "debug/macho"
13 "encoding/binary"
14 "fmt"
15 "io"
16 "os"
17 "sort"
18 "strings"
19 )
20
21 type MachoHdr struct {
22 cpu uint32
23 subcpu uint32
24 }
25
26 type MachoSect struct {
27 name string
28 segname string
29 addr uint64
30 size uint64
31 off uint32
32 align uint32
33 reloc uint32
34 nreloc uint32
35 flag uint32
36 res1 uint32
37 res2 uint32
38 }
39
40 type MachoSeg struct {
41 name string
42 vsize uint64
43 vaddr uint64
44 fileoffset uint64
45 filesize uint64
46 prot1 uint32
47 prot2 uint32
48 nsect uint32
49 msect uint32
50 sect []MachoSect
51 flag uint32
52 }
53
54
55
56 type MachoPlatformLoad struct {
57 platform MachoPlatform
58 cmd MachoLoad
59 }
60
61 type MachoLoad struct {
62 type_ uint32
63 data []uint32
64 }
65
66 type MachoPlatform int
67
68
73 const (
74 INITIAL_MACHO_HEADR = 4 * 1024
75 )
76
77 const (
78 MACHO_CPU_AMD64 = 1<<24 | 7
79 MACHO_CPU_386 = 7
80 MACHO_SUBCPU_X86 = 3
81 MACHO_CPU_ARM = 12
82 MACHO_SUBCPU_ARM = 0
83 MACHO_SUBCPU_ARMV7 = 9
84 MACHO_CPU_ARM64 = 1<<24 | 12
85 MACHO_SUBCPU_ARM64_ALL = 0
86 MACHO32SYMSIZE = 12
87 MACHO64SYMSIZE = 16
88 MACHO_X86_64_RELOC_UNSIGNED = 0
89 MACHO_X86_64_RELOC_SIGNED = 1
90 MACHO_X86_64_RELOC_BRANCH = 2
91 MACHO_X86_64_RELOC_GOT_LOAD = 3
92 MACHO_X86_64_RELOC_GOT = 4
93 MACHO_X86_64_RELOC_SUBTRACTOR = 5
94 MACHO_X86_64_RELOC_SIGNED_1 = 6
95 MACHO_X86_64_RELOC_SIGNED_2 = 7
96 MACHO_X86_64_RELOC_SIGNED_4 = 8
97 MACHO_ARM_RELOC_VANILLA = 0
98 MACHO_ARM_RELOC_PAIR = 1
99 MACHO_ARM_RELOC_SECTDIFF = 2
100 MACHO_ARM_RELOC_BR24 = 5
101 MACHO_ARM64_RELOC_UNSIGNED = 0
102 MACHO_ARM64_RELOC_BRANCH26 = 2
103 MACHO_ARM64_RELOC_PAGE21 = 3
104 MACHO_ARM64_RELOC_PAGEOFF12 = 4
105 MACHO_ARM64_RELOC_ADDEND = 10
106 MACHO_GENERIC_RELOC_VANILLA = 0
107 MACHO_FAKE_GOTPCREL = 100
108 )
109
110 const (
111 MH_MAGIC = 0xfeedface
112 MH_MAGIC_64 = 0xfeedfacf
113
114 MH_OBJECT = 0x1
115 MH_EXECUTE = 0x2
116
117 MH_NOUNDEFS = 0x1
118 )
119
120 const (
121 LC_SEGMENT = 0x1
122 LC_SYMTAB = 0x2
123 LC_SYMSEG = 0x3
124 LC_THREAD = 0x4
125 LC_UNIXTHREAD = 0x5
126 LC_LOADFVMLIB = 0x6
127 LC_IDFVMLIB = 0x7
128 LC_IDENT = 0x8
129 LC_FVMFILE = 0x9
130 LC_PREPAGE = 0xa
131 LC_DYSYMTAB = 0xb
132 LC_LOAD_DYLIB = 0xc
133 LC_ID_DYLIB = 0xd
134 LC_LOAD_DYLINKER = 0xe
135 LC_ID_DYLINKER = 0xf
136 LC_PREBOUND_DYLIB = 0x10
137 LC_ROUTINES = 0x11
138 LC_SUB_FRAMEWORK = 0x12
139 LC_SUB_UMBRELLA = 0x13
140 LC_SUB_CLIENT = 0x14
141 LC_SUB_LIBRARY = 0x15
142 LC_TWOLEVEL_HINTS = 0x16
143 LC_PREBIND_CKSUM = 0x17
144 LC_LOAD_WEAK_DYLIB = 0x80000018
145 LC_SEGMENT_64 = 0x19
146 LC_ROUTINES_64 = 0x1a
147 LC_UUID = 0x1b
148 LC_RPATH = 0x8000001c
149 LC_CODE_SIGNATURE = 0x1d
150 LC_SEGMENT_SPLIT_INFO = 0x1e
151 LC_REEXPORT_DYLIB = 0x8000001f
152 LC_LAZY_LOAD_DYLIB = 0x20
153 LC_ENCRYPTION_INFO = 0x21
154 LC_DYLD_INFO = 0x22
155 LC_DYLD_INFO_ONLY = 0x80000022
156 LC_LOAD_UPWARD_DYLIB = 0x80000023
157 LC_VERSION_MIN_MACOSX = 0x24
158 LC_VERSION_MIN_IPHONEOS = 0x25
159 LC_FUNCTION_STARTS = 0x26
160 LC_DYLD_ENVIRONMENT = 0x27
161 LC_MAIN = 0x80000028
162 LC_DATA_IN_CODE = 0x29
163 LC_SOURCE_VERSION = 0x2A
164 LC_DYLIB_CODE_SIGN_DRS = 0x2B
165 LC_ENCRYPTION_INFO_64 = 0x2C
166 LC_LINKER_OPTION = 0x2D
167 LC_LINKER_OPTIMIZATION_HINT = 0x2E
168 LC_VERSION_MIN_TVOS = 0x2F
169 LC_VERSION_MIN_WATCHOS = 0x30
170 LC_VERSION_NOTE = 0x31
171 LC_BUILD_VERSION = 0x32
172 )
173
174 const (
175 S_REGULAR = 0x0
176 S_ZEROFILL = 0x1
177 S_NON_LAZY_SYMBOL_POINTERS = 0x6
178 S_SYMBOL_STUBS = 0x8
179 S_MOD_INIT_FUNC_POINTERS = 0x9
180 S_ATTR_PURE_INSTRUCTIONS = 0x80000000
181 S_ATTR_DEBUG = 0x02000000
182 S_ATTR_SOME_INSTRUCTIONS = 0x00000400
183 )
184
185 const (
186 PLATFORM_MACOS MachoPlatform = 1
187 PLATFORM_IOS MachoPlatform = 2
188 PLATFORM_TVOS MachoPlatform = 3
189 PLATFORM_WATCHOS MachoPlatform = 4
190 PLATFORM_BRIDGEOS MachoPlatform = 5
191 )
192
193
194
195
196 var machohdr MachoHdr
197
198 var load []MachoLoad
199
200 var machoPlatform MachoPlatform
201
202 var seg [16]MachoSeg
203
204 var nseg int
205
206 var ndebug int
207
208 var nsect int
209
210 const (
211 SymKindLocal = 0 + iota
212 SymKindExtdef
213 SymKindUndef
214 NumSymKind
215 )
216
217 var nkind [NumSymKind]int
218
219 var sortsym []*sym.Symbol
220
221 var nsortsym int
222
223
224
225
226
227
228
229 var loadBudget = INITIAL_MACHO_HEADR - 2*1024
230
231 func getMachoHdr() *MachoHdr {
232 return &machohdr
233 }
234
235 func newMachoLoad(arch *sys.Arch, type_ uint32, ndata uint32) *MachoLoad {
236 if arch.PtrSize == 8 && (ndata&1 != 0) {
237 ndata++
238 }
239
240 load = append(load, MachoLoad{})
241 l := &load[len(load)-1]
242 l.type_ = type_
243 l.data = make([]uint32, ndata)
244 return l
245 }
246
247 func newMachoSeg(name string, msect int) *MachoSeg {
248 if nseg >= len(seg) {
249 Exitf("too many segs")
250 }
251
252 s := &seg[nseg]
253 nseg++
254 s.name = name
255 s.msect = uint32(msect)
256 s.sect = make([]MachoSect, msect)
257 return s
258 }
259
260 func newMachoSect(seg *MachoSeg, name string, segname string) *MachoSect {
261 if seg.nsect >= seg.msect {
262 Exitf("too many sects in segment %s", seg.name)
263 }
264
265 s := &seg.sect[seg.nsect]
266 seg.nsect++
267 s.name = name
268 s.segname = segname
269 nsect++
270 return s
271 }
272
273
274
275 var dylib []string
276
277 var linkoff int64
278
279 func machowrite(arch *sys.Arch, out *OutBuf, linkmode LinkMode) int {
280 o1 := out.Offset()
281
282 loadsize := 4 * 4 * ndebug
283 for i := range load {
284 loadsize += 4 * (len(load[i].data) + 2)
285 }
286 if arch.PtrSize == 8 {
287 loadsize += 18 * 4 * nseg
288 loadsize += 20 * 4 * nsect
289 } else {
290 loadsize += 14 * 4 * nseg
291 loadsize += 17 * 4 * nsect
292 }
293
294 if arch.PtrSize == 8 {
295 out.Write32(MH_MAGIC_64)
296 } else {
297 out.Write32(MH_MAGIC)
298 }
299 out.Write32(machohdr.cpu)
300 out.Write32(machohdr.subcpu)
301 if linkmode == LinkExternal {
302 out.Write32(MH_OBJECT)
303 } else {
304 out.Write32(MH_EXECUTE)
305 }
306 out.Write32(uint32(len(load)) + uint32(nseg) + uint32(ndebug))
307 out.Write32(uint32(loadsize))
308 if nkind[SymKindUndef] == 0 {
309 out.Write32(MH_NOUNDEFS)
310 } else {
311 out.Write32(0)
312 }
313 if arch.PtrSize == 8 {
314 out.Write32(0)
315 }
316
317 for i := 0; i < nseg; i++ {
318 s := &seg[i]
319 if arch.PtrSize == 8 {
320 out.Write32(LC_SEGMENT_64)
321 out.Write32(72 + 80*s.nsect)
322 out.WriteStringN(s.name, 16)
323 out.Write64(s.vaddr)
324 out.Write64(s.vsize)
325 out.Write64(s.fileoffset)
326 out.Write64(s.filesize)
327 out.Write32(s.prot1)
328 out.Write32(s.prot2)
329 out.Write32(s.nsect)
330 out.Write32(s.flag)
331 } else {
332 out.Write32(LC_SEGMENT)
333 out.Write32(56 + 68*s.nsect)
334 out.WriteStringN(s.name, 16)
335 out.Write32(uint32(s.vaddr))
336 out.Write32(uint32(s.vsize))
337 out.Write32(uint32(s.fileoffset))
338 out.Write32(uint32(s.filesize))
339 out.Write32(s.prot1)
340 out.Write32(s.prot2)
341 out.Write32(s.nsect)
342 out.Write32(s.flag)
343 }
344
345 for j := uint32(0); j < s.nsect; j++ {
346 t := &s.sect[j]
347 if arch.PtrSize == 8 {
348 out.WriteStringN(t.name, 16)
349 out.WriteStringN(t.segname, 16)
350 out.Write64(t.addr)
351 out.Write64(t.size)
352 out.Write32(t.off)
353 out.Write32(t.align)
354 out.Write32(t.reloc)
355 out.Write32(t.nreloc)
356 out.Write32(t.flag)
357 out.Write32(t.res1)
358 out.Write32(t.res2)
359 out.Write32(0)
360 } else {
361 out.WriteStringN(t.name, 16)
362 out.WriteStringN(t.segname, 16)
363 out.Write32(uint32(t.addr))
364 out.Write32(uint32(t.size))
365 out.Write32(t.off)
366 out.Write32(t.align)
367 out.Write32(t.reloc)
368 out.Write32(t.nreloc)
369 out.Write32(t.flag)
370 out.Write32(t.res1)
371 out.Write32(t.res2)
372 }
373 }
374 }
375
376 for i := range load {
377 l := &load[i]
378 out.Write32(l.type_)
379 out.Write32(4 * (uint32(len(l.data)) + 2))
380 for j := 0; j < len(l.data); j++ {
381 out.Write32(l.data[j])
382 }
383 }
384
385 return int(out.Offset() - o1)
386 }
387
388 func (ctxt *Link) domacho() {
389 if *FlagD {
390 return
391 }
392
393
394 for _, h := range hostobj {
395 load, err := hostobjMachoPlatform(&h)
396 if err != nil {
397 Exitf("%v", err)
398 }
399 if load != nil {
400 machoPlatform = load.platform
401 ml := newMachoLoad(ctxt.Arch, load.cmd.type_, uint32(len(load.cmd.data)))
402 copy(ml.data, load.cmd.data)
403 break
404 }
405 }
406 if machoPlatform == 0 {
407 machoPlatform = PLATFORM_MACOS
408 if ctxt.LinkMode == LinkInternal {
409
410
411
412
413
414
415
416
417
418
419 ml := newMachoLoad(ctxt.Arch, LC_VERSION_MIN_MACOSX, 2)
420 ml.data[0] = 10<<16 | 9<<8 | 0<<0
421 ml.data[1] = 10<<16 | 9<<8 | 0<<0
422 }
423 }
424
425
426 s := ctxt.Syms.Lookup(".machosymstr", 0)
427
428 s.Type = sym.SMACHOSYMSTR
429 s.Attr |= sym.AttrReachable
430 s.AddUint8(' ')
431 s.AddUint8('\x00')
432
433 s = ctxt.Syms.Lookup(".machosymtab", 0)
434 s.Type = sym.SMACHOSYMTAB
435 s.Attr |= sym.AttrReachable
436
437 if ctxt.LinkMode != LinkExternal {
438 s := ctxt.Syms.Lookup(".plt", 0)
439 s.Type = sym.SMACHOPLT
440 s.Attr |= sym.AttrReachable
441
442 s = ctxt.Syms.Lookup(".got", 0)
443 s.Type = sym.SMACHOGOT
444 s.Attr |= sym.AttrReachable
445 s.Align = 4
446
447 s = ctxt.Syms.Lookup(".linkedit.plt", 0)
448 s.Type = sym.SMACHOINDIRECTPLT
449 s.Attr |= sym.AttrReachable
450
451 s = ctxt.Syms.Lookup(".linkedit.got", 0)
452 s.Type = sym.SMACHOINDIRECTGOT
453 s.Attr |= sym.AttrReachable
454 }
455
456
457 if ctxt.LinkMode == LinkExternal {
458 s := ctxt.Syms.Lookup(".llvmasm", 0)
459 s.Type = sym.SMACHO
460 s.Attr |= sym.AttrReachable
461 s.AddUint8(0)
462 }
463 }
464
465 func machoadddynlib(lib string, linkmode LinkMode) {
466 if seenlib[lib] || linkmode == LinkExternal {
467 return
468 }
469 seenlib[lib] = true
470
471
472
473
474
475 loadBudget -= (len(lib)+7)/8*8 + 24
476
477 if loadBudget < 0 {
478 HEADR += 4096
479 *FlagTextAddr += 4096
480 loadBudget += 4096
481 }
482
483 dylib = append(dylib, lib)
484 }
485
486 func machoshbits(ctxt *Link, mseg *MachoSeg, sect *sym.Section, segname string) {
487 buf := "__" + strings.Replace(sect.Name[1:], ".", "_", -1)
488
489 var msect *MachoSect
490 if sect.Rwx&1 == 0 && segname != "__DWARF" && (ctxt.Arch.Family == sys.ARM64 ||
491 (ctxt.Arch.Family == sys.AMD64 && ctxt.BuildMode != BuildModeExe) ||
492 (ctxt.Arch.Family == sys.ARM && ctxt.BuildMode != BuildModeExe)) {
493
494
495
496 msect = newMachoSect(mseg, buf, "__DATA")
497 } else {
498 msect = newMachoSect(mseg, buf, segname)
499 }
500
501 if sect.Rellen > 0 {
502 msect.reloc = uint32(sect.Reloff)
503 msect.nreloc = uint32(sect.Rellen / 8)
504 }
505
506 for 1<<msect.align < sect.Align {
507 msect.align++
508 }
509 msect.addr = sect.Vaddr
510 msect.size = sect.Length
511
512 if sect.Vaddr < sect.Seg.Vaddr+sect.Seg.Filelen {
513
514 if sect.Length > sect.Seg.Vaddr+sect.Seg.Filelen-sect.Vaddr {
515 Errorf(nil, "macho cannot represent section %s crossing data and bss", sect.Name)
516 }
517 msect.off = uint32(sect.Seg.Fileoff + sect.Vaddr - sect.Seg.Vaddr)
518 } else {
519 msect.off = 0
520 msect.flag |= S_ZEROFILL
521 }
522
523 if sect.Rwx&1 != 0 {
524 msect.flag |= S_ATTR_SOME_INSTRUCTIONS
525 }
526
527 if sect.Name == ".text" {
528 msect.flag |= S_ATTR_PURE_INSTRUCTIONS
529 }
530
531 if sect.Name == ".plt" {
532 msect.name = "__symbol_stub1"
533 msect.flag = S_ATTR_PURE_INSTRUCTIONS | S_ATTR_SOME_INSTRUCTIONS | S_SYMBOL_STUBS
534 msect.res1 = 0
535 msect.res2 = 6
536 }
537
538 if sect.Name == ".got" {
539 msect.name = "__nl_symbol_ptr"
540 msect.flag = S_NON_LAZY_SYMBOL_POINTERS
541 msect.res1 = uint32(ctxt.Syms.Lookup(".linkedit.plt", 0).Size / 4)
542 }
543
544 if sect.Name == ".init_array" {
545 msect.name = "__mod_init_func"
546 msect.flag = S_MOD_INIT_FUNC_POINTERS
547 }
548
549
550
551
552
553
554
555 if sect.Name == ".llvmasm" {
556 msect.name = "__asm"
557 msect.segname = "__LLVM"
558 }
559
560 if segname == "__DWARF" {
561 msect.flag |= S_ATTR_DEBUG
562 }
563 }
564
565 func Asmbmacho(ctxt *Link) {
566
567 va := *FlagTextAddr - int64(HEADR)
568
569 mh := getMachoHdr()
570 switch ctxt.Arch.Family {
571 default:
572 Exitf("unknown macho architecture: %v", ctxt.Arch.Family)
573
574 case sys.ARM:
575 mh.cpu = MACHO_CPU_ARM
576 mh.subcpu = MACHO_SUBCPU_ARMV7
577
578 case sys.AMD64:
579 mh.cpu = MACHO_CPU_AMD64
580 mh.subcpu = MACHO_SUBCPU_X86
581
582 case sys.ARM64:
583 mh.cpu = MACHO_CPU_ARM64
584 mh.subcpu = MACHO_SUBCPU_ARM64_ALL
585
586 case sys.I386:
587 mh.cpu = MACHO_CPU_386
588 mh.subcpu = MACHO_SUBCPU_X86
589 }
590
591 var ms *MachoSeg
592 if ctxt.LinkMode == LinkExternal {
593
594 ms = newMachoSeg("", 40)
595
596 ms.fileoffset = Segtext.Fileoff
597 ms.filesize = Segdwarf.Fileoff + Segdwarf.Filelen - Segtext.Fileoff
598 ms.vsize = Segdwarf.Vaddr + Segdwarf.Length - Segtext.Vaddr
599 }
600
601
602 if ctxt.LinkMode != LinkExternal {
603 ms = newMachoSeg("__PAGEZERO", 0)
604 ms.vsize = uint64(va)
605 }
606
607
608 v := Rnd(int64(uint64(HEADR)+Segtext.Length), int64(*FlagRound))
609
610 if ctxt.LinkMode != LinkExternal {
611 ms = newMachoSeg("__TEXT", 20)
612 ms.vaddr = uint64(va)
613 ms.vsize = uint64(v)
614 ms.fileoffset = 0
615 ms.filesize = uint64(v)
616 ms.prot1 = 7
617 ms.prot2 = 5
618 }
619
620 for _, sect := range Segtext.Sections {
621 machoshbits(ctxt, ms, sect, "__TEXT")
622 }
623
624
625 if ctxt.LinkMode != LinkExternal {
626 w := int64(Segdata.Length)
627 ms = newMachoSeg("__DATA", 20)
628 ms.vaddr = uint64(va) + uint64(v)
629 ms.vsize = uint64(w)
630 ms.fileoffset = uint64(v)
631 ms.filesize = Segdata.Filelen
632 ms.prot1 = 3
633 ms.prot2 = 3
634 }
635
636 for _, sect := range Segdata.Sections {
637 machoshbits(ctxt, ms, sect, "__DATA")
638 }
639
640
641 if !*FlagW {
642 if ctxt.LinkMode != LinkExternal {
643 ms = newMachoSeg("__DWARF", 20)
644 ms.vaddr = Segdwarf.Vaddr
645 ms.vsize = 0
646 ms.fileoffset = Segdwarf.Fileoff
647 ms.filesize = Segdwarf.Filelen
648 }
649 for _, sect := range Segdwarf.Sections {
650 machoshbits(ctxt, ms, sect, "__DWARF")
651 }
652 }
653
654 if ctxt.LinkMode != LinkExternal {
655 switch ctxt.Arch.Family {
656 default:
657 Exitf("unknown macho architecture: %v", ctxt.Arch.Family)
658
659 case sys.ARM:
660 ml := newMachoLoad(ctxt.Arch, LC_UNIXTHREAD, 17+2)
661 ml.data[0] = 1
662 ml.data[1] = 17
663 ml.data[2+15] = uint32(Entryvalue(ctxt))
664
665 case sys.AMD64:
666 ml := newMachoLoad(ctxt.Arch, LC_UNIXTHREAD, 42+2)
667 ml.data[0] = 4
668 ml.data[1] = 42
669 ml.data[2+32] = uint32(Entryvalue(ctxt))
670 ml.data[2+32+1] = uint32(Entryvalue(ctxt) >> 32)
671
672 case sys.ARM64:
673 ml := newMachoLoad(ctxt.Arch, LC_UNIXTHREAD, 68+2)
674 ml.data[0] = 6
675 ml.data[1] = 68
676 ml.data[2+64] = uint32(Entryvalue(ctxt))
677 ml.data[2+64+1] = uint32(Entryvalue(ctxt) >> 32)
678
679 case sys.I386:
680 ml := newMachoLoad(ctxt.Arch, LC_UNIXTHREAD, 16+2)
681 ml.data[0] = 1
682 ml.data[1] = 16
683 ml.data[2+10] = uint32(Entryvalue(ctxt))
684 }
685 }
686
687 if !*FlagD {
688
689 s1 := ctxt.Syms.Lookup(".machosymtab", 0)
690 s2 := ctxt.Syms.Lookup(".linkedit.plt", 0)
691 s3 := ctxt.Syms.Lookup(".linkedit.got", 0)
692 s4 := ctxt.Syms.Lookup(".machosymstr", 0)
693
694 if ctxt.LinkMode != LinkExternal {
695 ms := newMachoSeg("__LINKEDIT", 0)
696 ms.vaddr = uint64(va) + uint64(v) + uint64(Rnd(int64(Segdata.Length), int64(*FlagRound)))
697 ms.vsize = uint64(s1.Size) + uint64(s2.Size) + uint64(s3.Size) + uint64(s4.Size)
698 ms.fileoffset = uint64(linkoff)
699 ms.filesize = ms.vsize
700 ms.prot1 = 7
701 ms.prot2 = 3
702 }
703
704 ml := newMachoLoad(ctxt.Arch, LC_SYMTAB, 4)
705 ml.data[0] = uint32(linkoff)
706 ml.data[1] = uint32(nsortsym)
707 ml.data[2] = uint32(linkoff + s1.Size + s2.Size + s3.Size)
708 ml.data[3] = uint32(s4.Size)
709
710 machodysymtab(ctxt)
711
712 if ctxt.LinkMode != LinkExternal {
713 ml := newMachoLoad(ctxt.Arch, LC_LOAD_DYLINKER, 6)
714 ml.data[0] = 12
715 stringtouint32(ml.data[1:], "/usr/lib/dyld")
716
717 for _, lib := range dylib {
718 ml = newMachoLoad(ctxt.Arch, LC_LOAD_DYLIB, 4+(uint32(len(lib))+1+7)/8*2)
719 ml.data[0] = 24
720 ml.data[1] = 0
721 ml.data[2] = 0
722 ml.data[3] = 0
723 stringtouint32(ml.data[4:], lib)
724 }
725 }
726 }
727
728 a := machowrite(ctxt.Arch, ctxt.Out, ctxt.LinkMode)
729 if int32(a) > HEADR {
730 Exitf("HEADR too small: %d > %d", a, HEADR)
731 }
732 }
733
734 func symkind(s *sym.Symbol) int {
735 if s.Type == sym.SDYNIMPORT {
736 return SymKindUndef
737 }
738 if s.Attr.CgoExport() {
739 return SymKindExtdef
740 }
741 return SymKindLocal
742 }
743
744 func addsym(ctxt *Link, s *sym.Symbol, name string, type_ SymbolType, addr int64, gotype *sym.Symbol) {
745 if s == nil {
746 return
747 }
748
749 switch type_ {
750 default:
751 return
752
753 case DataSym, BSSSym, TextSym:
754 break
755 }
756
757 if sortsym != nil {
758 sortsym[nsortsym] = s
759 nkind[symkind(s)]++
760 }
761
762 nsortsym++
763 }
764
765 type machoscmp []*sym.Symbol
766
767 func (x machoscmp) Len() int {
768 return len(x)
769 }
770
771 func (x machoscmp) Swap(i, j int) {
772 x[i], x[j] = x[j], x[i]
773 }
774
775 func (x machoscmp) Less(i, j int) bool {
776 s1 := x[i]
777 s2 := x[j]
778
779 k1 := symkind(s1)
780 k2 := symkind(s2)
781 if k1 != k2 {
782 return k1 < k2
783 }
784
785 return s1.Extname() < s2.Extname()
786 }
787
788 func machogenasmsym(ctxt *Link) {
789 genasmsym(ctxt, addsym)
790 for _, s := range ctxt.Syms.Allsym {
791
792 if s.Type == sym.SDYNIMPORT && s.Dynimplib() == "/usr/lib/libSystem.B.dylib" {
793
794 if machoPlatform == PLATFORM_MACOS {
795 switch n := s.Extname(); n {
796 case "fdopendir":
797 switch objabi.GOARCH {
798 case "amd64":
799 s.SetExtname(n + "$INODE64")
800 case "386":
801 s.SetExtname(n + "$INODE64$UNIX2003")
802 }
803 case "readdir_r", "getfsstat":
804 switch objabi.GOARCH {
805 case "amd64", "386":
806 s.SetExtname(n + "$INODE64")
807 }
808 }
809 }
810 }
811
812 if s.Type == sym.SDYNIMPORT || s.Type == sym.SHOSTOBJ {
813 if s.Attr.Reachable() {
814 addsym(ctxt, s, "", DataSym, 0, nil)
815 }
816 }
817 }
818 }
819
820 func machosymorder(ctxt *Link) {
821
822
823
824 for i := range dynexp {
825 dynexp[i].Attr |= sym.AttrReachable
826 }
827 machogenasmsym(ctxt)
828 sortsym = make([]*sym.Symbol, nsortsym)
829 nsortsym = 0
830 machogenasmsym(ctxt)
831 sort.Sort(machoscmp(sortsym[:nsortsym]))
832 for i := 0; i < nsortsym; i++ {
833 sortsym[i].Dynid = int32(i)
834 }
835 }
836
837
838
839
840
841 func machoShouldExport(ctxt *Link, s *sym.Symbol) bool {
842 if !ctxt.DynlinkingGo() || s.Attr.Local() {
843 return false
844 }
845 if ctxt.BuildMode == BuildModePlugin && strings.HasPrefix(s.Extname(), objabi.PathToPrefix(*flagPluginPath)) {
846 return true
847 }
848 if strings.HasPrefix(s.Name, "go.itab.") {
849 return true
850 }
851 if strings.HasPrefix(s.Name, "type.") && !strings.HasPrefix(s.Name, "type..") {
852
853
854
855 return true
856 }
857 if strings.HasPrefix(s.Name, "go.link.pkghash") {
858 return true
859 }
860 return s.Type >= sym.SFirstWritable
861 }
862
863 func machosymtab(ctxt *Link) {
864 symtab := ctxt.Syms.Lookup(".machosymtab", 0)
865 symstr := ctxt.Syms.Lookup(".machosymstr", 0)
866
867 for i := 0; i < nsortsym; i++ {
868 s := sortsym[i]
869 symtab.AddUint32(ctxt.Arch, uint32(symstr.Size))
870
871 export := machoShouldExport(ctxt, s)
872
873
874
875
876
877
878
879
880 cexport := !strings.Contains(s.Extname(), ".") && (ctxt.BuildMode != BuildModePlugin || onlycsymbol(s))
881 if cexport || export {
882 symstr.AddUint8('_')
883 }
884
885
886 Addstring(symstr, strings.Replace(s.Extname(), "·", ".", -1))
887
888 if s.Type == sym.SDYNIMPORT || s.Type == sym.SHOSTOBJ {
889 symtab.AddUint8(0x01)
890 symtab.AddUint8(0)
891 symtab.AddUint16(ctxt.Arch, 0)
892 symtab.AddUintXX(ctxt.Arch, 0, ctxt.Arch.PtrSize)
893 } else {
894 if s.Attr.CgoExport() || export {
895 symtab.AddUint8(0x0f)
896 } else {
897 symtab.AddUint8(0x0e)
898 }
899 o := s
900 for o.Outer != nil {
901 o = o.Outer
902 }
903 if o.Sect == nil {
904 Errorf(s, "missing section for symbol")
905 symtab.AddUint8(0)
906 } else {
907 symtab.AddUint8(uint8(o.Sect.Extnum))
908 }
909 symtab.AddUint16(ctxt.Arch, 0)
910 symtab.AddUintXX(ctxt.Arch, uint64(Symaddr(s)), ctxt.Arch.PtrSize)
911 }
912 }
913 }
914
915 func machodysymtab(ctxt *Link) {
916 ml := newMachoLoad(ctxt.Arch, LC_DYSYMTAB, 18)
917
918 n := 0
919 ml.data[0] = uint32(n)
920 ml.data[1] = uint32(nkind[SymKindLocal])
921 n += nkind[SymKindLocal]
922
923 ml.data[2] = uint32(n)
924 ml.data[3] = uint32(nkind[SymKindExtdef])
925 n += nkind[SymKindExtdef]
926
927 ml.data[4] = uint32(n)
928 ml.data[5] = uint32(nkind[SymKindUndef])
929
930 ml.data[6] = 0
931 ml.data[7] = 0
932 ml.data[8] = 0
933 ml.data[9] = 0
934 ml.data[10] = 0
935 ml.data[11] = 0
936
937
938 s1 := ctxt.Syms.Lookup(".machosymtab", 0)
939
940 s2 := ctxt.Syms.Lookup(".linkedit.plt", 0)
941 s3 := ctxt.Syms.Lookup(".linkedit.got", 0)
942 ml.data[12] = uint32(linkoff + s1.Size)
943 ml.data[13] = uint32((s2.Size + s3.Size) / 4)
944
945 ml.data[14] = 0
946 ml.data[15] = 0
947 ml.data[16] = 0
948 ml.data[17] = 0
949 }
950
951 func Domacholink(ctxt *Link) int64 {
952 machosymtab(ctxt)
953
954
955 s1 := ctxt.Syms.Lookup(".machosymtab", 0)
956
957 s2 := ctxt.Syms.Lookup(".linkedit.plt", 0)
958 s3 := ctxt.Syms.Lookup(".linkedit.got", 0)
959 s4 := ctxt.Syms.Lookup(".machosymstr", 0)
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978 for s4.Size%16 != 0 {
979 s4.AddUint8(0)
980 }
981
982 size := int(s1.Size + s2.Size + s3.Size + s4.Size)
983
984 if size > 0 {
985 linkoff = Rnd(int64(uint64(HEADR)+Segtext.Length), int64(*FlagRound)) + Rnd(int64(Segdata.Filelen), int64(*FlagRound)) + Rnd(int64(Segdwarf.Filelen), int64(*FlagRound))
986 ctxt.Out.SeekSet(linkoff)
987
988 ctxt.Out.Write(s1.P[:s1.Size])
989 ctxt.Out.Write(s2.P[:s2.Size])
990 ctxt.Out.Write(s3.P[:s3.Size])
991 ctxt.Out.Write(s4.P[:s4.Size])
992 }
993
994 return Rnd(int64(size), int64(*FlagRound))
995 }
996
997 func machorelocsect(ctxt *Link, sect *sym.Section, syms []*sym.Symbol) {
998
999 if sect.Vaddr >= sect.Seg.Vaddr+sect.Seg.Filelen {
1000 return
1001 }
1002
1003 sect.Reloff = uint64(ctxt.Out.Offset())
1004 for i, s := range syms {
1005 if !s.Attr.Reachable() {
1006 continue
1007 }
1008 if uint64(s.Value) >= sect.Vaddr {
1009 syms = syms[i:]
1010 break
1011 }
1012 }
1013
1014 eaddr := int32(sect.Vaddr + sect.Length)
1015 for _, s := range syms {
1016 if !s.Attr.Reachable() {
1017 continue
1018 }
1019 if s.Value >= int64(eaddr) {
1020 break
1021 }
1022 for ri := range s.R {
1023 r := &s.R[ri]
1024 if r.Done {
1025 continue
1026 }
1027 if r.Xsym == nil {
1028 Errorf(s, "missing xsym in relocation")
1029 continue
1030 }
1031 if !r.Xsym.Attr.Reachable() {
1032 Errorf(s, "unreachable reloc %d (%s) target %v", r.Type, sym.RelocName(ctxt.Arch, r.Type), r.Xsym.Name)
1033 }
1034 if !thearch.Machoreloc1(ctxt.Arch, ctxt.Out, s, r, int64(uint64(s.Value+int64(r.Off))-sect.Vaddr)) {
1035 Errorf(s, "unsupported obj reloc %d (%s)/%d to %s", r.Type, sym.RelocName(ctxt.Arch, r.Type), r.Siz, r.Sym.Name)
1036 }
1037 }
1038 }
1039
1040 sect.Rellen = uint64(ctxt.Out.Offset()) - sect.Reloff
1041 }
1042
1043 func Machoemitreloc(ctxt *Link) {
1044 for ctxt.Out.Offset()&7 != 0 {
1045 ctxt.Out.Write8(0)
1046 }
1047
1048 machorelocsect(ctxt, Segtext.Sections[0], ctxt.Textp)
1049 for _, sect := range Segtext.Sections[1:] {
1050 machorelocsect(ctxt, sect, datap)
1051 }
1052 for _, sect := range Segdata.Sections {
1053 machorelocsect(ctxt, sect, datap)
1054 }
1055 for _, sect := range Segdwarf.Sections {
1056 machorelocsect(ctxt, sect, dwarfp)
1057 }
1058 }
1059
1060
1061
1062 func hostobjMachoPlatform(h *Hostobj) (*MachoPlatformLoad, error) {
1063 f, err := os.Open(h.file)
1064 if err != nil {
1065 return nil, fmt.Errorf("%s: failed to open host object: %v\n", h.file, err)
1066 }
1067 defer f.Close()
1068 sr := io.NewSectionReader(f, h.off, h.length)
1069 m, err := macho.NewFile(sr)
1070 if err != nil {
1071
1072 return nil, nil
1073 }
1074 return peekMachoPlatform(m)
1075 }
1076
1077
1078
1079 func peekMachoPlatform(m *macho.File) (*MachoPlatformLoad, error) {
1080 for _, cmd := range m.Loads {
1081 raw := cmd.Raw()
1082 ml := MachoLoad{
1083 type_: m.ByteOrder.Uint32(raw),
1084 }
1085
1086 data := raw[8:]
1087 var p MachoPlatform
1088 switch ml.type_ {
1089 case LC_VERSION_MIN_IPHONEOS:
1090 p = PLATFORM_IOS
1091 case LC_VERSION_MIN_MACOSX:
1092 p = PLATFORM_MACOS
1093 case LC_VERSION_MIN_WATCHOS:
1094 p = PLATFORM_WATCHOS
1095 case LC_VERSION_MIN_TVOS:
1096 p = PLATFORM_TVOS
1097 case LC_BUILD_VERSION:
1098 p = MachoPlatform(m.ByteOrder.Uint32(data))
1099 default:
1100 continue
1101 }
1102 ml.data = make([]uint32, len(data)/4)
1103 r := bytes.NewReader(data)
1104 if err := binary.Read(r, m.ByteOrder, &ml.data); err != nil {
1105 return nil, err
1106 }
1107 return &MachoPlatformLoad{
1108 platform: p,
1109 cmd: ml,
1110 }, nil
1111 }
1112 return nil, nil
1113 }
1114
View as plain text