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"
12 "cmd/link/internal/loader"
13 "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
90 MACHO_SUBCPU_ARM64_V8 = 1
91 MACHO_SUBCPU_ARM64E = 2
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
119 MH_MAGIC = 0xfeedface
120 MH_MAGIC_64 = 0xfeedfacf
144 LC_LOAD_DYLINKER = 0xe
146 LC_PREBOUND_DYLIB = 0x10
148 LC_SUB_FRAMEWORK = 0x12
149 LC_SUB_UMBRELLA = 0x13
151 LC_SUB_LIBRARY = 0x15
152 LC_TWOLEVEL_HINTS = 0x16
153 LC_PREBIND_CKSUM = 0x17
154 LC_LOAD_WEAK_DYLIB = 0x80000018
156 LC_ROUTINES_64 = 0x1a
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
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
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
189 S_NON_LAZY_SYMBOL_POINTERS = 0x6
191 S_MOD_INIT_FUNC_POINTERS = 0x9
192 S_ATTR_PURE_INSTRUCTIONS = 0x80000000
193 S_ATTR_DEBUG = 0x02000000
194 S_ATTR_SOME_INSTRUCTIONS = 0x00000400
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
205 // rebase table opcode
207 REBASE_TYPE_POINTER = 1
208 REBASE_TYPE_TEXT_ABSOLUTE32 = 2
209 REBASE_TYPE_TEXT_PCREL32 = 3
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
226 BIND_TYPE_POINTER = 1
227 BIND_TYPE_TEXT_ABSOLUTE32 = 2
228 BIND_TYPE_TEXT_PCREL32 = 3
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
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
255 const machoHeaderSize64 = 8 * 4 // size of 64-bit Mach-O header
257 // Mach-O file writing
258 // https://developer.apple.com/mac/library/DOCUMENTATION/DeveloperTools/Conceptual/MachORuntime/Reference/reference.html
260 var machohdr MachoHdr
264 var machoPlatform MachoPlatform
275 SymKindLocal = 0 + iota
281 var nkind [NumSymKind]int
283 var sortsym []loader.Sym
287 // Amount of space left for adding load commands
288 // that refer to dynamic libraries. Because these have
289 // to go in the Mach-O header, we can't just pick a
290 // "big enough" header size. The initial header is
291 // one page, the non-dynamic library stuff takes
292 // up about 1300 bytes; we overestimate that as 2k.
293 var loadBudget = INITIAL_MACHO_HEADR - 2*1024
295 func getMachoHdr() *MachoHdr {
299 func newMachoLoad(arch *sys.Arch, type_ uint32, ndata uint32) *MachoLoad {
300 if arch.PtrSize == 8 && (ndata&1 != 0) {
304 load = append(load, MachoLoad{})
305 l := &load[len(load)-1]
307 l.data = make([]uint32, ndata)
311 func newMachoSeg(name string, msect int) *MachoSeg {
312 if nseg >= len(seg) {
313 Exitf("too many segs")
319 s.msect = uint32(msect)
320 s.sect = make([]MachoSect, msect)
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)
329 s := &seg.sect[seg.nsect]
337 // Generic linking code.
343 func machowrite(ctxt *Link, arch *sys.Arch, out *OutBuf, linkmode LinkMode) int {
346 loadsize := 4 * 4 * ndebug
347 for i := range load {
348 loadsize += 4 * (len(load[i].data) + 2)
350 if arch.PtrSize == 8 {
351 loadsize += 18 * 4 * nseg
352 loadsize += 20 * 4 * nsect
354 loadsize += 14 * 4 * nseg
355 loadsize += 17 * 4 * nsect
358 if arch.PtrSize == 8 {
359 out.Write32(MH_MAGIC_64)
361 out.Write32(MH_MAGIC)
363 out.Write32(machohdr.cpu)
364 out.Write32(machohdr.subcpu)
365 if linkmode == LinkExternal {
366 out.Write32(MH_OBJECT) /* file type - mach object */
368 out.Write32(MH_EXECUTE) /* file type - mach executable */
370 out.Write32(uint32(len(load)) + uint32(nseg) + uint32(ndebug))
371 out.Write32(uint32(loadsize))
373 if nkind[SymKindUndef] == 0 {
376 if ctxt.IsPIE() && linkmode == LinkInternal {
377 flags |= MH_PIE | MH_DYLDLINK
379 out.Write32(flags) /* flags */
380 if arch.PtrSize == 8 {
381 out.Write32(0) /* reserved */
384 for i := 0; i < nseg; 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)
392 out.Write64(s.fileoffset)
393 out.Write64(s.filesize)
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))
412 for j := uint32(0); j < s.nsect; j++ {
414 if arch.PtrSize == 8 {
415 out.WriteStringN(t.name, 16)
416 out.WriteStringN(t.segname, 16)
422 out.Write32(t.nreloc)
424 out.Write32(t.res1) /* reserved */
425 out.Write32(t.res2) /* reserved */
426 out.Write32(0) /* reserved */
428 out.WriteStringN(t.name, 16)
429 out.WriteStringN(t.segname, 16)
430 out.Write32(uint32(t.addr))
431 out.Write32(uint32(t.size))
435 out.Write32(t.nreloc)
437 out.Write32(t.res1) /* reserved */
438 out.Write32(t.res2) /* reserved */
443 for i := range load {
446 out.Write32(4 * (uint32(len(l.data)) + 2))
447 for j := 0; j < len(l.data); j++ {
448 out.Write32(l.data[j])
452 return int(out.Offset() - o1)
455 func (ctxt *Link) domacho() {
460 // Copy platform load command.
461 for _, h := range hostobj {
462 load, err := hostobjMachoPlatform(&h)
467 machoPlatform = load.platform
468 ml := newMachoLoad(ctxt.Arch, load.cmd.type_, uint32(len(load.cmd.data)))
469 copy(ml.data, load.cmd.data)
473 if machoPlatform == 0 {
474 machoPlatform = PLATFORM_MACOS
475 if buildcfg.GOOS == "ios" {
476 machoPlatform = PLATFORM_IOS
478 if ctxt.LinkMode == LinkInternal && machoPlatform == PLATFORM_MACOS {
480 switch ctxt.Arch.Family {
482 // The version must be at least 10.9; see golang.org/issues/30488.
483 version = 10<<16 | 9<<8 | 0<<0 // 10.9.0
485 version = 11<<16 | 0<<8 | 0<<0 // 11.0.0
487 ml := newMachoLoad(ctxt.Arch, LC_BUILD_VERSION, 4)
488 ml.data[0] = uint32(machoPlatform)
489 ml.data[1] = version // OS version
490 ml.data[2] = version // SDK version
491 ml.data[3] = 0 // ntools
495 // empirically, string table must begin with " \x00".
496 s := ctxt.loader.LookupOrCreateSym(".machosymstr", 0)
497 sb := ctxt.loader.MakeSymbolUpdater(s)
499 sb.SetType(sym.SMACHOSYMSTR)
500 sb.SetReachable(true)
504 s = ctxt.loader.LookupOrCreateSym(".machosymtab", 0)
505 sb = ctxt.loader.MakeSymbolUpdater(s)
506 sb.SetType(sym.SMACHOSYMTAB)
507 sb.SetReachable(true)
509 if ctxt.IsInternal() {
510 s = ctxt.loader.LookupOrCreateSym(".plt", 0) // will be __symbol_stub
511 sb = ctxt.loader.MakeSymbolUpdater(s)
512 sb.SetType(sym.SMACHOPLT)
513 sb.SetReachable(true)
515 s = ctxt.loader.LookupOrCreateSym(".got", 0) // will be __nl_symbol_ptr
516 sb = ctxt.loader.MakeSymbolUpdater(s)
517 sb.SetType(sym.SMACHOGOT)
518 sb.SetReachable(true)
521 s = ctxt.loader.LookupOrCreateSym(".linkedit.plt", 0) // indirect table for .plt
522 sb = ctxt.loader.MakeSymbolUpdater(s)
523 sb.SetType(sym.SMACHOINDIRECTPLT)
524 sb.SetReachable(true)
526 s = ctxt.loader.LookupOrCreateSym(".linkedit.got", 0) // indirect table for .got
527 sb = ctxt.loader.MakeSymbolUpdater(s)
528 sb.SetType(sym.SMACHOINDIRECTGOT)
529 sb.SetReachable(true)
532 // Add a dummy symbol that will become the __asm marker section.
533 if ctxt.IsExternal() {
534 s = ctxt.loader.LookupOrCreateSym(".llvmasm", 0)
535 sb = ctxt.loader.MakeSymbolUpdater(s)
536 sb.SetType(sym.SMACHO)
537 sb.SetReachable(true)
541 // Un-export runtime symbols from plugins. Since the runtime
542 // is included in both the main binary and each plugin, these
543 // symbols appear in both images. If we leave them exported in
544 // the plugin, then the dynamic linker will resolve
545 // relocations to these functions in the plugin's functab to
546 // point to the main image, causing the runtime to think the
547 // plugin's functab is corrupted. By unexporting them, these
548 // become static references, which are resolved to the
551 // It would be better to omit the runtime from plugins. (Using
552 // relative PCs in the functab instead of relocations would
553 // also address this.)
556 if ctxt.BuildMode == BuildModePlugin {
557 for _, name := range []string{"_cgo_topofstack", "__cgo_topofstack", "_cgo_panic", "crosscall2"} {
558 // Most of these are data symbols or C
559 // symbols, so they have symbol version 0.
561 // _cgo_panic is a Go function, so it uses ABIInternal.
562 if name == "_cgo_panic" {
565 s := ctxt.loader.Lookup(name, ver)
567 ctxt.loader.SetAttrCgoExportDynamic(s, false)
573 func machoadddynlib(lib string, linkmode LinkMode) {
574 if seenlib[lib] || linkmode == LinkExternal {
579 // Will need to store the library name rounded up
580 // and 24 bytes of header metadata. If not enough
581 // space, grab another page of initial space at the
582 // beginning of the output file.
583 loadBudget -= (len(lib)+7)/8*8 + 24
587 *FlagTextAddr += 4096
591 dylib = append(dylib, lib)
594 func machoshbits(ctxt *Link, mseg *MachoSeg, sect *sym.Section, segname string) {
595 buf := "__" + strings.Replace(sect.Name[1:], ".", "_", -1)
597 msect := newMachoSect(mseg, buf, segname)
600 msect.reloc = uint32(sect.Reloff)
601 msect.nreloc = uint32(sect.Rellen / 8)
604 for 1<<msect.align < sect.Align {
607 msect.addr = sect.Vaddr
608 msect.size = sect.Length
610 if sect.Vaddr < sect.Seg.Vaddr+sect.Seg.Filelen {
612 if sect.Length > sect.Seg.Vaddr+sect.Seg.Filelen-sect.Vaddr {
613 Errorf(nil, "macho cannot represent section %s crossing data and bss", sect.Name)
615 msect.off = uint32(sect.Seg.Fileoff + sect.Vaddr - sect.Seg.Vaddr)
618 msect.flag |= S_ZEROFILL
622 msect.flag |= S_ATTR_SOME_INSTRUCTIONS
625 if sect.Name == ".text" {
626 msect.flag |= S_ATTR_PURE_INSTRUCTIONS
629 if sect.Name == ".plt" {
630 msect.name = "__symbol_stub1"
631 msect.flag = S_ATTR_PURE_INSTRUCTIONS | S_ATTR_SOME_INSTRUCTIONS | S_SYMBOL_STUBS
632 msect.res1 = 0 //nkind[SymKindLocal];
636 if sect.Name == ".got" {
637 msect.name = "__nl_symbol_ptr"
638 msect.flag = S_NON_LAZY_SYMBOL_POINTERS
639 msect.res1 = uint32(ctxt.loader.SymSize(ctxt.ArchSyms.LinkEditPLT) / 4) /* offset into indirect symbol table */
642 if sect.Name == ".init_array" {
643 msect.name = "__mod_init_func"
644 msect.flag = S_MOD_INIT_FUNC_POINTERS
647 // Some platforms such as watchOS and tvOS require binaries with
648 // bitcode enabled. The Go toolchain can't output bitcode, so use
649 // a marker section in the __LLVM segment, "__asm", to tell the Apple
650 // toolchain that the Go text came from assembler and thus has no
651 // bitcode. This is not true, but Kotlin/Native, Rust and Flutter
652 // are also using this trick.
653 if sect.Name == ".llvmasm" {
655 msect.segname = "__LLVM"
658 if segname == "__DWARF" {
659 msect.flag |= S_ATTR_DEBUG
663 func asmbMacho(ctxt *Link) {
664 machlink := doMachoLink(ctxt)
665 if !*FlagS && ctxt.IsExternal() {
666 symo := int64(Segdwarf.Fileoff + uint64(Rnd(int64(Segdwarf.Filelen), int64(*FlagRound))) + uint64(machlink))
667 ctxt.Out.SeekSet(symo)
675 va := *FlagTextAddr - int64(HEADR)
678 switch ctxt.Arch.Family {
680 Exitf("unknown macho architecture: %v", ctxt.Arch.Family)
683 mh.cpu = MACHO_CPU_AMD64
684 mh.subcpu = MACHO_SUBCPU_X86
687 mh.cpu = MACHO_CPU_ARM64
688 mh.subcpu = MACHO_SUBCPU_ARM64_ALL
692 if ctxt.LinkMode == LinkExternal {
693 /* segment for entire file */
694 ms = newMachoSeg("", 40)
696 ms.fileoffset = Segtext.Fileoff
697 ms.filesize = Segdwarf.Fileoff + Segdwarf.Filelen - Segtext.Fileoff
698 ms.vsize = Segdwarf.Vaddr + Segdwarf.Length - Segtext.Vaddr
701 /* segment for zero page */
702 if ctxt.LinkMode != LinkExternal {
703 ms = newMachoSeg("__PAGEZERO", 0)
704 ms.vsize = uint64(va)
708 v := Rnd(int64(uint64(HEADR)+Segtext.Length), int64(*FlagRound))
710 if ctxt.LinkMode != LinkExternal {
711 ms = newMachoSeg("__TEXT", 20)
712 ms.vaddr = uint64(va)
715 ms.filesize = uint64(v)
720 for _, sect := range Segtext.Sections {
721 machoshbits(ctxt, ms, sect, "__TEXT")
725 if ctxt.LinkMode != LinkExternal && Segrelrodata.Length > 0 {
726 ms = newMachoSeg("__DATA_CONST", 20)
727 ms.vaddr = Segrelrodata.Vaddr
728 ms.vsize = Segrelrodata.Length
729 ms.fileoffset = Segrelrodata.Fileoff
730 ms.filesize = Segrelrodata.Filelen
733 ms.flag = 0x10 // SG_READ_ONLY
736 for _, sect := range Segrelrodata.Sections {
737 machoshbits(ctxt, ms, sect, "__DATA_CONST")
741 if ctxt.LinkMode != LinkExternal {
742 ms = newMachoSeg("__DATA", 20)
743 ms.vaddr = Segdata.Vaddr
744 ms.vsize = Segdata.Length
745 ms.fileoffset = Segdata.Fileoff
746 ms.filesize = Segdata.Filelen
751 for _, sect := range Segdata.Sections {
752 machoshbits(ctxt, ms, sect, "__DATA")
757 if ctxt.LinkMode != LinkExternal {
758 ms = newMachoSeg("__DWARF", 20)
759 ms.vaddr = Segdwarf.Vaddr
761 ms.fileoffset = Segdwarf.Fileoff
762 ms.filesize = Segdwarf.Filelen
764 for _, sect := range Segdwarf.Sections {
765 machoshbits(ctxt, ms, sect, "__DWARF")
769 if ctxt.LinkMode != LinkExternal {
770 switch ctxt.Arch.Family {
772 Exitf("unknown macho architecture: %v", ctxt.Arch.Family)
775 ml := newMachoLoad(ctxt.Arch, LC_UNIXTHREAD, 42+2)
776 ml.data[0] = 4 /* thread type */
777 ml.data[1] = 42 /* word count */
778 ml.data[2+32] = uint32(Entryvalue(ctxt)) /* start pc */
779 ml.data[2+32+1] = uint32(Entryvalue(ctxt) >> 32)
782 ml := newMachoLoad(ctxt.Arch, LC_MAIN, 4)
783 ml.data[0] = uint32(uint64(Entryvalue(ctxt)) - (Segtext.Vaddr - uint64(HEADR)))
784 ml.data[1] = uint32((uint64(Entryvalue(ctxt)) - (Segtext.Vaddr - uint64(HEADR))) >> 32)
790 // must match doMachoLink below
791 s1 := ldr.SymSize(ldr.Lookup(".machorebase", 0))
792 s2 := ldr.SymSize(ldr.Lookup(".machobind", 0))
793 s3 := ldr.SymSize(ldr.Lookup(".machosymtab", 0))
794 s4 := ldr.SymSize(ctxt.ArchSyms.LinkEditPLT)
795 s5 := ldr.SymSize(ctxt.ArchSyms.LinkEditGOT)
796 s6 := ldr.SymSize(ldr.Lookup(".machosymstr", 0))
797 s7 := ldr.SymSize(ldr.Lookup(".machocodesig", 0))
799 if ctxt.LinkMode != LinkExternal {
800 ms := newMachoSeg("__LINKEDIT", 0)
801 ms.vaddr = uint64(Rnd(int64(Segdata.Vaddr+Segdata.Length), int64(*FlagRound)))
802 ms.vsize = uint64(s1 + s2 + s3 + s4 + s5 + s6 + s7)
803 ms.fileoffset = uint64(linkoff)
804 ms.filesize = ms.vsize
808 codesigOff = linkoff + s1 + s2 + s3 + s4 + s5 + s6
811 if ctxt.LinkMode != LinkExternal && ctxt.IsPIE() {
812 ml := newMachoLoad(ctxt.Arch, LC_DYLD_INFO_ONLY, 10)
813 ml.data[0] = uint32(linkoff) // rebase off
814 ml.data[1] = uint32(s1) // rebase size
815 ml.data[2] = uint32(linkoff + s1) // bind off
816 ml.data[3] = uint32(s2) // bind size
817 ml.data[4] = 0 // weak bind off
818 ml.data[5] = 0 // weak bind size
819 ml.data[6] = 0 // lazy bind off
820 ml.data[7] = 0 // lazy bind size
821 ml.data[8] = 0 // export
822 ml.data[9] = 0 // export size
825 ml := newMachoLoad(ctxt.Arch, LC_SYMTAB, 4)
826 ml.data[0] = uint32(linkoff + s1 + s2) /* symoff */
827 ml.data[1] = uint32(nsortsym) /* nsyms */
828 ml.data[2] = uint32(linkoff + s1 + s2 + s3 + s4 + s5) /* stroff */
829 ml.data[3] = uint32(s6) /* strsize */
831 machodysymtab(ctxt, linkoff+s1+s2)
833 if ctxt.LinkMode != LinkExternal {
834 ml := newMachoLoad(ctxt.Arch, LC_LOAD_DYLINKER, 6)
835 ml.data[0] = 12 /* offset to string */
836 stringtouint32(ml.data[1:], "/usr/lib/dyld")
838 for _, lib := range dylib {
839 ml = newMachoLoad(ctxt.Arch, LC_LOAD_DYLIB, 4+(uint32(len(lib))+1+7)/8*2)
840 ml.data[0] = 24 /* offset of string from beginning of load */
841 ml.data[1] = 0 /* time stamp */
842 ml.data[2] = 0 /* version */
843 ml.data[3] = 0 /* compatibility version */
844 stringtouint32(ml.data[4:], lib)
848 if ctxt.IsInternal() && ctxt.NeedCodeSign() {
849 ml := newMachoLoad(ctxt.Arch, LC_CODE_SIGNATURE, 2)
850 ml.data[0] = uint32(codesigOff)
851 ml.data[1] = uint32(s7)
855 a := machowrite(ctxt, ctxt.Arch, ctxt.Out, ctxt.LinkMode)
856 if int32(a) > HEADR {
857 Exitf("HEADR too small: %d > %d", a, HEADR)
860 // Now we have written everything. Compute the code signature (which
861 // is a hash of the file content, so it must be done at last.)
862 if ctxt.IsInternal() && ctxt.NeedCodeSign() {
863 cs := ldr.Lookup(".machocodesig", 0)
864 data := ctxt.Out.Data()
865 if int64(len(data)) != codesigOff {
868 codesign.Sign(ldr.Data(cs), bytes.NewReader(data), "a.out", codesigOff, int64(Segtext.Fileoff), int64(Segtext.Filelen), ctxt.IsExe() || ctxt.IsPIE())
869 ctxt.Out.SeekSet(codesigOff)
870 ctxt.Out.Write(ldr.Data(cs))
874 func symkind(ldr *loader.Loader, s loader.Sym) int {
875 if ldr.SymType(s) == sym.SDYNIMPORT {
878 if ldr.AttrCgoExport(s) {
884 func collectmachosyms(ctxt *Link) {
887 addsym := func(s loader.Sym) {
888 sortsym = append(sortsym, s)
889 nkind[symkind(ldr, s)]++
892 // Add special runtime.text and runtime.etext symbols.
893 // We've already included this symbol in Textp on darwin if ctxt.DynlinkingGo().
894 // See data.go:/textaddress
895 if !ctxt.DynlinkingGo() {
896 s := ldr.Lookup("runtime.text", 0)
897 if ldr.SymType(s) == sym.STEXT {
900 for n := range Segtext.Sections[1:] {
901 s := ldr.Lookup(fmt.Sprintf("runtime.text.%d", n+1), 0)
908 s = ldr.Lookup("runtime.etext", 0)
909 if ldr.SymType(s) == sym.STEXT {
915 for _, s := range ctxt.Textp {
919 shouldBeInSymbolTable := func(s loader.Sym) bool {
920 if ldr.AttrNotInSymbolTable(s) {
923 name := ldr.SymName(s) // TODO: try not to read the name
924 if name == "" || name[0] == '.' {
930 // Add data symbols and external references.
931 for s := loader.Sym(1); s < loader.Sym(ldr.NSym()); s++ {
932 if !ldr.AttrReachable(s) {
936 if t >= sym.SELFRXSECT && t < sym.SXREF { // data sections handled in dodata
937 if t == sym.STLSBSS {
938 // TLSBSS is not used on darwin. See data.go:allocateDataSections
941 if !shouldBeInSymbolTable(s) {
948 case sym.SDYNIMPORT, sym.SHOSTOBJ, sym.SUNDEFEXT:
952 // Some 64-bit functions have a "$INODE64" or "$INODE64$UNIX2003" suffix.
953 if t == sym.SDYNIMPORT && ldr.SymDynimplib(s) == "/usr/lib/libSystem.B.dylib" {
954 // But only on macOS.
955 if machoPlatform == PLATFORM_MACOS {
956 switch n := ldr.SymExtname(s); n {
958 switch buildcfg.GOARCH {
960 ldr.SetSymExtname(s, n+"$INODE64")
962 case "readdir_r", "getfsstat":
963 switch buildcfg.GOARCH {
965 ldr.SetSymExtname(s, n+"$INODE64")
972 nsortsym = len(sortsym)
975 func machosymorder(ctxt *Link) {
978 // On Mac OS X Mountain Lion, we must sort exported symbols
979 // So we sort them here and pre-allocate dynid for them
980 // See https://golang.org/issue/4029
981 for _, s := range ctxt.dynexp {
982 if !ldr.AttrReachable(s) {
983 panic("dynexp symbol is not reachable")
986 collectmachosyms(ctxt)
987 sort.Slice(sortsym[:nsortsym], func(i, j int) bool {
990 k1 := symkind(ldr, s1)
991 k2 := symkind(ldr, s2)
995 return ldr.SymExtname(s1) < ldr.SymExtname(s2) // Note: unnamed symbols are not added in collectmachosyms
997 for i, s := range sortsym {
998 ldr.SetSymDynid(s, int32(i))
1002 // AddMachoSym adds s to Mach-O symbol table, used in GenSymLate.
1003 // Currently only used on ARM64 when external linking.
1004 func AddMachoSym(ldr *loader.Loader, s loader.Sym) {
1005 ldr.SetSymDynid(s, int32(nsortsym))
1006 sortsym = append(sortsym, s)
1008 nkind[symkind(ldr, s)]++
1011 // machoShouldExport reports whether a symbol needs to be exported.
1013 // When dynamically linking, all non-local variables and plugin-exported
1014 // symbols need to be exported.
1015 func machoShouldExport(ctxt *Link, ldr *loader.Loader, s loader.Sym) bool {
1016 if !ctxt.DynlinkingGo() || ldr.AttrLocal(s) {
1019 if ctxt.BuildMode == BuildModePlugin && strings.HasPrefix(ldr.SymExtname(s), objabi.PathToPrefix(*flagPluginPath)) {
1022 name := ldr.SymName(s)
1023 if strings.HasPrefix(name, "go:itab.") {
1026 if strings.HasPrefix(name, "type:") && !strings.HasPrefix(name, "type:.") {
1027 // reduce runtime typemap pressure, but do not
1028 // export alg functions (type:.*), as these
1029 // appear in pclntable.
1032 if strings.HasPrefix(name, "go:link.pkghash") {
1035 return ldr.SymType(s) >= sym.SFirstWritable // only writable sections
1038 func machosymtab(ctxt *Link) {
1040 symtab := ldr.CreateSymForUpdate(".machosymtab", 0)
1041 symstr := ldr.CreateSymForUpdate(".machosymstr", 0)
1043 for _, s := range sortsym[:nsortsym] {
1044 symtab.AddUint32(ctxt.Arch, uint32(symstr.Size()))
1046 export := machoShouldExport(ctxt, ldr, s)
1048 // Prefix symbol names with "_" to match the system toolchain.
1049 // (We used to only prefix C symbols, which is all required for the build.
1050 // But some tools don't recognize Go symbols as symbols, so we prefix them
1052 symstr.AddUint8('_')
1054 // replace "·" as ".", because DTrace cannot handle it.
1055 name := strings.Replace(ldr.SymExtname(s), "·", ".", -1)
1057 name = mangleABIName(ctxt, ldr, s, name)
1058 symstr.Addstring(name)
1060 if t := ldr.SymType(s); t == sym.SDYNIMPORT || t == sym.SHOSTOBJ || t == sym.SUNDEFEXT {
1061 symtab.AddUint8(0x01) // type N_EXT, external symbol
1062 symtab.AddUint8(0) // no section
1063 symtab.AddUint16(ctxt.Arch, 0) // desc
1064 symtab.AddUintXX(ctxt.Arch, 0, ctxt.Arch.PtrSize) // no value
1066 if export || ldr.AttrCgoExportDynamic(s) {
1067 symtab.AddUint8(0x0f) // N_SECT | N_EXT
1068 } else if ldr.AttrCgoExportStatic(s) {
1069 // Only export statically, not dynamically. (N_PEXT is like hidden visibility)
1070 symtab.AddUint8(0x1f) // N_SECT | N_EXT | N_PEXT
1072 symtab.AddUint8(0x0e) // N_SECT
1075 if outer := ldr.OuterSym(o); outer != 0 {
1078 if ldr.SymSect(o) == nil {
1079 ldr.Errorf(s, "missing section for symbol")
1082 symtab.AddUint8(uint8(ldr.SymSect(o).Extnum))
1084 symtab.AddUint16(ctxt.Arch, 0) // desc
1085 symtab.AddUintXX(ctxt.Arch, uint64(ldr.SymAddr(s)), ctxt.Arch.PtrSize)
1090 func machodysymtab(ctxt *Link, base int64) {
1091 ml := newMachoLoad(ctxt.Arch, LC_DYSYMTAB, 18)
1094 ml.data[0] = uint32(n) /* ilocalsym */
1095 ml.data[1] = uint32(nkind[SymKindLocal]) /* nlocalsym */
1096 n += nkind[SymKindLocal]
1098 ml.data[2] = uint32(n) /* iextdefsym */
1099 ml.data[3] = uint32(nkind[SymKindExtdef]) /* nextdefsym */
1100 n += nkind[SymKindExtdef]
1102 ml.data[4] = uint32(n) /* iundefsym */
1103 ml.data[5] = uint32(nkind[SymKindUndef]) /* nundefsym */
1105 ml.data[6] = 0 /* tocoffset */
1106 ml.data[7] = 0 /* ntoc */
1107 ml.data[8] = 0 /* modtaboff */
1108 ml.data[9] = 0 /* nmodtab */
1109 ml.data[10] = 0 /* extrefsymoff */
1110 ml.data[11] = 0 /* nextrefsyms */
1114 // must match domacholink below
1115 s1 := ldr.SymSize(ldr.Lookup(".machosymtab", 0))
1116 s2 := ldr.SymSize(ctxt.ArchSyms.LinkEditPLT)
1117 s3 := ldr.SymSize(ctxt.ArchSyms.LinkEditGOT)
1118 ml.data[12] = uint32(base + s1) /* indirectsymoff */
1119 ml.data[13] = uint32((s2 + s3) / 4) /* nindirectsyms */
1121 ml.data[14] = 0 /* extreloff */
1122 ml.data[15] = 0 /* nextrel */
1123 ml.data[16] = 0 /* locreloff */
1124 ml.data[17] = 0 /* nlocrel */
1127 func doMachoLink(ctxt *Link) int64 {
1133 // write data that will be linkedit section
1134 s1 := ldr.Lookup(".machorebase", 0)
1135 s2 := ldr.Lookup(".machobind", 0)
1136 s3 := ldr.Lookup(".machosymtab", 0)
1137 s4 := ctxt.ArchSyms.LinkEditPLT
1138 s5 := ctxt.ArchSyms.LinkEditGOT
1139 s6 := ldr.Lookup(".machosymstr", 0)
1141 size := ldr.SymSize(s1) + ldr.SymSize(s2) + ldr.SymSize(s3) + ldr.SymSize(s4) + ldr.SymSize(s5) + ldr.SymSize(s6)
1143 // Force the linkedit section to end on a 16-byte
1144 // boundary. This allows pure (non-cgo) Go binaries
1145 // to be code signed correctly.
1147 // Apple's codesign_allocate (a helper utility for
1148 // the codesign utility) can do this fine itself if
1149 // it is run on a dynamic Mach-O binary. However,
1150 // when it is run on a pure (non-cgo) Go binary, where
1151 // the linkedit section is mostly empty, it fails to
1152 // account for the extra padding that it itself adds
1153 // when adding the LC_CODE_SIGNATURE load command
1154 // (which must be aligned on a 16-byte boundary).
1156 // By forcing the linkedit section to end on a 16-byte
1157 // boundary, codesign_allocate will not need to apply
1158 // any alignment padding itself, working around the
1162 s6b := ldr.MakeSymbolUpdater(s6)
1163 s6b.Grow(s6b.Size() + n)
1164 s6b.SetSize(s6b.Size() + n)
1169 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))
1170 ctxt.Out.SeekSet(linkoff)
1172 ctxt.Out.Write(ldr.Data(s1))
1173 ctxt.Out.Write(ldr.Data(s2))
1174 ctxt.Out.Write(ldr.Data(s3))
1175 ctxt.Out.Write(ldr.Data(s4))
1176 ctxt.Out.Write(ldr.Data(s5))
1177 ctxt.Out.Write(ldr.Data(s6))
1179 // Add code signature if necessary. This must be the last.
1180 s7 := machoCodeSigSym(ctxt, linkoff+size)
1181 size += ldr.SymSize(s7)
1184 return Rnd(size, int64(*FlagRound))
1187 func machorelocsect(ctxt *Link, out *OutBuf, sect *sym.Section, syms []loader.Sym) {
1188 // If main section has no bits, nothing to relocate.
1189 if sect.Vaddr >= sect.Seg.Vaddr+sect.Seg.Filelen {
1194 for i, s := range syms {
1195 if !ldr.AttrReachable(s) {
1198 if uint64(ldr.SymValue(s)) >= sect.Vaddr {
1204 eaddr := sect.Vaddr + sect.Length
1205 for _, s := range syms {
1206 if !ldr.AttrReachable(s) {
1209 if ldr.SymValue(s) >= int64(eaddr) {
1213 // Compute external relocations on the go, and pass to Machoreloc1
1215 relocs := ldr.Relocs(s)
1216 for ri := 0; ri < relocs.Count(); ri++ {
1218 rr, ok := extreloc(ctxt, ldr, s, r)
1223 ldr.Errorf(s, "missing xsym in relocation")
1226 if !ldr.AttrReachable(rr.Xsym) {
1227 ldr.Errorf(s, "unreachable reloc %d (%s) target %v", r.Type(), sym.RelocName(ctxt.Arch, r.Type()), ldr.SymName(rr.Xsym))
1229 if !thearch.Machoreloc1(ctxt.Arch, out, ldr, s, rr, int64(uint64(ldr.SymValue(s)+int64(r.Off()))-sect.Vaddr)) {
1230 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()))
1236 if uint64(out.Offset()) != sect.Reloff+sect.Rellen {
1237 panic("machorelocsect: size mismatch")
1241 func machoEmitReloc(ctxt *Link) {
1242 for ctxt.Out.Offset()&7 != 0 {
1246 sizeExtRelocs(ctxt, thearch.MachorelocSize)
1247 relocSect, wg := relocSectFn(ctxt, machorelocsect)
1249 relocSect(ctxt, Segtext.Sections[0], ctxt.Textp)
1250 for _, sect := range Segtext.Sections[1:] {
1251 if sect.Name == ".text" {
1252 relocSect(ctxt, sect, ctxt.Textp)
1254 relocSect(ctxt, sect, ctxt.datap)
1257 for _, sect := range Segrelrodata.Sections {
1258 relocSect(ctxt, sect, ctxt.datap)
1260 for _, sect := range Segdata.Sections {
1261 relocSect(ctxt, sect, ctxt.datap)
1263 for i := 0; i < len(Segdwarf.Sections); i++ {
1264 sect := Segdwarf.Sections[i]
1266 if si.secSym() != loader.Sym(sect.Sym) ||
1267 ctxt.loader.SymSect(si.secSym()) != sect {
1268 panic("inconsistency between dwarfp and Segdwarf")
1270 relocSect(ctxt, sect, si.syms)
1275 // hostobjMachoPlatform returns the first platform load command found
1276 // in the host object, if any.
1277 func hostobjMachoPlatform(h *Hostobj) (*MachoPlatformLoad, error) {
1278 f, err := os.Open(h.file)
1280 return nil, fmt.Errorf("%s: failed to open host object: %v\n", h.file, err)
1283 sr := io.NewSectionReader(f, h.off, h.length)
1284 m, err := macho.NewFile(sr)
1286 // Not a valid Mach-O file.
1289 return peekMachoPlatform(m)
1292 // peekMachoPlatform returns the first LC_VERSION_MIN_* or LC_BUILD_VERSION
1293 // load command found in the Mach-O file, if any.
1294 func peekMachoPlatform(m *macho.File) (*MachoPlatformLoad, error) {
1295 for _, cmd := range m.Loads {
1298 type_: m.ByteOrder.Uint32(raw),
1300 // Skip the type and command length.
1304 case LC_VERSION_MIN_IPHONEOS:
1306 case LC_VERSION_MIN_MACOSX:
1308 case LC_VERSION_MIN_WATCHOS:
1309 p = PLATFORM_WATCHOS
1310 case LC_VERSION_MIN_TVOS:
1312 case LC_BUILD_VERSION:
1313 p = MachoPlatform(m.ByteOrder.Uint32(data))
1317 ml.data = make([]uint32, len(data)/4)
1318 r := bytes.NewReader(data)
1319 if err := binary.Read(r, m.ByteOrder, &ml.data); err != nil {
1322 return &MachoPlatformLoad{
1330 // A rebase entry tells the dynamic linker the data at sym+off needs to be
1331 // relocated when the in-memory image moves. (This is somewhat like, say,
1332 // ELF R_X86_64_RELATIVE).
1333 // For now, the only kind of entry we support is that the data is an absolute
1334 // address. That seems all we need.
1335 // In the binary it uses a compact stateful bytecode encoding. So we record
1336 // entries as we go and build the table at the end.
1337 type machoRebaseRecord struct {
1342 var machorebase []machoRebaseRecord
1344 func MachoAddRebase(s loader.Sym, off int64) {
1345 machorebase = append(machorebase, machoRebaseRecord{s, off})
1348 // A bind entry tells the dynamic linker the data at GOT+off should be bound
1349 // to the address of the target symbol, which is a dynamic import.
1350 // For now, the only kind of entry we support is that the data is an absolute
1351 // address, and the source symbol is always the GOT. That seems all we need.
1352 // In the binary it uses a compact stateful bytecode encoding. So we record
1353 // entries as we go and build the table at the end.
1354 type machoBindRecord struct {
1359 var machobind []machoBindRecord
1361 func MachoAddBind(off int64, targ loader.Sym) {
1362 machobind = append(machobind, machoBindRecord{off, targ})
1365 // Generate data for the dynamic linker, used in LC_DYLD_INFO_ONLY load command.
1366 // See mach-o/loader.h, struct dyld_info_command, for the encoding.
1367 // e.g. https://opensource.apple.com/source/xnu/xnu-6153.81.5/EXTERNAL_HEADERS/mach-o/loader.h
1368 func machoDyldInfo(ctxt *Link) {
1370 rebase := ldr.CreateSymForUpdate(".machorebase", 0)
1371 bind := ldr.CreateSymForUpdate(".machobind", 0)
1373 if !(ctxt.IsPIE() && ctxt.IsInternal()) {
1377 segId := func(seg *sym.Segment) uint8 {
1384 if Segrelrodata.Length > 0 {
1389 panic("unknown segment")
1392 dylibId := func(s loader.Sym) int {
1393 slib := ldr.SymDynimplib(s)
1394 for i, lib := range dylib {
1399 return BIND_SPECIAL_DYLIB_FLAT_LOOKUP // don't know where it is from
1403 // TODO: use more compact encoding. The encoding is stateful, and
1404 // we can use delta encoding.
1405 rebase.AddUint8(REBASE_OPCODE_SET_TYPE_IMM | REBASE_TYPE_POINTER)
1406 for _, r := range machorebase {
1407 seg := ldr.SymSect(r.sym).Seg
1408 off := uint64(ldr.SymValue(r.sym)+r.off) - seg.Vaddr
1409 rebase.AddUint8(REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | segId(seg))
1412 rebase.AddUint8(REBASE_OPCODE_DO_REBASE_IMM_TIMES | 1)
1414 rebase.AddUint8(REBASE_OPCODE_DONE)
1415 sz := Rnd(rebase.Size(), 8)
1420 // TODO: compact encoding, as above.
1421 // TODO: lazy binding?
1423 seg := ldr.SymSect(got).Seg
1424 gotAddr := ldr.SymValue(got)
1425 bind.AddUint8(BIND_OPCODE_SET_TYPE_IMM | BIND_TYPE_POINTER)
1426 for _, r := range machobind {
1427 off := uint64(gotAddr+r.off) - seg.Vaddr
1428 bind.AddUint8(BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | segId(seg))
1431 d := dylibId(r.targ)
1432 if d > 0 && d < 128 {
1433 bind.AddUint8(BIND_OPCODE_SET_DYLIB_ORDINAL_IMM | uint8(d)&0xf)
1434 } else if d >= 128 {
1435 bind.AddUint8(BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB)
1436 bind.AddUleb(uint64(d))
1438 bind.AddUint8(BIND_OPCODE_SET_DYLIB_SPECIAL_IMM | uint8(d)&0xf)
1441 bind.AddUint8(BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM)
1442 // target symbol name as a C string, with _ prefix
1444 bind.Addstring(ldr.SymExtname(r.targ))
1446 bind.AddUint8(BIND_OPCODE_DO_BIND)
1448 bind.AddUint8(BIND_OPCODE_DONE)
1449 sz = Rnd(bind.Size(), 16) // make it 16-byte aligned, see the comment in doMachoLink
1453 // TODO: export table.
1454 // The symbols names are encoded as a trie. I'm really too lazy to do that
1456 // Without it, the symbols are not dynamically exported, so they cannot be
1457 // e.g. dlsym'd. But internal linking is not the default in that case, so
1461 // machoCodeSigSym creates and returns a symbol for code signature.
1462 // The symbol context is left as zeros, which will be generated at the end
1463 // (as it depends on the rest of the file).
1464 func machoCodeSigSym(ctxt *Link, codeSize int64) loader.Sym {
1466 cs := ldr.CreateSymForUpdate(".machocodesig", 0)
1467 if !ctxt.NeedCodeSign() || ctxt.IsExternal() {
1470 sz := codesign.Size(codeSize, "a.out")
1476 // machoCodeSign code-signs Mach-O file fname with an ad-hoc signature.
1477 // This is used for updating an external linker generated binary.
1478 func machoCodeSign(ctxt *Link, fname string) error {
1479 f, err := os.OpenFile(fname, os.O_RDWR, 0)
1485 mf, err := macho.NewFile(f)
1489 if mf.Magic != macho.Magic64 {
1490 Exitf("not 64-bit Mach-O file: %s", fname)
1493 // Find existing LC_CODE_SIGNATURE and __LINKEDIT segment
1494 var sigOff, sigSz, csCmdOff, linkeditOff int64
1495 var linkeditSeg, textSeg *macho.Segment
1496 loadOff := int64(machoHeaderSize64)
1497 get32 := mf.ByteOrder.Uint32
1498 for _, l := range mf.Loads {
1500 cmd, sz := get32(data), get32(data[4:])
1501 if cmd == LC_CODE_SIGNATURE {
1502 sigOff = int64(get32(data[8:]))
1503 sigSz = int64(get32(data[12:]))
1506 if seg, ok := l.(*macho.Segment); ok {
1510 linkeditOff = loadOff
1515 loadOff += int64(sz)
1519 // The C linker doesn't generate a signed binary, for some reason.
1528 if sigOff+sigSz != fi.Size() {
1529 // We don't expect anything after the signature (this will invalidate
1530 // the signature anyway.)
1531 return fmt.Errorf("unexpected content after code signature")
1534 sz := codesign.Size(sigOff, "a.out")
1536 // Update the load command,
1538 mf.ByteOrder.PutUint32(tmp[:4], uint32(sz))
1539 _, err = f.WriteAt(tmp[:4], csCmdOff+12)
1544 // Uodate the __LINKEDIT segment.
1545 segSz := sigOff + sz - int64(linkeditSeg.Offset)
1546 mf.ByteOrder.PutUint64(tmp[:8], uint64(segSz))
1547 _, err = f.WriteAt(tmp[:8], int64(linkeditOff)+int64(unsafe.Offsetof(macho.Segment64{}.Memsz)))
1551 _, err = f.WriteAt(tmp[:8], int64(linkeditOff)+int64(unsafe.Offsetof(macho.Segment64{}.Filesz)))
1557 cs := make([]byte, sz)
1558 codesign.Sign(cs, f, "a.out", sigOff, int64(textSeg.Offset), int64(textSeg.Filesz), ctxt.IsExe() || ctxt.IsPIE())
1559 _, err = f.WriteAt(cs, sigOff)
1563 err = f.Truncate(sigOff + sz)