1 // Copyright 2009 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
9 "cmd/internal/codesign"
13 "cmd/link/internal/loader"
14 "cmd/link/internal/sym"
25 type MachoHdr struct {
30 type MachoSect struct {
44 type MachoSeg struct {
58 // MachoPlatformLoad represents a LC_VERSION_MIN_* or
59 // LC_BUILD_VERSION load command.
60 type MachoPlatformLoad struct {
61 platform MachoPlatform // One of PLATFORM_* constants.
65 type MachoLoad struct {
70 type MachoPlatform int
73 * Total amount of space to reserve at the start of the file
74 * for Header, PHeaders, and SHeaders.
78 INITIAL_MACHO_HEADR = 4 * 1024
82 MACHO_CPU_AMD64 = 1<<24 | 7
87 MACHO_SUBCPU_ARMV7 = 9
88 MACHO_CPU_ARM64 = 1<<24 | 12
89 MACHO_SUBCPU_ARM64_ALL = 0
92 MACHO_X86_64_RELOC_UNSIGNED = 0
93 MACHO_X86_64_RELOC_SIGNED = 1
94 MACHO_X86_64_RELOC_BRANCH = 2
95 MACHO_X86_64_RELOC_GOT_LOAD = 3
96 MACHO_X86_64_RELOC_GOT = 4
97 MACHO_X86_64_RELOC_SUBTRACTOR = 5
98 MACHO_X86_64_RELOC_SIGNED_1 = 6
99 MACHO_X86_64_RELOC_SIGNED_2 = 7
100 MACHO_X86_64_RELOC_SIGNED_4 = 8
101 MACHO_ARM_RELOC_VANILLA = 0
102 MACHO_ARM_RELOC_PAIR = 1
103 MACHO_ARM_RELOC_SECTDIFF = 2
104 MACHO_ARM_RELOC_BR24 = 5
105 MACHO_ARM64_RELOC_UNSIGNED = 0
106 MACHO_ARM64_RELOC_BRANCH26 = 2
107 MACHO_ARM64_RELOC_PAGE21 = 3
108 MACHO_ARM64_RELOC_PAGEOFF12 = 4
109 MACHO_ARM64_RELOC_GOT_LOAD_PAGE21 = 5
110 MACHO_ARM64_RELOC_GOT_LOAD_PAGEOFF12 = 6
111 MACHO_ARM64_RELOC_ADDEND = 10
112 MACHO_GENERIC_RELOC_VANILLA = 0
113 MACHO_FAKE_GOTPCREL = 100
117 MH_MAGIC = 0xfeedface
118 MH_MAGIC_64 = 0xfeedfacf
142 LC_LOAD_DYLINKER = 0xe
144 LC_PREBOUND_DYLIB = 0x10
146 LC_SUB_FRAMEWORK = 0x12
147 LC_SUB_UMBRELLA = 0x13
149 LC_SUB_LIBRARY = 0x15
150 LC_TWOLEVEL_HINTS = 0x16
151 LC_PREBIND_CKSUM = 0x17
152 LC_LOAD_WEAK_DYLIB = 0x80000018
154 LC_ROUTINES_64 = 0x1a
156 LC_RPATH = 0x8000001c
157 LC_CODE_SIGNATURE = 0x1d
158 LC_SEGMENT_SPLIT_INFO = 0x1e
159 LC_REEXPORT_DYLIB = 0x8000001f
160 LC_LAZY_LOAD_DYLIB = 0x20
161 LC_ENCRYPTION_INFO = 0x21
163 LC_DYLD_INFO_ONLY = 0x80000022
164 LC_LOAD_UPWARD_DYLIB = 0x80000023
165 LC_VERSION_MIN_MACOSX = 0x24
166 LC_VERSION_MIN_IPHONEOS = 0x25
167 LC_FUNCTION_STARTS = 0x26
168 LC_DYLD_ENVIRONMENT = 0x27
170 LC_DATA_IN_CODE = 0x29
171 LC_SOURCE_VERSION = 0x2A
172 LC_DYLIB_CODE_SIGN_DRS = 0x2B
173 LC_ENCRYPTION_INFO_64 = 0x2C
174 LC_LINKER_OPTION = 0x2D
175 LC_LINKER_OPTIMIZATION_HINT = 0x2E
176 LC_VERSION_MIN_TVOS = 0x2F
177 LC_VERSION_MIN_WATCHOS = 0x30
178 LC_VERSION_NOTE = 0x31
179 LC_BUILD_VERSION = 0x32
185 S_NON_LAZY_SYMBOL_POINTERS = 0x6
187 S_MOD_INIT_FUNC_POINTERS = 0x9
188 S_ATTR_PURE_INSTRUCTIONS = 0x80000000
189 S_ATTR_DEBUG = 0x02000000
190 S_ATTR_SOME_INSTRUCTIONS = 0x00000400
194 PLATFORM_MACOS MachoPlatform = 1
195 PLATFORM_IOS MachoPlatform = 2
196 PLATFORM_TVOS MachoPlatform = 3
197 PLATFORM_WATCHOS MachoPlatform = 4
198 PLATFORM_BRIDGEOS MachoPlatform = 5
201 // rebase table opcode
203 REBASE_TYPE_POINTER = 1
204 REBASE_TYPE_TEXT_ABSOLUTE32 = 2
205 REBASE_TYPE_TEXT_PCREL32 = 3
207 REBASE_OPCODE_MASK = 0xF0
208 REBASE_IMMEDIATE_MASK = 0x0F
209 REBASE_OPCODE_DONE = 0x00
210 REBASE_OPCODE_SET_TYPE_IMM = 0x10
211 REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB = 0x20
212 REBASE_OPCODE_ADD_ADDR_ULEB = 0x30
213 REBASE_OPCODE_ADD_ADDR_IMM_SCALED = 0x40
214 REBASE_OPCODE_DO_REBASE_IMM_TIMES = 0x50
215 REBASE_OPCODE_DO_REBASE_ULEB_TIMES = 0x60
216 REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB = 0x70
217 REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB = 0x80
222 BIND_TYPE_POINTER = 1
223 BIND_TYPE_TEXT_ABSOLUTE32 = 2
224 BIND_TYPE_TEXT_PCREL32 = 3
226 BIND_SPECIAL_DYLIB_SELF = 0
227 BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE = -1
228 BIND_SPECIAL_DYLIB_FLAT_LOOKUP = -2
229 BIND_SPECIAL_DYLIB_WEAK_LOOKUP = -3
231 BIND_OPCODE_MASK = 0xF0
232 BIND_IMMEDIATE_MASK = 0x0F
233 BIND_OPCODE_DONE = 0x00
234 BIND_OPCODE_SET_DYLIB_ORDINAL_IMM = 0x10
235 BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB = 0x20
236 BIND_OPCODE_SET_DYLIB_SPECIAL_IMM = 0x30
237 BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM = 0x40
238 BIND_OPCODE_SET_TYPE_IMM = 0x50
239 BIND_OPCODE_SET_ADDEND_SLEB = 0x60
240 BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB = 0x70
241 BIND_OPCODE_ADD_ADDR_ULEB = 0x80
242 BIND_OPCODE_DO_BIND = 0x90
243 BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB = 0xA0
244 BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED = 0xB0
245 BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB = 0xC0
246 BIND_OPCODE_THREADED = 0xD0
247 BIND_SUBOPCODE_THREADED_SET_BIND_ORDINAL_TABLE_SIZE_ULEB = 0x00
248 BIND_SUBOPCODE_THREADED_APPLY = 0x01
251 const machoHeaderSize64 = 8 * 4 // size of 64-bit Mach-O header
253 // Mach-O file writing
254 // https://developer.apple.com/mac/library/DOCUMENTATION/DeveloperTools/Conceptual/MachORuntime/Reference/reference.html
256 var machohdr MachoHdr
260 var machoPlatform MachoPlatform
271 SymKindLocal = 0 + iota
277 var nkind [NumSymKind]int
279 var sortsym []loader.Sym
283 // Amount of space left for adding load commands
284 // that refer to dynamic libraries. Because these have
285 // to go in the Mach-O header, we can't just pick a
286 // "big enough" header size. The initial header is
287 // one page, the non-dynamic library stuff takes
288 // up about 1300 bytes; we overestimate that as 2k.
289 var loadBudget = INITIAL_MACHO_HEADR - 2*1024
291 func getMachoHdr() *MachoHdr {
295 func newMachoLoad(arch *sys.Arch, type_ uint32, ndata uint32) *MachoLoad {
296 if arch.PtrSize == 8 && (ndata&1 != 0) {
300 load = append(load, MachoLoad{})
301 l := &load[len(load)-1]
303 l.data = make([]uint32, ndata)
307 func newMachoSeg(name string, msect int) *MachoSeg {
308 if nseg >= len(seg) {
309 Exitf("too many segs")
315 s.msect = uint32(msect)
316 s.sect = make([]MachoSect, msect)
320 func newMachoSect(seg *MachoSeg, name string, segname string) *MachoSect {
321 if seg.nsect >= seg.msect {
322 Exitf("too many sects in segment %s", seg.name)
325 s := &seg.sect[seg.nsect]
333 // Generic linking code.
339 func machowrite(ctxt *Link, arch *sys.Arch, out *OutBuf, linkmode LinkMode) int {
342 loadsize := 4 * 4 * ndebug
343 for i := range load {
344 loadsize += 4 * (len(load[i].data) + 2)
346 if arch.PtrSize == 8 {
347 loadsize += 18 * 4 * nseg
348 loadsize += 20 * 4 * nsect
350 loadsize += 14 * 4 * nseg
351 loadsize += 17 * 4 * nsect
354 if arch.PtrSize == 8 {
355 out.Write32(MH_MAGIC_64)
357 out.Write32(MH_MAGIC)
359 out.Write32(machohdr.cpu)
360 out.Write32(machohdr.subcpu)
361 if linkmode == LinkExternal {
362 out.Write32(MH_OBJECT) /* file type - mach object */
364 out.Write32(MH_EXECUTE) /* file type - mach executable */
366 out.Write32(uint32(len(load)) + uint32(nseg) + uint32(ndebug))
367 out.Write32(uint32(loadsize))
369 if nkind[SymKindUndef] == 0 {
372 if ctxt.IsPIE() && linkmode == LinkInternal {
373 flags |= MH_PIE | MH_DYLDLINK
375 out.Write32(flags) /* flags */
376 if arch.PtrSize == 8 {
377 out.Write32(0) /* reserved */
380 for i := 0; i < nseg; i++ {
382 if arch.PtrSize == 8 {
383 out.Write32(LC_SEGMENT_64)
384 out.Write32(72 + 80*s.nsect)
385 out.WriteStringN(s.name, 16)
388 out.Write64(s.fileoffset)
389 out.Write64(s.filesize)
395 out.Write32(LC_SEGMENT)
396 out.Write32(56 + 68*s.nsect)
397 out.WriteStringN(s.name, 16)
398 out.Write32(uint32(s.vaddr))
399 out.Write32(uint32(s.vsize))
400 out.Write32(uint32(s.fileoffset))
401 out.Write32(uint32(s.filesize))
408 for j := uint32(0); j < s.nsect; j++ {
410 if arch.PtrSize == 8 {
411 out.WriteStringN(t.name, 16)
412 out.WriteStringN(t.segname, 16)
418 out.Write32(t.nreloc)
420 out.Write32(t.res1) /* reserved */
421 out.Write32(t.res2) /* reserved */
422 out.Write32(0) /* reserved */
424 out.WriteStringN(t.name, 16)
425 out.WriteStringN(t.segname, 16)
426 out.Write32(uint32(t.addr))
427 out.Write32(uint32(t.size))
431 out.Write32(t.nreloc)
433 out.Write32(t.res1) /* reserved */
434 out.Write32(t.res2) /* reserved */
439 for i := range load {
442 out.Write32(4 * (uint32(len(l.data)) + 2))
443 for j := 0; j < len(l.data); j++ {
444 out.Write32(l.data[j])
448 return int(out.Offset() - o1)
451 func (ctxt *Link) domacho() {
456 // Copy platform load command.
457 for _, h := range hostobj {
458 load, err := hostobjMachoPlatform(&h)
463 machoPlatform = load.platform
464 ml := newMachoLoad(ctxt.Arch, load.cmd.type_, uint32(len(load.cmd.data)))
465 copy(ml.data, load.cmd.data)
469 if machoPlatform == 0 {
470 switch ctxt.Arch.Family {
472 machoPlatform = PLATFORM_MACOS
473 if ctxt.LinkMode == LinkInternal {
474 // For lldb, must say LC_VERSION_MIN_MACOSX or else
475 // it won't know that this Mach-O binary is from OS X
476 // (could be iOS or WatchOS instead).
477 // Go on iOS uses linkmode=external, and linkmode=external
478 // adds this itself. So we only need this code for linkmode=internal
479 // and we can assume OS X.
481 // See golang.org/issues/12941.
483 // The version must be at least 10.9; see golang.org/issues/30488.
484 ml := newMachoLoad(ctxt.Arch, LC_VERSION_MIN_MACOSX, 2)
485 ml.data[0] = 10<<16 | 9<<8 | 0<<0 // OS X version 10.9.0
486 ml.data[1] = 10<<16 | 9<<8 | 0<<0 // SDK 10.9.0
488 case sys.ARM, sys.ARM64:
489 machoPlatform = PLATFORM_IOS
493 // empirically, string table must begin with " \x00".
494 s := ctxt.loader.LookupOrCreateSym(".machosymstr", 0)
495 sb := ctxt.loader.MakeSymbolUpdater(s)
497 sb.SetType(sym.SMACHOSYMSTR)
498 sb.SetReachable(true)
502 s = ctxt.loader.LookupOrCreateSym(".machosymtab", 0)
503 sb = ctxt.loader.MakeSymbolUpdater(s)
504 sb.SetType(sym.SMACHOSYMTAB)
505 sb.SetReachable(true)
507 if ctxt.IsInternal() {
508 s = ctxt.loader.LookupOrCreateSym(".plt", 0) // will be __symbol_stub
509 sb = ctxt.loader.MakeSymbolUpdater(s)
510 sb.SetType(sym.SMACHOPLT)
511 sb.SetReachable(true)
513 s = ctxt.loader.LookupOrCreateSym(".got", 0) // will be __nl_symbol_ptr
514 sb = ctxt.loader.MakeSymbolUpdater(s)
515 sb.SetType(sym.SMACHOGOT)
516 sb.SetReachable(true)
519 s = ctxt.loader.LookupOrCreateSym(".linkedit.plt", 0) // indirect table for .plt
520 sb = ctxt.loader.MakeSymbolUpdater(s)
521 sb.SetType(sym.SMACHOINDIRECTPLT)
522 sb.SetReachable(true)
524 s = ctxt.loader.LookupOrCreateSym(".linkedit.got", 0) // indirect table for .got
525 sb = ctxt.loader.MakeSymbolUpdater(s)
526 sb.SetType(sym.SMACHOINDIRECTGOT)
527 sb.SetReachable(true)
530 // Add a dummy symbol that will become the __asm marker section.
531 if ctxt.IsExternal() {
532 s = ctxt.loader.LookupOrCreateSym(".llvmasm", 0)
533 sb = ctxt.loader.MakeSymbolUpdater(s)
534 sb.SetType(sym.SMACHO)
535 sb.SetReachable(true)
539 // Un-export runtime symbols from plugins. Since the runtime
540 // is included in both the main binary and each plugin, these
541 // symbols appear in both images. If we leave them exported in
542 // the plugin, then the dynamic linker will resolve
543 // relocations to these functions in the plugin's functab to
544 // point to the main image, causing the runtime to think the
545 // plugin's functab is corrupted. By unexporting them, these
546 // become static references, which are resolved to the
549 // It would be better to omit the runtime from plugins. (Using
550 // relative PCs in the functab instead of relocations would
551 // also address this.)
554 if ctxt.BuildMode == BuildModePlugin {
555 for _, name := range []string{"_cgo_topofstack", "__cgo_topofstack", "_cgo_panic", "crosscall2"} {
556 // Most of these are data symbols or C
557 // symbols, so they have symbol version 0.
559 // _cgo_panic is a Go function, so it uses ABIInternal.
560 if name == "_cgo_panic" {
561 ver = sym.ABIToVersion(obj.ABIInternal)
563 s := ctxt.loader.Lookup(name, ver)
565 ctxt.loader.SetAttrCgoExportDynamic(s, false)
571 func machoadddynlib(lib string, linkmode LinkMode) {
572 if seenlib[lib] || linkmode == LinkExternal {
577 // Will need to store the library name rounded up
578 // and 24 bytes of header metadata. If not enough
579 // space, grab another page of initial space at the
580 // beginning of the output file.
581 loadBudget -= (len(lib)+7)/8*8 + 24
585 *FlagTextAddr += 4096
589 dylib = append(dylib, lib)
592 func machoshbits(ctxt *Link, mseg *MachoSeg, sect *sym.Section, segname string) {
593 buf := "__" + strings.Replace(sect.Name[1:], ".", "_", -1)
595 msect := newMachoSect(mseg, buf, segname)
598 msect.reloc = uint32(sect.Reloff)
599 msect.nreloc = uint32(sect.Rellen / 8)
602 for 1<<msect.align < sect.Align {
605 msect.addr = sect.Vaddr
606 msect.size = sect.Length
608 if sect.Vaddr < sect.Seg.Vaddr+sect.Seg.Filelen {
610 if sect.Length > sect.Seg.Vaddr+sect.Seg.Filelen-sect.Vaddr {
611 Errorf(nil, "macho cannot represent section %s crossing data and bss", sect.Name)
613 msect.off = uint32(sect.Seg.Fileoff + sect.Vaddr - sect.Seg.Vaddr)
616 msect.flag |= S_ZEROFILL
620 msect.flag |= S_ATTR_SOME_INSTRUCTIONS
623 if sect.Name == ".text" {
624 msect.flag |= S_ATTR_PURE_INSTRUCTIONS
627 if sect.Name == ".plt" {
628 msect.name = "__symbol_stub1"
629 msect.flag = S_ATTR_PURE_INSTRUCTIONS | S_ATTR_SOME_INSTRUCTIONS | S_SYMBOL_STUBS
630 msect.res1 = 0 //nkind[SymKindLocal];
634 if sect.Name == ".got" {
635 msect.name = "__nl_symbol_ptr"
636 msect.flag = S_NON_LAZY_SYMBOL_POINTERS
637 msect.res1 = uint32(ctxt.loader.SymSize(ctxt.ArchSyms.LinkEditPLT) / 4) /* offset into indirect symbol table */
640 if sect.Name == ".init_array" {
641 msect.name = "__mod_init_func"
642 msect.flag = S_MOD_INIT_FUNC_POINTERS
645 // Some platforms such as watchOS and tvOS require binaries with
646 // bitcode enabled. The Go toolchain can't output bitcode, so use
647 // a marker section in the __LLVM segment, "__asm", to tell the Apple
648 // toolchain that the Go text came from assembler and thus has no
649 // bitcode. This is not true, but Kotlin/Native, Rust and Flutter
650 // are also using this trick.
651 if sect.Name == ".llvmasm" {
653 msect.segname = "__LLVM"
656 if segname == "__DWARF" {
657 msect.flag |= S_ATTR_DEBUG
661 func asmbMacho(ctxt *Link) {
662 machlink := doMachoLink(ctxt)
663 if !*FlagS && ctxt.IsExternal() {
664 symo := int64(Segdwarf.Fileoff + uint64(Rnd(int64(Segdwarf.Filelen), int64(*FlagRound))) + uint64(machlink))
665 ctxt.Out.SeekSet(symo)
673 va := *FlagTextAddr - int64(HEADR)
676 switch ctxt.Arch.Family {
678 Exitf("unknown macho architecture: %v", ctxt.Arch.Family)
681 mh.cpu = MACHO_CPU_AMD64
682 mh.subcpu = MACHO_SUBCPU_X86
685 mh.cpu = MACHO_CPU_ARM64
686 mh.subcpu = MACHO_SUBCPU_ARM64_ALL
690 if ctxt.LinkMode == LinkExternal {
691 /* segment for entire file */
692 ms = newMachoSeg("", 40)
694 ms.fileoffset = Segtext.Fileoff
695 ms.filesize = Segdwarf.Fileoff + Segdwarf.Filelen - Segtext.Fileoff
696 ms.vsize = Segdwarf.Vaddr + Segdwarf.Length - Segtext.Vaddr
699 /* segment for zero page */
700 if ctxt.LinkMode != LinkExternal {
701 ms = newMachoSeg("__PAGEZERO", 0)
702 ms.vsize = uint64(va)
706 v := Rnd(int64(uint64(HEADR)+Segtext.Length), int64(*FlagRound))
708 if ctxt.LinkMode != LinkExternal {
709 ms = newMachoSeg("__TEXT", 20)
710 ms.vaddr = uint64(va)
713 ms.filesize = uint64(v)
718 for _, sect := range Segtext.Sections {
719 machoshbits(ctxt, ms, sect, "__TEXT")
723 if ctxt.LinkMode != LinkExternal && Segrelrodata.Length > 0 {
724 ms = newMachoSeg("__DATA_CONST", 20)
725 ms.vaddr = Segrelrodata.Vaddr
726 ms.vsize = Segrelrodata.Length
727 ms.fileoffset = Segrelrodata.Fileoff
728 ms.filesize = Segrelrodata.Filelen
731 ms.flag = 0x10 // SG_READ_ONLY
734 for _, sect := range Segrelrodata.Sections {
735 machoshbits(ctxt, ms, sect, "__DATA_CONST")
739 if ctxt.LinkMode != LinkExternal {
740 ms = newMachoSeg("__DATA", 20)
741 ms.vaddr = Segdata.Vaddr
742 ms.vsize = Segdata.Length
743 ms.fileoffset = Segdata.Fileoff
744 ms.filesize = Segdata.Filelen
749 for _, sect := range Segdata.Sections {
750 machoshbits(ctxt, ms, sect, "__DATA")
755 if ctxt.LinkMode != LinkExternal {
756 ms = newMachoSeg("__DWARF", 20)
757 ms.vaddr = Segdwarf.Vaddr
759 ms.fileoffset = Segdwarf.Fileoff
760 ms.filesize = Segdwarf.Filelen
762 for _, sect := range Segdwarf.Sections {
763 machoshbits(ctxt, ms, sect, "__DWARF")
767 if ctxt.LinkMode != LinkExternal {
768 switch ctxt.Arch.Family {
770 Exitf("unknown macho architecture: %v", ctxt.Arch.Family)
773 ml := newMachoLoad(ctxt.Arch, LC_UNIXTHREAD, 42+2)
774 ml.data[0] = 4 /* thread type */
775 ml.data[1] = 42 /* word count */
776 ml.data[2+32] = uint32(Entryvalue(ctxt)) /* start pc */
777 ml.data[2+32+1] = uint32(Entryvalue(ctxt) >> 32)
780 ml := newMachoLoad(ctxt.Arch, LC_MAIN, 4)
781 ml.data[0] = uint32(uint64(Entryvalue(ctxt)) - (Segtext.Vaddr - uint64(HEADR)))
782 ml.data[1] = uint32((uint64(Entryvalue(ctxt)) - (Segtext.Vaddr - uint64(HEADR))) >> 32)
788 // must match doMachoLink below
789 s1 := ldr.SymSize(ldr.Lookup(".machorebase", 0))
790 s2 := ldr.SymSize(ldr.Lookup(".machobind", 0))
791 s3 := ldr.SymSize(ldr.Lookup(".machosymtab", 0))
792 s4 := ldr.SymSize(ctxt.ArchSyms.LinkEditPLT)
793 s5 := ldr.SymSize(ctxt.ArchSyms.LinkEditGOT)
794 s6 := ldr.SymSize(ldr.Lookup(".machosymstr", 0))
795 s7 := ldr.SymSize(ldr.Lookup(".machocodesig", 0))
797 if ctxt.LinkMode != LinkExternal {
798 ms := newMachoSeg("__LINKEDIT", 0)
799 ms.vaddr = uint64(Rnd(int64(Segdata.Vaddr+Segdata.Length), int64(*FlagRound)))
800 ms.vsize = uint64(s1 + s2 + s3 + s4 + s5 + s6 + s7)
801 ms.fileoffset = uint64(linkoff)
802 ms.filesize = ms.vsize
806 codesigOff = linkoff + s1 + s2 + s3 + s4 + s5 + s6
809 if ctxt.LinkMode != LinkExternal && ctxt.IsPIE() {
810 ml := newMachoLoad(ctxt.Arch, LC_DYLD_INFO_ONLY, 10)
811 ml.data[0] = uint32(linkoff) // rebase off
812 ml.data[1] = uint32(s1) // rebase size
813 ml.data[2] = uint32(linkoff + s1) // bind off
814 ml.data[3] = uint32(s2) // bind size
815 ml.data[4] = 0 // weak bind off
816 ml.data[5] = 0 // weak bind size
817 ml.data[6] = 0 // lazy bind off
818 ml.data[7] = 0 // lazy bind size
819 ml.data[8] = 0 // export
820 ml.data[9] = 0 // export size
823 ml := newMachoLoad(ctxt.Arch, LC_SYMTAB, 4)
824 ml.data[0] = uint32(linkoff + s1 + s2) /* symoff */
825 ml.data[1] = uint32(nsortsym) /* nsyms */
826 ml.data[2] = uint32(linkoff + s1 + s2 + s3 + s4 + s5) /* stroff */
827 ml.data[3] = uint32(s6) /* strsize */
829 machodysymtab(ctxt, linkoff+s1+s2)
831 if ctxt.LinkMode != LinkExternal {
832 ml := newMachoLoad(ctxt.Arch, LC_LOAD_DYLINKER, 6)
833 ml.data[0] = 12 /* offset to string */
834 stringtouint32(ml.data[1:], "/usr/lib/dyld")
836 for _, lib := range dylib {
837 ml = newMachoLoad(ctxt.Arch, LC_LOAD_DYLIB, 4+(uint32(len(lib))+1+7)/8*2)
838 ml.data[0] = 24 /* offset of string from beginning of load */
839 ml.data[1] = 0 /* time stamp */
840 ml.data[2] = 0 /* version */
841 ml.data[3] = 0 /* compatibility version */
842 stringtouint32(ml.data[4:], lib)
846 if ctxt.IsInternal() && ctxt.NeedCodeSign() {
847 ml := newMachoLoad(ctxt.Arch, LC_CODE_SIGNATURE, 2)
848 ml.data[0] = uint32(codesigOff)
849 ml.data[1] = uint32(s7)
853 a := machowrite(ctxt, ctxt.Arch, ctxt.Out, ctxt.LinkMode)
854 if int32(a) > HEADR {
855 Exitf("HEADR too small: %d > %d", a, HEADR)
858 // Now we have written everything. Compute the code signature (which
859 // is a hash of the file content, so it must be done at last.)
860 if ctxt.IsInternal() && ctxt.NeedCodeSign() {
861 cs := ldr.Lookup(".machocodesig", 0)
862 data := ctxt.Out.Data()
863 if int64(len(data)) != codesigOff {
866 codesign.Sign(ldr.Data(cs), bytes.NewReader(data), "a.out", codesigOff, int64(Segtext.Fileoff), int64(Segtext.Filelen), ctxt.IsExe() || ctxt.IsPIE())
867 ctxt.Out.SeekSet(codesigOff)
868 ctxt.Out.Write(ldr.Data(cs))
872 func symkind(ldr *loader.Loader, s loader.Sym) int {
873 if ldr.SymType(s) == sym.SDYNIMPORT {
876 if ldr.AttrCgoExport(s) {
882 func collectmachosyms(ctxt *Link) {
885 addsym := func(s loader.Sym) {
886 sortsym = append(sortsym, s)
887 nkind[symkind(ldr, s)]++
890 // Add special runtime.text and runtime.etext symbols.
891 // We've already included this symbol in Textp on darwin if ctxt.DynlinkingGo().
892 // See data.go:/textaddress
893 if !ctxt.DynlinkingGo() {
894 s := ldr.Lookup("runtime.text", 0)
895 if ldr.SymType(s) == sym.STEXT {
898 s = ldr.Lookup("runtime.etext", 0)
899 if ldr.SymType(s) == sym.STEXT {
905 for _, s := range ctxt.Textp {
909 shouldBeInSymbolTable := func(s loader.Sym) bool {
910 if ldr.AttrNotInSymbolTable(s) {
913 name := ldr.RawSymName(s) // TODO: try not to read the name
914 if name == "" || name[0] == '.' {
920 // Add data symbols and external references.
921 for s := loader.Sym(1); s < loader.Sym(ldr.NSym()); s++ {
922 if !ldr.AttrReachable(s) {
926 if t >= sym.SELFRXSECT && t < sym.SXREF { // data sections handled in dodata
927 if t == sym.STLSBSS {
928 // TLSBSS is not used on darwin. See data.go:allocateDataSections
931 if !shouldBeInSymbolTable(s) {
938 case sym.SDYNIMPORT, sym.SHOSTOBJ, sym.SUNDEFEXT:
942 // Some 64-bit functions have a "$INODE64" or "$INODE64$UNIX2003" suffix.
943 if t == sym.SDYNIMPORT && ldr.SymDynimplib(s) == "/usr/lib/libSystem.B.dylib" {
944 // But only on macOS.
945 if machoPlatform == PLATFORM_MACOS {
946 switch n := ldr.SymExtname(s); n {
948 switch objabi.GOARCH {
950 ldr.SetSymExtname(s, n+"$INODE64")
952 case "readdir_r", "getfsstat":
953 switch objabi.GOARCH {
955 ldr.SetSymExtname(s, n+"$INODE64")
962 nsortsym = len(sortsym)
965 func machosymorder(ctxt *Link) {
968 // On Mac OS X Mountain Lion, we must sort exported symbols
969 // So we sort them here and pre-allocate dynid for them
970 // See https://golang.org/issue/4029
971 for _, s := range ctxt.dynexp {
972 if !ldr.AttrReachable(s) {
973 panic("dynexp symbol is not reachable")
976 collectmachosyms(ctxt)
977 sort.Slice(sortsym[:nsortsym], func(i, j int) bool {
980 k1 := symkind(ldr, s1)
981 k2 := symkind(ldr, s2)
985 return ldr.SymExtname(s1) < ldr.SymExtname(s2) // Note: unnamed symbols are not added in collectmachosyms
987 for i, s := range sortsym {
988 ldr.SetSymDynid(s, int32(i))
992 // AddMachoSym adds s to Mach-O symbol table, used in GenSymLate.
993 // Currently only used on ARM64 when external linking.
994 func AddMachoSym(ldr *loader.Loader, s loader.Sym) {
995 ldr.SetSymDynid(s, int32(nsortsym))
996 sortsym = append(sortsym, s)
998 nkind[symkind(ldr, s)]++
1001 // machoShouldExport reports whether a symbol needs to be exported.
1003 // When dynamically linking, all non-local variables and plugin-exported
1004 // symbols need to be exported.
1005 func machoShouldExport(ctxt *Link, ldr *loader.Loader, s loader.Sym) bool {
1006 if !ctxt.DynlinkingGo() || ldr.AttrLocal(s) {
1009 if ctxt.BuildMode == BuildModePlugin && strings.HasPrefix(ldr.SymExtname(s), objabi.PathToPrefix(*flagPluginPath)) {
1012 name := ldr.RawSymName(s)
1013 if strings.HasPrefix(name, "go.itab.") {
1016 if strings.HasPrefix(name, "type.") && !strings.HasPrefix(name, "type..") {
1017 // reduce runtime typemap pressure, but do not
1018 // export alg functions (type..*), as these
1019 // appear in pclntable.
1022 if strings.HasPrefix(name, "go.link.pkghash") {
1025 return ldr.SymType(s) >= sym.SFirstWritable // only writable sections
1028 func machosymtab(ctxt *Link) {
1030 symtab := ldr.CreateSymForUpdate(".machosymtab", 0)
1031 symstr := ldr.CreateSymForUpdate(".machosymstr", 0)
1033 for _, s := range sortsym[:nsortsym] {
1034 symtab.AddUint32(ctxt.Arch, uint32(symstr.Size()))
1036 export := machoShouldExport(ctxt, ldr, s)
1038 // Prefix symbol names with "_" to match the system toolchain.
1039 // (We used to only prefix C symbols, which is all required for the build.
1040 // But some tools don't recognize Go symbols as symbols, so we prefix them
1042 symstr.AddUint8('_')
1044 // replace "·" as ".", because DTrace cannot handle it.
1045 name := strings.Replace(ldr.SymExtname(s), "·", ".", -1)
1047 name = mangleABIName(ldr, s, name)
1048 symstr.Addstring(name)
1050 if t := ldr.SymType(s); t == sym.SDYNIMPORT || t == sym.SHOSTOBJ || t == sym.SUNDEFEXT {
1051 symtab.AddUint8(0x01) // type N_EXT, external symbol
1052 symtab.AddUint8(0) // no section
1053 symtab.AddUint16(ctxt.Arch, 0) // desc
1054 symtab.AddUintXX(ctxt.Arch, 0, ctxt.Arch.PtrSize) // no value
1056 if export || ldr.AttrCgoExportDynamic(s) {
1057 symtab.AddUint8(0x0f) // N_SECT | N_EXT
1058 } else if ldr.AttrCgoExportStatic(s) {
1059 // Only export statically, not dynamically. (N_PEXT is like hidden visibility)
1060 symtab.AddUint8(0x1f) // N_SECT | N_EXT | N_PEXT
1062 symtab.AddUint8(0x0e) // N_SECT
1065 if outer := ldr.OuterSym(o); outer != 0 {
1068 if ldr.SymSect(o) == nil {
1069 ldr.Errorf(s, "missing section for symbol")
1072 symtab.AddUint8(uint8(ldr.SymSect(o).Extnum))
1074 symtab.AddUint16(ctxt.Arch, 0) // desc
1075 symtab.AddUintXX(ctxt.Arch, uint64(ldr.SymAddr(s)), ctxt.Arch.PtrSize)
1080 func machodysymtab(ctxt *Link, base int64) {
1081 ml := newMachoLoad(ctxt.Arch, LC_DYSYMTAB, 18)
1084 ml.data[0] = uint32(n) /* ilocalsym */
1085 ml.data[1] = uint32(nkind[SymKindLocal]) /* nlocalsym */
1086 n += nkind[SymKindLocal]
1088 ml.data[2] = uint32(n) /* iextdefsym */
1089 ml.data[3] = uint32(nkind[SymKindExtdef]) /* nextdefsym */
1090 n += nkind[SymKindExtdef]
1092 ml.data[4] = uint32(n) /* iundefsym */
1093 ml.data[5] = uint32(nkind[SymKindUndef]) /* nundefsym */
1095 ml.data[6] = 0 /* tocoffset */
1096 ml.data[7] = 0 /* ntoc */
1097 ml.data[8] = 0 /* modtaboff */
1098 ml.data[9] = 0 /* nmodtab */
1099 ml.data[10] = 0 /* extrefsymoff */
1100 ml.data[11] = 0 /* nextrefsyms */
1104 // must match domacholink below
1105 s1 := ldr.SymSize(ldr.Lookup(".machosymtab", 0))
1106 s2 := ldr.SymSize(ctxt.ArchSyms.LinkEditPLT)
1107 s3 := ldr.SymSize(ctxt.ArchSyms.LinkEditGOT)
1108 ml.data[12] = uint32(base + s1) /* indirectsymoff */
1109 ml.data[13] = uint32((s2 + s3) / 4) /* nindirectsyms */
1111 ml.data[14] = 0 /* extreloff */
1112 ml.data[15] = 0 /* nextrel */
1113 ml.data[16] = 0 /* locreloff */
1114 ml.data[17] = 0 /* nlocrel */
1117 func doMachoLink(ctxt *Link) int64 {
1123 // write data that will be linkedit section
1124 s1 := ldr.Lookup(".machorebase", 0)
1125 s2 := ldr.Lookup(".machobind", 0)
1126 s3 := ldr.Lookup(".machosymtab", 0)
1127 s4 := ctxt.ArchSyms.LinkEditPLT
1128 s5 := ctxt.ArchSyms.LinkEditGOT
1129 s6 := ldr.Lookup(".machosymstr", 0)
1131 size := ldr.SymSize(s1) + ldr.SymSize(s2) + ldr.SymSize(s3) + ldr.SymSize(s4) + ldr.SymSize(s5) + ldr.SymSize(s6)
1133 // Force the linkedit section to end on a 16-byte
1134 // boundary. This allows pure (non-cgo) Go binaries
1135 // to be code signed correctly.
1137 // Apple's codesign_allocate (a helper utility for
1138 // the codesign utility) can do this fine itself if
1139 // it is run on a dynamic Mach-O binary. However,
1140 // when it is run on a pure (non-cgo) Go binary, where
1141 // the linkedit section is mostly empty, it fails to
1142 // account for the extra padding that it itself adds
1143 // when adding the LC_CODE_SIGNATURE load command
1144 // (which must be aligned on a 16-byte boundary).
1146 // By forcing the linkedit section to end on a 16-byte
1147 // boundary, codesign_allocate will not need to apply
1148 // any alignment padding itself, working around the
1152 s6b := ldr.MakeSymbolUpdater(s6)
1153 s6b.Grow(s6b.Size() + n)
1154 s6b.SetSize(s6b.Size() + n)
1159 linkoff = Rnd(int64(uint64(HEADR)+Segtext.Length), int64(*FlagRound)) + Rnd(int64(Segrelrodata.Filelen), int64(*FlagRound)) + Rnd(int64(Segdata.Filelen), int64(*FlagRound)) + Rnd(int64(Segdwarf.Filelen), int64(*FlagRound))
1160 ctxt.Out.SeekSet(linkoff)
1162 ctxt.Out.Write(ldr.Data(s1))
1163 ctxt.Out.Write(ldr.Data(s2))
1164 ctxt.Out.Write(ldr.Data(s3))
1165 ctxt.Out.Write(ldr.Data(s4))
1166 ctxt.Out.Write(ldr.Data(s5))
1167 ctxt.Out.Write(ldr.Data(s6))
1169 // Add code signature if necessary. This must be the last.
1170 s7 := machoCodeSigSym(ctxt, linkoff+size)
1171 size += ldr.SymSize(s7)
1174 return Rnd(size, int64(*FlagRound))
1177 func machorelocsect(ctxt *Link, out *OutBuf, sect *sym.Section, syms []loader.Sym) {
1178 // If main section has no bits, nothing to relocate.
1179 if sect.Vaddr >= sect.Seg.Vaddr+sect.Seg.Filelen {
1184 for i, s := range syms {
1185 if !ldr.AttrReachable(s) {
1188 if uint64(ldr.SymValue(s)) >= sect.Vaddr {
1194 eaddr := int32(sect.Vaddr + sect.Length)
1195 for _, s := range syms {
1196 if !ldr.AttrReachable(s) {
1199 if ldr.SymValue(s) >= int64(eaddr) {
1203 // Compute external relocations on the go, and pass to Machoreloc1
1205 relocs := ldr.Relocs(s)
1206 for ri := 0; ri < relocs.Count(); ri++ {
1208 rr, ok := extreloc(ctxt, ldr, s, r)
1213 ldr.Errorf(s, "missing xsym in relocation")
1216 if !ldr.AttrReachable(rr.Xsym) {
1217 ldr.Errorf(s, "unreachable reloc %d (%s) target %v", r.Type(), sym.RelocName(ctxt.Arch, r.Type()), ldr.SymName(rr.Xsym))
1219 if !thearch.Machoreloc1(ctxt.Arch, out, ldr, s, rr, int64(uint64(ldr.SymValue(s)+int64(r.Off()))-sect.Vaddr)) {
1220 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()))
1226 if uint64(out.Offset()) != sect.Reloff+sect.Rellen {
1227 panic("machorelocsect: size mismatch")
1231 func machoEmitReloc(ctxt *Link) {
1232 for ctxt.Out.Offset()&7 != 0 {
1236 sizeExtRelocs(ctxt, thearch.MachorelocSize)
1237 relocSect, wg := relocSectFn(ctxt, machorelocsect)
1239 relocSect(ctxt, Segtext.Sections[0], ctxt.Textp)
1240 for _, sect := range Segtext.Sections[1:] {
1241 relocSect(ctxt, sect, ctxt.datap)
1243 for _, sect := range Segrelrodata.Sections {
1244 relocSect(ctxt, sect, ctxt.datap)
1246 for _, sect := range Segdata.Sections {
1247 relocSect(ctxt, sect, ctxt.datap)
1249 for i := 0; i < len(Segdwarf.Sections); i++ {
1250 sect := Segdwarf.Sections[i]
1252 if si.secSym() != loader.Sym(sect.Sym) ||
1253 ctxt.loader.SymSect(si.secSym()) != sect {
1254 panic("inconsistency between dwarfp and Segdwarf")
1256 relocSect(ctxt, sect, si.syms)
1261 // hostobjMachoPlatform returns the first platform load command found
1262 // in the host object, if any.
1263 func hostobjMachoPlatform(h *Hostobj) (*MachoPlatformLoad, error) {
1264 f, err := os.Open(h.file)
1266 return nil, fmt.Errorf("%s: failed to open host object: %v\n", h.file, err)
1269 sr := io.NewSectionReader(f, h.off, h.length)
1270 m, err := macho.NewFile(sr)
1272 // Not a valid Mach-O file.
1275 return peekMachoPlatform(m)
1278 // peekMachoPlatform returns the first LC_VERSION_MIN_* or LC_BUILD_VERSION
1279 // load command found in the Mach-O file, if any.
1280 func peekMachoPlatform(m *macho.File) (*MachoPlatformLoad, error) {
1281 for _, cmd := range m.Loads {
1284 type_: m.ByteOrder.Uint32(raw),
1286 // Skip the type and command length.
1290 case LC_VERSION_MIN_IPHONEOS:
1292 case LC_VERSION_MIN_MACOSX:
1294 case LC_VERSION_MIN_WATCHOS:
1295 p = PLATFORM_WATCHOS
1296 case LC_VERSION_MIN_TVOS:
1298 case LC_BUILD_VERSION:
1299 p = MachoPlatform(m.ByteOrder.Uint32(data))
1303 ml.data = make([]uint32, len(data)/4)
1304 r := bytes.NewReader(data)
1305 if err := binary.Read(r, m.ByteOrder, &ml.data); err != nil {
1308 return &MachoPlatformLoad{
1316 // A rebase entry tells the dynamic linker the data at sym+off needs to be
1317 // relocated when the in-memory image moves. (This is somewhat like, say,
1318 // ELF R_X86_64_RELATIVE).
1319 // For now, the only kind of entry we support is that the data is an absolute
1320 // address. That seems all we need.
1321 // In the binary it uses a compact stateful bytecode encoding. So we record
1322 // entries as we go and build the table at the end.
1323 type machoRebaseRecord struct {
1328 var machorebase []machoRebaseRecord
1330 func MachoAddRebase(s loader.Sym, off int64) {
1331 machorebase = append(machorebase, machoRebaseRecord{s, off})
1334 // A bind entry tells the dynamic linker the data at GOT+off should be bound
1335 // to the address of the target symbol, which is a dynamic import.
1336 // For now, the only kind of entry we support is that the data is an absolute
1337 // address, and the source symbol is always the GOT. That seems all we need.
1338 // In the binary it uses a compact stateful bytecode encoding. So we record
1339 // entries as we go and build the table at the end.
1340 type machoBindRecord struct {
1345 var machobind []machoBindRecord
1347 func MachoAddBind(off int64, targ loader.Sym) {
1348 machobind = append(machobind, machoBindRecord{off, targ})
1351 // Generate data for the dynamic linker, used in LC_DYLD_INFO_ONLY load command.
1352 // See mach-o/loader.h, struct dyld_info_command, for the encoding.
1353 // e.g. https://opensource.apple.com/source/xnu/xnu-6153.81.5/EXTERNAL_HEADERS/mach-o/loader.h
1354 func machoDyldInfo(ctxt *Link) {
1356 rebase := ldr.CreateSymForUpdate(".machorebase", 0)
1357 bind := ldr.CreateSymForUpdate(".machobind", 0)
1359 if !(ctxt.IsPIE() && ctxt.IsInternal()) {
1363 segId := func(seg *sym.Segment) uint8 {
1370 if Segrelrodata.Length > 0 {
1375 panic("unknown segment")
1378 dylibId := func(s loader.Sym) int {
1379 slib := ldr.SymDynimplib(s)
1380 for i, lib := range dylib {
1385 return BIND_SPECIAL_DYLIB_FLAT_LOOKUP // don't know where it is from
1389 // TODO: use more compact encoding. The encoding is stateful, and
1390 // we can use delta encoding.
1391 rebase.AddUint8(REBASE_OPCODE_SET_TYPE_IMM | REBASE_TYPE_POINTER)
1392 for _, r := range machorebase {
1393 seg := ldr.SymSect(r.sym).Seg
1394 off := uint64(ldr.SymValue(r.sym)+r.off) - seg.Vaddr
1395 rebase.AddUint8(REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | segId(seg))
1398 rebase.AddUint8(REBASE_OPCODE_DO_REBASE_IMM_TIMES | 1)
1400 rebase.AddUint8(REBASE_OPCODE_DONE)
1401 sz := Rnd(rebase.Size(), 8)
1406 // TODO: compact encoding, as above.
1407 // TODO: lazy binding?
1409 seg := ldr.SymSect(got).Seg
1410 gotAddr := ldr.SymValue(got)
1411 bind.AddUint8(BIND_OPCODE_SET_TYPE_IMM | BIND_TYPE_POINTER)
1412 for _, r := range machobind {
1413 off := uint64(gotAddr+r.off) - seg.Vaddr
1414 bind.AddUint8(BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | segId(seg))
1417 d := dylibId(r.targ)
1418 if d > 0 && d < 128 {
1419 bind.AddUint8(BIND_OPCODE_SET_DYLIB_ORDINAL_IMM | uint8(d)&0xf)
1420 } else if d >= 128 {
1421 bind.AddUint8(BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB)
1422 bind.AddUleb(uint64(d))
1424 bind.AddUint8(BIND_OPCODE_SET_DYLIB_SPECIAL_IMM | uint8(d)&0xf)
1427 bind.AddUint8(BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM)
1428 // target symbol name as a C string, with _ prefix
1430 bind.Addstring(ldr.SymExtname(r.targ))
1432 bind.AddUint8(BIND_OPCODE_DO_BIND)
1434 bind.AddUint8(BIND_OPCODE_DONE)
1435 sz = Rnd(bind.Size(), 16) // make it 16-byte aligned, see the comment in doMachoLink
1439 // TODO: export table.
1440 // The symbols names are encoded as a trie. I'm really too lazy to do that
1442 // Without it, the symbols are not dynamically exported, so they cannot be
1443 // e.g. dlsym'd. But internal linking is not the default in that case, so
1447 // machoCodeSigSym creates and returns a symbol for code signature.
1448 // The symbol context is left as zeros, which will be generated at the end
1449 // (as it depends on the rest of the file).
1450 func machoCodeSigSym(ctxt *Link, codeSize int64) loader.Sym {
1452 cs := ldr.CreateSymForUpdate(".machocodesig", 0)
1453 if !ctxt.NeedCodeSign() || ctxt.IsExternal() {
1456 sz := codesign.Size(codeSize, "a.out")
1462 // machoCodeSign code-signs Mach-O file fname with an ad-hoc signature.
1463 // This is used for updating an external linker generated binary.
1464 func machoCodeSign(ctxt *Link, fname string) error {
1465 f, err := os.OpenFile(fname, os.O_RDWR, 0)
1471 mf, err := macho.NewFile(f)
1475 if mf.Magic != macho.Magic64 {
1476 Exitf("not 64-bit Mach-O file: %s", fname)
1479 // Find existing LC_CODE_SIGNATURE and __LINKEDIT segment
1480 var sigOff, sigSz, csCmdOff, linkeditOff int64
1481 var linkeditSeg, textSeg *macho.Segment
1482 loadOff := int64(machoHeaderSize64)
1483 get32 := mf.ByteOrder.Uint32
1484 for _, l := range mf.Loads {
1486 cmd, sz := get32(data), get32(data[4:])
1487 if cmd == LC_CODE_SIGNATURE {
1488 sigOff = int64(get32(data[8:]))
1489 sigSz = int64(get32(data[12:]))
1492 if seg, ok := l.(*macho.Segment); ok {
1496 linkeditOff = loadOff
1501 loadOff += int64(sz)
1505 // The C linker doesn't generate a signed binary, for some reason.
1514 if sigOff+sigSz != fi.Size() {
1515 // We don't expect anything after the signature (this will invalidate
1516 // the signature anyway.)
1517 return fmt.Errorf("unexpected content after code signature")
1520 sz := codesign.Size(sigOff, "a.out")
1522 // Update the load command,
1524 mf.ByteOrder.PutUint32(tmp[:4], uint32(sz))
1525 _, err = f.WriteAt(tmp[:4], csCmdOff+12)
1530 // Uodate the __LINKEDIT segment.
1531 segSz := sigOff + sz - int64(linkeditSeg.Offset)
1532 mf.ByteOrder.PutUint64(tmp[:8], uint64(segSz))
1533 _, err = f.WriteAt(tmp[:8], int64(linkeditOff)+int64(unsafe.Offsetof(macho.Segment64{}.Memsz)))
1537 _, err = f.WriteAt(tmp[:8], int64(linkeditOff)+int64(unsafe.Offsetof(macho.Segment64{}.Filesz)))
1543 cs := make([]byte, sz)
1544 codesign.Sign(cs, f, "a.out", sigOff, int64(textSeg.Offset), int64(textSeg.Filesz), ctxt.IsExe() || ctxt.IsPIE())
1545 _, err = f.WriteAt(cs, sigOff)
1549 err = f.Truncate(sigOff + sz)