Help us shape the future of Go! Take the 2026 Go Developer Survey

Source file src/cmd/link/internal/ld/macho.go

     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.
     4  
     5  package ld
     6  
     7  import (
     8  	"bytes"
     9  	"cmd/internal/codesign"
    10  	"cmd/internal/hash"
    11  	imacho "cmd/internal/macho"
    12  	"cmd/internal/objabi"
    13  	"cmd/internal/sys"
    14  	"cmd/link/internal/loader"
    15  	"cmd/link/internal/sym"
    16  	"debug/macho"
    17  	"encoding/binary"
    18  	"fmt"
    19  	"internal/buildcfg"
    20  	"io"
    21  	"os"
    22  	"slices"
    23  	"sort"
    24  	"strconv"
    25  	"strings"
    26  	"unsafe"
    27  )
    28  
    29  type MachoHdr struct {
    30  	cpu    uint32
    31  	subcpu uint32
    32  }
    33  
    34  type MachoSect struct {
    35  	name    string
    36  	segname string
    37  	addr    uint64
    38  	size    uint64
    39  	off     uint32
    40  	align   uint32
    41  	reloc   uint32
    42  	nreloc  uint32
    43  	flag    uint32
    44  	res1    uint32
    45  	res2    uint32
    46  }
    47  
    48  type MachoSeg struct {
    49  	name       string
    50  	vsize      uint64
    51  	vaddr      uint64
    52  	fileoffset uint64
    53  	filesize   uint64
    54  	prot1      uint32
    55  	prot2      uint32
    56  	nsect      uint32
    57  	msect      uint32
    58  	sect       []MachoSect
    59  	flag       uint32
    60  }
    61  
    62  // MachoPlatformLoad represents a LC_VERSION_MIN_* or
    63  // LC_BUILD_VERSION load command.
    64  type MachoPlatformLoad struct {
    65  	platform MachoPlatform // One of PLATFORM_* constants.
    66  	cmd      MachoLoad
    67  }
    68  
    69  type MachoLoad struct {
    70  	type_ uint32
    71  	data  []uint32
    72  }
    73  
    74  type MachoPlatform int
    75  
    76  /*
    77   * Total amount of space to reserve at the start of the file
    78   * for Header, PHeaders, and SHeaders.
    79   * May waste some.
    80   */
    81  const (
    82  	INITIAL_MACHO_HEADR = 4 * 1024
    83  )
    84  
    85  const (
    86  	MACHO_CPU_AMD64                      = 1<<24 | 7
    87  	MACHO_CPU_386                        = 7
    88  	MACHO_SUBCPU_X86                     = 3
    89  	MACHO_CPU_ARM                        = 12
    90  	MACHO_SUBCPU_ARM                     = 0
    91  	MACHO_SUBCPU_ARMV7                   = 9
    92  	MACHO_CPU_ARM64                      = 1<<24 | 12
    93  	MACHO_SUBCPU_ARM64_ALL               = 0
    94  	MACHO_SUBCPU_ARM64_V8                = 1
    95  	MACHO_SUBCPU_ARM64E                  = 2
    96  	MACHO32SYMSIZE                       = 12
    97  	MACHO64SYMSIZE                       = 16
    98  	MACHO_X86_64_RELOC_UNSIGNED          = 0
    99  	MACHO_X86_64_RELOC_SIGNED            = 1
   100  	MACHO_X86_64_RELOC_BRANCH            = 2
   101  	MACHO_X86_64_RELOC_GOT_LOAD          = 3
   102  	MACHO_X86_64_RELOC_GOT               = 4
   103  	MACHO_X86_64_RELOC_SUBTRACTOR        = 5
   104  	MACHO_X86_64_RELOC_SIGNED_1          = 6
   105  	MACHO_X86_64_RELOC_SIGNED_2          = 7
   106  	MACHO_X86_64_RELOC_SIGNED_4          = 8
   107  	MACHO_ARM_RELOC_VANILLA              = 0
   108  	MACHO_ARM_RELOC_PAIR                 = 1
   109  	MACHO_ARM_RELOC_SECTDIFF             = 2
   110  	MACHO_ARM_RELOC_BR24                 = 5
   111  	MACHO_ARM64_RELOC_UNSIGNED           = 0
   112  	MACHO_ARM64_RELOC_SUBTRACTOR         = 1
   113  	MACHO_ARM64_RELOC_BRANCH26           = 2
   114  	MACHO_ARM64_RELOC_PAGE21             = 3
   115  	MACHO_ARM64_RELOC_PAGEOFF12          = 4
   116  	MACHO_ARM64_RELOC_GOT_LOAD_PAGE21    = 5
   117  	MACHO_ARM64_RELOC_GOT_LOAD_PAGEOFF12 = 6
   118  	MACHO_ARM64_RELOC_POINTER_TO_GOT     = 7
   119  	MACHO_ARM64_RELOC_ADDEND             = 10
   120  	MACHO_GENERIC_RELOC_VANILLA          = 0
   121  	MACHO_FAKE_GOTPCREL                  = 100
   122  )
   123  
   124  const (
   125  	MH_MAGIC    = 0xfeedface
   126  	MH_MAGIC_64 = 0xfeedfacf
   127  
   128  	MH_OBJECT  = 0x1
   129  	MH_EXECUTE = 0x2
   130  	MH_DSYM    = 0xa
   131  
   132  	MH_NOUNDEFS = 0x1
   133  	MH_DYLDLINK = 0x4
   134  	MH_PIE      = 0x200000
   135  )
   136  
   137  const (
   138  	S_REGULAR                  = 0x0
   139  	S_ZEROFILL                 = 0x1
   140  	S_NON_LAZY_SYMBOL_POINTERS = 0x6
   141  	S_SYMBOL_STUBS             = 0x8
   142  	S_MOD_INIT_FUNC_POINTERS   = 0x9
   143  	S_ATTR_PURE_INSTRUCTIONS   = 0x80000000
   144  	S_ATTR_DEBUG               = 0x02000000
   145  	S_ATTR_SOME_INSTRUCTIONS   = 0x00000400
   146  )
   147  
   148  const (
   149  	PLATFORM_MACOS       MachoPlatform = 1
   150  	PLATFORM_IOS         MachoPlatform = 2
   151  	PLATFORM_TVOS        MachoPlatform = 3
   152  	PLATFORM_WATCHOS     MachoPlatform = 4
   153  	PLATFORM_BRIDGEOS    MachoPlatform = 5
   154  	PLATFORM_MACCATALYST MachoPlatform = 6
   155  )
   156  
   157  // rebase table opcode
   158  const (
   159  	REBASE_TYPE_POINTER         = 1
   160  	REBASE_TYPE_TEXT_ABSOLUTE32 = 2
   161  	REBASE_TYPE_TEXT_PCREL32    = 3
   162  
   163  	REBASE_OPCODE_MASK                               = 0xF0
   164  	REBASE_IMMEDIATE_MASK                            = 0x0F
   165  	REBASE_OPCODE_DONE                               = 0x00
   166  	REBASE_OPCODE_SET_TYPE_IMM                       = 0x10
   167  	REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB        = 0x20
   168  	REBASE_OPCODE_ADD_ADDR_ULEB                      = 0x30
   169  	REBASE_OPCODE_ADD_ADDR_IMM_SCALED                = 0x40
   170  	REBASE_OPCODE_DO_REBASE_IMM_TIMES                = 0x50
   171  	REBASE_OPCODE_DO_REBASE_ULEB_TIMES               = 0x60
   172  	REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB            = 0x70
   173  	REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB = 0x80
   174  )
   175  
   176  // bind table opcode
   177  const (
   178  	BIND_TYPE_POINTER         = 1
   179  	BIND_TYPE_TEXT_ABSOLUTE32 = 2
   180  	BIND_TYPE_TEXT_PCREL32    = 3
   181  
   182  	BIND_SPECIAL_DYLIB_SELF            = 0
   183  	BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE = -1
   184  	BIND_SPECIAL_DYLIB_FLAT_LOOKUP     = -2
   185  	BIND_SPECIAL_DYLIB_WEAK_LOOKUP     = -3
   186  
   187  	BIND_SYMBOL_FLAGS_WEAK_IMPORT = 0x1
   188  
   189  	BIND_OPCODE_MASK                                         = 0xF0
   190  	BIND_IMMEDIATE_MASK                                      = 0x0F
   191  	BIND_OPCODE_DONE                                         = 0x00
   192  	BIND_OPCODE_SET_DYLIB_ORDINAL_IMM                        = 0x10
   193  	BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB                       = 0x20
   194  	BIND_OPCODE_SET_DYLIB_SPECIAL_IMM                        = 0x30
   195  	BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM                = 0x40
   196  	BIND_OPCODE_SET_TYPE_IMM                                 = 0x50
   197  	BIND_OPCODE_SET_ADDEND_SLEB                              = 0x60
   198  	BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB                  = 0x70
   199  	BIND_OPCODE_ADD_ADDR_ULEB                                = 0x80
   200  	BIND_OPCODE_DO_BIND                                      = 0x90
   201  	BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB                        = 0xA0
   202  	BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED                  = 0xB0
   203  	BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB             = 0xC0
   204  	BIND_OPCODE_THREADED                                     = 0xD0
   205  	BIND_SUBOPCODE_THREADED_SET_BIND_ORDINAL_TABLE_SIZE_ULEB = 0x00
   206  	BIND_SUBOPCODE_THREADED_APPLY                            = 0x01
   207  )
   208  
   209  const machoHeaderSize64 = 8 * 4 // size of 64-bit Mach-O header
   210  
   211  // Mach-O file writing
   212  // https://developer.apple.com/mac/library/DOCUMENTATION/DeveloperTools/Conceptual/MachORuntime/Reference/reference.html
   213  
   214  var machohdr MachoHdr
   215  
   216  var load []MachoLoad
   217  
   218  var machoPlatform MachoPlatform
   219  
   220  var seg [16]MachoSeg
   221  
   222  var nseg int
   223  
   224  var ndebug int
   225  
   226  var nsect int
   227  
   228  const (
   229  	SymKindLocal = 0 + iota
   230  	SymKindExtdef
   231  	SymKindUndef
   232  	NumSymKind
   233  )
   234  
   235  var nkind [NumSymKind]int
   236  
   237  var sortsym []loader.Sym
   238  
   239  var nsortsym int
   240  
   241  // Amount of space left for adding load commands
   242  // that refer to dynamic libraries. Because these have
   243  // to go in the Mach-O header, we can't just pick a
   244  // "big enough" header size. The initial header is
   245  // one page, the non-dynamic library stuff takes
   246  // up about 1300 bytes; we overestimate that as 2k.
   247  var loadBudget = INITIAL_MACHO_HEADR - 2*1024
   248  
   249  func getMachoHdr() *MachoHdr {
   250  	return &machohdr
   251  }
   252  
   253  // Create a new Mach-O load command. ndata is the number of 32-bit words for
   254  // the data (not including the load command header).
   255  func newMachoLoad(arch *sys.Arch, type_ uint32, ndata uint32) *MachoLoad {
   256  	if ndata&1 != 0 {
   257  		ndata++
   258  	}
   259  
   260  	load = append(load, MachoLoad{})
   261  	l := &load[len(load)-1]
   262  	l.type_ = type_
   263  	l.data = make([]uint32, ndata)
   264  	return l
   265  }
   266  
   267  func newMachoSeg(name string, msect int) *MachoSeg {
   268  	if nseg >= len(seg) {
   269  		Exitf("too many segs")
   270  	}
   271  
   272  	s := &seg[nseg]
   273  	nseg++
   274  	s.name = name
   275  	s.msect = uint32(msect)
   276  	s.sect = make([]MachoSect, msect)
   277  	return s
   278  }
   279  
   280  func newMachoSect(seg *MachoSeg, name string, segname string) *MachoSect {
   281  	if seg.nsect >= seg.msect {
   282  		Exitf("too many sects in segment %s", seg.name)
   283  	}
   284  
   285  	s := &seg.sect[seg.nsect]
   286  	seg.nsect++
   287  	s.name = name
   288  	s.segname = segname
   289  	nsect++
   290  	return s
   291  }
   292  
   293  // Generic linking code.
   294  
   295  var dylib []string
   296  
   297  var linkoff int64
   298  
   299  func machowrite(ctxt *Link, arch *sys.Arch, out *OutBuf, linkmode LinkMode) int {
   300  	o1 := out.Offset()
   301  
   302  	loadsize := 4 * 4 * ndebug
   303  	for i := range load {
   304  		loadsize += 4 * (len(load[i].data) + 2)
   305  	}
   306  	loadsize += 18 * 4 * nseg
   307  	loadsize += 20 * 4 * nsect
   308  
   309  	out.Write32(MH_MAGIC_64)
   310  	out.Write32(machohdr.cpu)
   311  	out.Write32(machohdr.subcpu)
   312  	if out == ctxt.OutDWARF {
   313  		out.Write32(MH_DSYM)
   314  	} else if linkmode == LinkExternal {
   315  		out.Write32(MH_OBJECT) /* file type - mach object */
   316  	} else {
   317  		out.Write32(MH_EXECUTE) /* file type - mach executable */
   318  	}
   319  	out.Write32(uint32(len(load)) + uint32(nseg) + uint32(ndebug))
   320  	out.Write32(uint32(loadsize))
   321  	flags := uint32(0)
   322  	if out != ctxt.OutDWARF {
   323  		if nkind[SymKindUndef] == 0 {
   324  			flags |= MH_NOUNDEFS
   325  		}
   326  		if ctxt.IsPIE() && linkmode == LinkInternal {
   327  			flags |= MH_PIE | MH_DYLDLINK
   328  		}
   329  	}
   330  	out.Write32(flags) /* flags */
   331  	out.Write32(0)     /* reserved */
   332  
   333  	for i := 0; i < nseg; i++ {
   334  		s := &seg[i]
   335  		out.Write32(imacho.LC_SEGMENT_64)
   336  		out.Write32(72 + 80*s.nsect)
   337  		out.WriteStringN(s.name, 16)
   338  		out.Write64(s.vaddr)
   339  		out.Write64(s.vsize)
   340  		out.Write64(s.fileoffset)
   341  		out.Write64(s.filesize)
   342  		out.Write32(s.prot1)
   343  		out.Write32(s.prot2)
   344  		out.Write32(s.nsect)
   345  		out.Write32(s.flag)
   346  
   347  		for j := uint32(0); j < s.nsect; j++ {
   348  			t := &s.sect[j]
   349  			out.WriteStringN(t.name, 16)
   350  			out.WriteStringN(t.segname, 16)
   351  			out.Write64(t.addr)
   352  			out.Write64(t.size)
   353  			out.Write32(t.off)
   354  			out.Write32(t.align)
   355  			out.Write32(t.reloc)
   356  			out.Write32(t.nreloc)
   357  			out.Write32(t.flag)
   358  			out.Write32(t.res1) /* reserved */
   359  			out.Write32(t.res2) /* reserved */
   360  			out.Write32(0)      /* reserved */
   361  		}
   362  	}
   363  
   364  	for i := range load {
   365  		l := &load[i]
   366  		out.Write32(l.type_)
   367  		out.Write32(4 * (uint32(len(l.data)) + 2))
   368  		for j := 0; j < len(l.data); j++ {
   369  			out.Write32(l.data[j])
   370  		}
   371  	}
   372  
   373  	return int(out.Offset() - o1)
   374  }
   375  
   376  type macVersionFlag [3]byte
   377  
   378  func (f *macVersionFlag) String() string {
   379  	return fmt.Sprintf("%d.%d.%d", f[0], f[1], f[2])
   380  }
   381  
   382  func (f *macVersionFlag) Set(s string) error {
   383  	var parsed macVersionFlag
   384  	nums := strings.Split(s, ".")
   385  	if len(nums) > 3 {
   386  		goto Error
   387  	}
   388  	for i, num := range nums {
   389  		n, err := strconv.Atoi(num)
   390  		if err != nil || n < 0 || n > 0xFF {
   391  			goto Error
   392  		}
   393  		parsed[i] = byte(n)
   394  	}
   395  	// success, now modify f
   396  	*f = parsed
   397  	return nil
   398  
   399  Error:
   400  	return fmt.Errorf("invalid version %q", s)
   401  }
   402  
   403  func (f *macVersionFlag) version() uint32 {
   404  	return uint32(f[0])<<16 | uint32(f[1])<<8 | uint32(f[2])
   405  }
   406  
   407  var (
   408  	// On advice from Apple engineers, we keep macOS set to the
   409  	// oldest supported macOS version but keep macSDK to the newest
   410  	// tested OS/SDK version. If these defaults are not good enough,
   411  	// the -macos and -macsdk linker flags can override them.
   412  	// For past problems involving these values, see
   413  	//	go.dev/issue/30488
   414  	//	go.dev/issue/56784
   415  	//	go.dev/issue/77917
   416  	macOS  = macVersionFlag{13, 0, 0}
   417  	macSDK = macVersionFlag{26, 2, 0}
   418  )
   419  
   420  func (ctxt *Link) domacho() {
   421  	// Copy platform load command.
   422  	for _, h := range hostobj {
   423  		load, err := hostobjMachoPlatform(&h)
   424  		if err != nil {
   425  			Exitf("%v", err)
   426  		}
   427  		if load != nil && load.platform != PLATFORM_MACOS {
   428  			ml := newMachoLoad(ctxt.Arch, load.cmd.type_, uint32(len(load.cmd.data)))
   429  			copy(ml.data, load.cmd.data)
   430  			break
   431  		}
   432  	}
   433  	if machoPlatform == 0 {
   434  		machoPlatform = PLATFORM_MACOS
   435  		if buildcfg.GOOS == "ios" {
   436  			machoPlatform = PLATFORM_IOS
   437  		}
   438  		if load == nil && machoPlatform == PLATFORM_MACOS {
   439  			ml := newMachoLoad(ctxt.Arch, imacho.LC_BUILD_VERSION, 4)
   440  			ml.data[0] = uint32(machoPlatform)
   441  			ml.data[1] = macOS.version()
   442  			ml.data[2] = macSDK.version()
   443  			ml.data[3] = 0 // ntools
   444  		}
   445  	}
   446  
   447  	// empirically, string table must begin with " \x00".
   448  	s := ctxt.loader.LookupOrCreateSym(".machosymstr", 0)
   449  	sb := ctxt.loader.MakeSymbolUpdater(s)
   450  
   451  	sb.SetType(sym.SMACHOSYMSTR)
   452  	sb.SetReachable(true)
   453  	sb.AddUint8(' ')
   454  	sb.AddUint8('\x00')
   455  
   456  	s = ctxt.loader.LookupOrCreateSym(".machosymtab", 0)
   457  	sb = ctxt.loader.MakeSymbolUpdater(s)
   458  	sb.SetType(sym.SMACHOSYMTAB)
   459  	sb.SetReachable(true)
   460  
   461  	if ctxt.IsInternal() {
   462  		s = ctxt.loader.LookupOrCreateSym(".plt", 0) // will be __symbol_stub
   463  		sb = ctxt.loader.MakeSymbolUpdater(s)
   464  		sb.SetType(sym.SMACHOPLT)
   465  		sb.SetReachable(true)
   466  
   467  		s = ctxt.loader.LookupOrCreateSym(".got", 0) // will be __got
   468  		sb = ctxt.loader.MakeSymbolUpdater(s)
   469  		if ctxt.UseRelro() {
   470  			sb.SetType(sym.SMACHORELROSECT)
   471  		} else {
   472  			sb.SetType(sym.SMACHOGOT)
   473  		}
   474  		sb.SetReachable(true)
   475  		sb.SetAlign(4)
   476  
   477  		s = ctxt.loader.LookupOrCreateSym(".linkedit.plt", 0) // indirect table for .plt
   478  		sb = ctxt.loader.MakeSymbolUpdater(s)
   479  		sb.SetType(sym.SMACHOINDIRECTPLT)
   480  		sb.SetReachable(true)
   481  
   482  		s = ctxt.loader.LookupOrCreateSym(".linkedit.got", 0) // indirect table for .got
   483  		sb = ctxt.loader.MakeSymbolUpdater(s)
   484  		sb.SetType(sym.SMACHOINDIRECTGOT)
   485  		sb.SetReachable(true)
   486  	}
   487  
   488  	// Add a dummy symbol that will become the __asm marker section.
   489  	if ctxt.IsExternal() {
   490  		s = ctxt.loader.LookupOrCreateSym(".llvmasm", 0)
   491  		sb = ctxt.loader.MakeSymbolUpdater(s)
   492  		sb.SetType(sym.SMACHO)
   493  		sb.SetReachable(true)
   494  		sb.AddUint8(0)
   495  	}
   496  
   497  	// Un-export runtime symbols from plugins. Since the runtime
   498  	// is included in both the main binary and each plugin, these
   499  	// symbols appear in both images. If we leave them exported in
   500  	// the plugin, then the dynamic linker will resolve
   501  	// relocations to these functions in the plugin's functab to
   502  	// point to the main image, causing the runtime to think the
   503  	// plugin's functab is corrupted. By unexporting them, these
   504  	// become static references, which are resolved to the
   505  	// plugin's text.
   506  	//
   507  	// It would be better to omit the runtime from plugins. (Using
   508  	// relative PCs in the functab instead of relocations would
   509  	// also address this.)
   510  	//
   511  	// See issue #18190.
   512  	if ctxt.BuildMode == BuildModePlugin {
   513  		for _, name := range []string{"_cgo_topofstack", "__cgo_topofstack", "_cgo_panic", "crosscall2"} {
   514  			// Most of these are data symbols or C
   515  			// symbols, so they have symbol version 0.
   516  			ver := 0
   517  			// _cgo_panic is a Go function, so it uses ABIInternal.
   518  			if name == "_cgo_panic" {
   519  				ver = abiInternalVer
   520  			}
   521  			s := ctxt.loader.Lookup(name, ver)
   522  			if s != 0 {
   523  				ctxt.loader.SetAttrCgoExportDynamic(s, false)
   524  			}
   525  		}
   526  	}
   527  }
   528  
   529  func machoadddynlib(lib string, linkmode LinkMode) {
   530  	if seenlib[lib] || linkmode == LinkExternal {
   531  		return
   532  	}
   533  	seenlib[lib] = true
   534  
   535  	// Will need to store the library name rounded up
   536  	// and 24 bytes of header metadata. If not enough
   537  	// space, grab another page of initial space at the
   538  	// beginning of the output file.
   539  	loadBudget -= (len(lib)+7)/8*8 + 24
   540  
   541  	if loadBudget < 0 {
   542  		HEADR += 4096
   543  		*FlagTextAddr += 4096
   544  		loadBudget += 4096
   545  	}
   546  
   547  	dylib = append(dylib, lib)
   548  }
   549  
   550  func machoshbits(ctxt *Link, mseg *MachoSeg, sect *sym.Section, segname string) {
   551  	buf := "__" + strings.ReplaceAll(sect.Name[1:], ".", "_")
   552  
   553  	msect := newMachoSect(mseg, buf, segname)
   554  
   555  	if sect.Rellen > 0 {
   556  		msect.reloc = uint32(sect.Reloff)
   557  		msect.nreloc = uint32(sect.Rellen / 8)
   558  	}
   559  
   560  	for 1<<msect.align < sect.Align {
   561  		msect.align++
   562  	}
   563  	msect.addr = sect.Vaddr
   564  	msect.size = sect.Length
   565  
   566  	if sect.Vaddr < sect.Seg.Vaddr+sect.Seg.Filelen {
   567  		// data in file
   568  		if sect.Length > sect.Seg.Vaddr+sect.Seg.Filelen-sect.Vaddr {
   569  			Errorf("macho cannot represent section %s crossing data and bss", sect.Name)
   570  		}
   571  		msect.off = uint32(sect.Seg.Fileoff + sect.Vaddr - sect.Seg.Vaddr)
   572  	} else {
   573  		msect.off = 0
   574  		msect.flag |= S_ZEROFILL
   575  	}
   576  
   577  	if sect.Rwx&1 != 0 {
   578  		msect.flag |= S_ATTR_SOME_INSTRUCTIONS
   579  	}
   580  
   581  	if sect.Name == ".text" {
   582  		msect.flag |= S_ATTR_PURE_INSTRUCTIONS
   583  	}
   584  
   585  	if sect.Name == ".plt" {
   586  		msect.name = "__symbol_stub1"
   587  		msect.flag = S_ATTR_PURE_INSTRUCTIONS | S_ATTR_SOME_INSTRUCTIONS | S_SYMBOL_STUBS
   588  		msect.res1 = 0 //nkind[SymKindLocal];
   589  		msect.res2 = 6
   590  	}
   591  
   592  	if sect.Name == ".got" {
   593  		msect.name = "__got"
   594  		msect.flag = S_NON_LAZY_SYMBOL_POINTERS
   595  		msect.res1 = uint32(ctxt.loader.SymSize(ctxt.ArchSyms.LinkEditPLT) / 4) /* offset into indirect symbol table */
   596  	}
   597  
   598  	if sect.Name == ".init_array" {
   599  		msect.name = "__mod_init_func"
   600  		msect.flag = S_MOD_INIT_FUNC_POINTERS
   601  	}
   602  
   603  	// Some platforms such as watchOS and tvOS require binaries with
   604  	// bitcode enabled. The Go toolchain can't output bitcode, so use
   605  	// a marker section in the __LLVM segment, "__asm", to tell the Apple
   606  	// toolchain that the Go text came from assembler and thus has no
   607  	// bitcode. This is not true, but Kotlin/Native, Rust and Flutter
   608  	// are also using this trick.
   609  	if sect.Name == ".llvmasm" {
   610  		msect.name = "__asm"
   611  		msect.segname = "__LLVM"
   612  	}
   613  
   614  	if segname == "__DWARF" {
   615  		msect.flag |= S_ATTR_DEBUG
   616  	}
   617  }
   618  
   619  func asmbMacho(ctxt *Link) {
   620  	machlink := doMachoLink(ctxt)
   621  	if ctxt.IsExternal() {
   622  		symo := int64(Segdwarf.Fileoff + uint64(Rnd(int64(Segdwarf.Filelen), *FlagRound)) + uint64(machlink))
   623  		ctxt.Out.SeekSet(symo)
   624  		machoEmitReloc(ctxt)
   625  	}
   626  	ctxt.Out.SeekSet(0)
   627  
   628  	ldr := ctxt.loader
   629  
   630  	/* apple MACH */
   631  	va := *FlagTextAddr - int64(HEADR)
   632  
   633  	mh := getMachoHdr()
   634  	switch ctxt.Arch.Family {
   635  	default:
   636  		Exitf("unknown macho architecture: %v", ctxt.Arch.Family)
   637  
   638  	case sys.AMD64:
   639  		mh.cpu = MACHO_CPU_AMD64
   640  		mh.subcpu = MACHO_SUBCPU_X86
   641  
   642  	case sys.ARM64:
   643  		mh.cpu = MACHO_CPU_ARM64
   644  		mh.subcpu = MACHO_SUBCPU_ARM64_ALL
   645  	}
   646  
   647  	var ms *MachoSeg
   648  	if ctxt.LinkMode == LinkExternal {
   649  		/* segment for entire file */
   650  		ms = newMachoSeg("", 40)
   651  
   652  		ms.fileoffset = Segtext.Fileoff
   653  		ms.filesize = Segdwarf.Fileoff + Segdwarf.Filelen - Segtext.Fileoff
   654  		ms.vsize = Segdwarf.Vaddr + Segdwarf.Length - Segtext.Vaddr
   655  	}
   656  
   657  	/* segment for zero page */
   658  	if ctxt.LinkMode != LinkExternal {
   659  		ms = newMachoSeg("__PAGEZERO", 0)
   660  		ms.vsize = uint64(va)
   661  	}
   662  
   663  	/* text */
   664  	v := Rnd(int64(uint64(HEADR)+Segtext.Length), *FlagRound)
   665  
   666  	var mstext *MachoSeg
   667  	if ctxt.LinkMode != LinkExternal {
   668  		ms = newMachoSeg("__TEXT", 20)
   669  		ms.vaddr = uint64(va)
   670  		ms.vsize = uint64(v)
   671  		ms.fileoffset = 0
   672  		ms.filesize = uint64(v)
   673  		ms.prot1 = 7
   674  		ms.prot2 = 5
   675  		mstext = ms
   676  	}
   677  
   678  	for _, sect := range Segtext.Sections {
   679  		machoshbits(ctxt, ms, sect, "__TEXT")
   680  	}
   681  
   682  	/* rodata */
   683  	if ctxt.LinkMode != LinkExternal && Segrelrodata.Length > 0 {
   684  		ms = newMachoSeg("__DATA_CONST", 20)
   685  		ms.vaddr = Segrelrodata.Vaddr
   686  		ms.vsize = Segrelrodata.Length
   687  		ms.fileoffset = Segrelrodata.Fileoff
   688  		ms.filesize = Segrelrodata.Filelen
   689  		ms.prot1 = 3
   690  		ms.prot2 = 3
   691  		ms.flag = 0x10 // SG_READ_ONLY
   692  	}
   693  
   694  	for _, sect := range Segrelrodata.Sections {
   695  		machoshbits(ctxt, ms, sect, "__DATA_CONST")
   696  	}
   697  
   698  	/* data */
   699  	if ctxt.LinkMode != LinkExternal {
   700  		ms = newMachoSeg("__DATA", 20)
   701  		ms.vaddr = Segdata.Vaddr
   702  		ms.vsize = Segdata.Length
   703  		ms.fileoffset = Segdata.Fileoff
   704  		ms.filesize = Segdata.Filelen
   705  		ms.prot1 = 3
   706  		ms.prot2 = 3
   707  	}
   708  
   709  	for _, sect := range Segdata.Sections {
   710  		machoshbits(ctxt, ms, sect, "__DATA")
   711  	}
   712  
   713  	/* dwarf */
   714  	if !*FlagW && !(*FlagSplitDWARF && ctxt.IsInternal()) {
   715  		if ctxt.LinkMode != LinkExternal {
   716  			ms = newMachoSeg("__DWARF", 20)
   717  			ms.vaddr = Segdwarf.Vaddr
   718  			ms.vsize = 0
   719  			ms.fileoffset = Segdwarf.Fileoff
   720  			ms.filesize = Segdwarf.Filelen
   721  		}
   722  		for _, sect := range Segdwarf.Sections {
   723  			machoshbits(ctxt, ms, sect, "__DWARF")
   724  		}
   725  	}
   726  
   727  	if ctxt.LinkMode != LinkExternal {
   728  		switch ctxt.Arch.Family {
   729  		default:
   730  			Exitf("unknown macho architecture: %v", ctxt.Arch.Family)
   731  
   732  		case sys.AMD64:
   733  			ml := newMachoLoad(ctxt.Arch, imacho.LC_UNIXTHREAD, 42+2)
   734  			ml.data[0] = 4                           /* thread type */
   735  			ml.data[1] = 42                          /* word count */
   736  			ml.data[2+32] = uint32(Entryvalue(ctxt)) /* start pc */
   737  			ml.data[2+32+1] = uint32(Entryvalue(ctxt) >> 32)
   738  
   739  		case sys.ARM64:
   740  			ml := newMachoLoad(ctxt.Arch, imacho.LC_MAIN, 4)
   741  			ml.data[0] = uint32(uint64(Entryvalue(ctxt)) - (Segtext.Vaddr - uint64(HEADR)))
   742  			ml.data[1] = uint32((uint64(Entryvalue(ctxt)) - (Segtext.Vaddr - uint64(HEADR))) >> 32)
   743  		}
   744  	}
   745  
   746  	var codesigOff int64
   747  	// must match doMachoLink below
   748  	s1 := ldr.SymSize(ldr.Lookup(".machorebase", 0))
   749  	s2 := ldr.SymSize(ldr.Lookup(".machobind", 0))
   750  	s3 := ldr.SymSize(ldr.Lookup(".machosymtab", 0))
   751  	s4 := ldr.SymSize(ctxt.ArchSyms.LinkEditPLT)
   752  	s5 := ldr.SymSize(ctxt.ArchSyms.LinkEditGOT)
   753  	s6 := ldr.SymSize(ldr.Lookup(".machosymstr", 0))
   754  	padding := Rnd(s1+s2+s3+s4+s5+s6, 16) - (s1 + s2 + s3 + s4 + s5 + s6) // 16-byte alignment for code signature, see doMachoLink below
   755  	s7 := ldr.SymSize(ldr.Lookup(".machocodesig", 0))
   756  
   757  	if ctxt.LinkMode != LinkExternal {
   758  		ms := newMachoSeg("__LINKEDIT", 0)
   759  		ms.vaddr = uint64(Rnd(int64(Segdata.Vaddr+Segdata.Length), *FlagRound))
   760  		ms.vsize = uint64(s1 + s2 + s3 + s4 + s5 + s6 + padding + s7)
   761  		ms.fileoffset = uint64(linkoff)
   762  		ms.filesize = ms.vsize
   763  		ms.prot1 = 1
   764  		ms.prot2 = 1
   765  
   766  		codesigOff = linkoff + s1 + s2 + s3 + s4 + s5 + s6 + padding
   767  	}
   768  
   769  	if ctxt.LinkMode != LinkExternal && ctxt.IsPIE() {
   770  		ml := newMachoLoad(ctxt.Arch, imacho.LC_DYLD_INFO_ONLY, 10)
   771  		ml.data[0] = uint32(linkoff)      // rebase off
   772  		ml.data[1] = uint32(s1)           // rebase size
   773  		ml.data[2] = uint32(linkoff + s1) // bind off
   774  		ml.data[3] = uint32(s2)           // bind size
   775  		ml.data[4] = 0                    // weak bind off
   776  		ml.data[5] = 0                    // weak bind size
   777  		ml.data[6] = 0                    // lazy bind off
   778  		ml.data[7] = 0                    // lazy bind size
   779  		ml.data[8] = 0                    // export
   780  		ml.data[9] = 0                    // export size
   781  	}
   782  
   783  	ml := newMachoLoad(ctxt.Arch, imacho.LC_SYMTAB, 4)
   784  	ml.data[0] = uint32(linkoff + s1 + s2)                /* symoff */
   785  	ml.data[1] = uint32(nsortsym)                         /* nsyms */
   786  	ml.data[2] = uint32(linkoff + s1 + s2 + s3 + s4 + s5) /* stroff */
   787  	ml.data[3] = uint32(s6)                               /* strsize */
   788  
   789  	if ctxt.LinkMode != LinkExternal {
   790  		machodysymtab(ctxt, linkoff+s1+s2)
   791  
   792  		ml := newMachoLoad(ctxt.Arch, imacho.LC_LOAD_DYLINKER, 6)
   793  		ml.data[0] = 12 /* offset to string */
   794  		stringtouint32(ml.data[1:], "/usr/lib/dyld")
   795  
   796  		for _, lib := range dylib {
   797  			ml = newMachoLoad(ctxt.Arch, imacho.LC_LOAD_DYLIB, 4+(uint32(len(lib))+1+7)/8*2)
   798  			ml.data[0] = 24 /* offset of string from beginning of load */
   799  			ml.data[1] = 0  /* time stamp */
   800  			ml.data[2] = 0  /* version */
   801  			ml.data[3] = 0  /* compatibility version */
   802  			stringtouint32(ml.data[4:], lib)
   803  		}
   804  	}
   805  
   806  	if ctxt.IsInternal() && *flagHostBuildid != "none" {
   807  		ml := newMachoLoad(ctxt.Arch, imacho.LC_UUID, 4)
   808  		var uuid [16]byte
   809  		if len(buildinfo) >= 16 {
   810  			copy(uuid[:], buildinfo)
   811  		} else {
   812  			// Note: When setting macSDK to 26.2, dyld refuses to run any
   813  			// binary without an LC_UUID, which makes bootstrap fail.
   814  			// To work around that situation, if buildinfo is missing we
   815  			// construct a hash of the binary written so far and use that.
   816  			// Using -B none will bypass this if desired,
   817  			// but the resulting binary may not be runnable.
   818  			copy(uuid[:], uuidFromHash(hash.Sum32(ctxt.Out.Data())))
   819  		}
   820  		ml.data[0] = ctxt.Arch.ByteOrder.Uint32(uuid[0:])
   821  		ml.data[1] = ctxt.Arch.ByteOrder.Uint32(uuid[4:])
   822  		ml.data[2] = ctxt.Arch.ByteOrder.Uint32(uuid[8:])
   823  		ml.data[3] = ctxt.Arch.ByteOrder.Uint32(uuid[12:])
   824  	}
   825  
   826  	if ctxt.IsInternal() && ctxt.NeedCodeSign() {
   827  		ml := newMachoLoad(ctxt.Arch, imacho.LC_CODE_SIGNATURE, 2)
   828  		ml.data[0] = uint32(codesigOff)
   829  		ml.data[1] = uint32(s7)
   830  	}
   831  
   832  	a := machowrite(ctxt, ctxt.Arch, ctxt.Out, ctxt.LinkMode)
   833  	if int32(a) > HEADR {
   834  		Exitf("HEADR too small: %d > %d", a, HEADR)
   835  	}
   836  
   837  	// Now we have written everything. Compute the code signature (which
   838  	// is a hash of the file content, so it must be done at last.)
   839  	if ctxt.IsInternal() && ctxt.NeedCodeSign() {
   840  		cs := ldr.Lookup(".machocodesig", 0)
   841  		data := ctxt.Out.Data()
   842  		if int64(len(data)) != codesigOff {
   843  			panic("wrong size")
   844  		}
   845  		codesign.Sign(ldr.Data(cs), bytes.NewBuffer(data), "a.out", codesigOff, int64(mstext.fileoffset), int64(mstext.filesize), ctxt.IsExe() || ctxt.IsPIE())
   846  		ctxt.Out.SeekSet(codesigOff)
   847  		ctxt.Out.Write(ldr.Data(cs))
   848  	}
   849  
   850  	if *FlagSplitDWARF && ctxt.IsInternal() {
   851  		// Segment order when split DWARF is used, in both virtual address
   852  		// and file layout:
   853  		// - Mapped segments (__PAGEZERO, __TEXT, __DATA, etc.)
   854  		//   - Main binary: contains content in file.
   855  		//   - DWARF file: no content, just header listing virtual address.
   856  		// - __LINKEDIT
   857  		//   - Main binary: symbol table, dyld info, etc.
   858  		//   - DWARF file: start at same virtual address, but shorter,
   859  		//     contains only symbol table.
   860  		// - __DWARF
   861  		//   - DWARF file only.
   862  
   863  		// Write the __LINKEDIT segment (symbol table).
   864  		symtab := ldr.Lookup(".machosymtab", 0)
   865  		symstr := ldr.Lookup(".machosymstr", 0)
   866  		symtabSz := ldr.SymSize(symtab)
   867  		symstrSz := ldr.SymSize(symstr)
   868  		linkeditOff := Rnd(int64(HEADR), *FlagRound)
   869  		ctxt.OutDWARF.SeekSet(linkeditOff)
   870  		ctxt.OutDWARF.Write(ldr.Data(symtab))
   871  		ctxt.OutDWARF.Write(ldr.Data(symstr))
   872  		if Rnd(ctxt.OutDWARF.Offset(), *FlagRound) != int64(Segdwarf.Fileoff) {
   873  			panic("splitdwarf __LINKEDIT size mismatch")
   874  		}
   875  		ctxt.OutDWARF.SeekSet(0)
   876  
   877  		for i := range seg[:nseg] {
   878  			s := &seg[i]
   879  			if s.name == "__LINKEDIT" {
   880  				s.vsize = uint64(symtabSz + symstrSz)
   881  				s.fileoffset = uint64(linkeditOff)
   882  				s.filesize = s.vsize
   883  				continue
   884  			}
   885  			// The split DWARF file does not need the content of the segments
   886  			s.fileoffset = 0
   887  			s.filesize = 0
   888  			for j := range s.nsect {
   889  				s.sect[j].off = 0
   890  			}
   891  		}
   892  
   893  		ms := newMachoSeg("__DWARF", 20)
   894  		ms.vaddr = Segdwarf.Vaddr
   895  		ms.vsize = Segdwarf.Length
   896  		ms.fileoffset = Segdwarf.Fileoff
   897  		ms.filesize = Segdwarf.Filelen
   898  		ms.prot1 = 7
   899  		ms.prot2 = 3
   900  		for _, sect := range Segdwarf.Sections {
   901  			machoshbits(ctxt, ms, sect, "__DWARF")
   902  		}
   903  
   904  		// Keep only LC_BUILD_VERSION, LC_UUID, and LC_SYMTAB, dropping load
   905  		// commands specific to the executable (LC_MAIN, LC_DYLD_INFO_ONLY, etc.).
   906  		load = slices.DeleteFunc(load, func(l MachoLoad) bool {
   907  			return l.type_ != imacho.LC_BUILD_VERSION && l.type_ != imacho.LC_UUID && l.type_ != imacho.LC_SYMTAB
   908  		})
   909  		for i := range load {
   910  			if load[i].type_ == imacho.LC_SYMTAB {
   911  				load[i].data[0] = uint32(linkeditOff)            /* symoff */
   912  				load[i].data[1] = uint32(nsortsym)               /* nsyms */
   913  				load[i].data[2] = uint32(linkeditOff + symtabSz) /* stroff */
   914  				load[i].data[3] = uint32(symstrSz)               /* strsize */
   915  			}
   916  		}
   917  
   918  		a := machowrite(ctxt, ctxt.Arch, ctxt.OutDWARF, ctxt.LinkMode)
   919  		if int32(a) > HEADR {
   920  			Exitf("HEADR too small: %d > %d", a, HEADR)
   921  		}
   922  	}
   923  }
   924  
   925  func symkind(ldr *loader.Loader, s loader.Sym) int {
   926  	if t := ldr.SymType(s); t == sym.SDYNIMPORT || t == sym.SHOSTOBJ || t == sym.SUNDEFEXT {
   927  		return SymKindUndef
   928  	}
   929  	if ldr.AttrCgoExport(s) {
   930  		return SymKindExtdef
   931  	}
   932  	return SymKindLocal
   933  }
   934  
   935  func collectmachosyms(ctxt *Link) {
   936  	ldr := ctxt.loader
   937  
   938  	addsym := func(s loader.Sym) {
   939  		sortsym = append(sortsym, s)
   940  		nkind[symkind(ldr, s)]++
   941  	}
   942  
   943  	// On Mach-O, even with -s, we still need to keep dynamically exported and
   944  	// referenced symbols. We can strip defined local text and data symbols.
   945  	// So *FlagS is applied based on symbol type.
   946  
   947  	// Add special runtime.text and runtime.etext symbols (which are local).
   948  	// We've already included this symbol in Textp on darwin if ctxt.DynlinkingGo().
   949  	// See data.go:/textaddress
   950  	// NOTE: runtime.text.N symbols (if we split text sections) are not added, though,
   951  	// so we handle them here.
   952  	if !*FlagS {
   953  		if !ctxt.DynlinkingGo() {
   954  			s := ldr.Lookup("runtime.text", 0)
   955  			if ldr.SymType(s).IsText() {
   956  				addsym(s)
   957  			}
   958  		}
   959  		for n := range Segtext.Sections[1:] {
   960  			s := ldr.Lookup(fmt.Sprintf("runtime.text.%d", n+1), 0)
   961  			if s != 0 {
   962  				addsym(s)
   963  			} else {
   964  				break
   965  			}
   966  		}
   967  		if !ctxt.DynlinkingGo() {
   968  			s := ldr.Lookup("runtime.etext", 0)
   969  			if ldr.SymType(s).IsText() {
   970  				addsym(s)
   971  			}
   972  		}
   973  	}
   974  
   975  	// Add text symbols.
   976  	for _, s := range ctxt.Textp {
   977  		if *FlagS && !ldr.AttrCgoExportDynamic(s) {
   978  			continue
   979  		}
   980  		addsym(s)
   981  	}
   982  
   983  	shouldBeInSymbolTable := func(s loader.Sym) bool {
   984  		if ldr.AttrNotInSymbolTable(s) {
   985  			return false
   986  		}
   987  		name := ldr.SymName(s) // TODO: try not to read the name
   988  		if name == "" || name[0] == '.' {
   989  			return false
   990  		}
   991  		return true
   992  	}
   993  
   994  	// Add data symbols and external references.
   995  	for s := loader.Sym(1); s < loader.Sym(ldr.NSym()); s++ {
   996  		if !ldr.AttrReachable(s) {
   997  			continue
   998  		}
   999  		t := ldr.SymType(s)
  1000  		if t >= sym.SELFRXSECT && t < sym.SFirstUnallocated { // data sections handled in dodata
  1001  			if t == sym.STLSBSS {
  1002  				// TLSBSS is not used on darwin. See data.go:allocateDataSections
  1003  				continue
  1004  			}
  1005  			if !shouldBeInSymbolTable(s) {
  1006  				continue
  1007  			}
  1008  			if *FlagS && !ldr.AttrCgoExportDynamic(s) {
  1009  				continue
  1010  			}
  1011  			addsym(s)
  1012  			continue
  1013  		}
  1014  
  1015  		switch t {
  1016  		case sym.SDYNIMPORT, sym.SHOSTOBJ, sym.SUNDEFEXT:
  1017  			// Keep dynamic symbol references even if *FlagS.
  1018  			addsym(s)
  1019  		}
  1020  
  1021  		// Some 64-bit functions have a "$INODE64" or "$INODE64$UNIX2003" suffix.
  1022  		if t == sym.SDYNIMPORT && ldr.SymDynimplib(s) == "/usr/lib/libSystem.B.dylib" {
  1023  			// But only on macOS.
  1024  			if machoPlatform == PLATFORM_MACOS || machoPlatform == PLATFORM_MACCATALYST {
  1025  				switch n := ldr.SymExtname(s); n {
  1026  				case "fdopendir":
  1027  					switch buildcfg.GOARCH {
  1028  					case "amd64":
  1029  						ldr.SetSymExtname(s, n+"$INODE64")
  1030  					}
  1031  				case "readdir_r", "getfsstat":
  1032  					switch buildcfg.GOARCH {
  1033  					case "amd64":
  1034  						ldr.SetSymExtname(s, n+"$INODE64")
  1035  					}
  1036  				}
  1037  			}
  1038  		}
  1039  	}
  1040  
  1041  	nsortsym = len(sortsym)
  1042  }
  1043  
  1044  func machosymorder(ctxt *Link) {
  1045  	ldr := ctxt.loader
  1046  
  1047  	// On Mac OS X Mountain Lion, we must sort exported symbols
  1048  	// So we sort them here and pre-allocate dynid for them
  1049  	// See https://golang.org/issue/4029
  1050  	for _, s := range ctxt.dynexp {
  1051  		if !ldr.AttrReachable(s) {
  1052  			panic("dynexp symbol is not reachable")
  1053  		}
  1054  	}
  1055  	collectmachosyms(ctxt)
  1056  	sort.Slice(sortsym[:nsortsym], func(i, j int) bool {
  1057  		s1 := sortsym[i]
  1058  		s2 := sortsym[j]
  1059  		k1 := symkind(ldr, s1)
  1060  		k2 := symkind(ldr, s2)
  1061  		if k1 != k2 {
  1062  			return k1 < k2
  1063  		}
  1064  		return ldr.SymExtname(s1) < ldr.SymExtname(s2) // Note: unnamed symbols are not added in collectmachosyms
  1065  	})
  1066  	for i, s := range sortsym {
  1067  		ldr.SetSymDynid(s, int32(i))
  1068  	}
  1069  }
  1070  
  1071  // AddMachoSym adds s to Mach-O symbol table, used in GenSymLate.
  1072  // Currently only used on ARM64 when external linking.
  1073  func AddMachoSym(ctxt *Link, s loader.Sym) {
  1074  	ldr := ctxt.loader
  1075  	ldr.SetSymDynid(s, int32(nsortsym))
  1076  	sortsym = append(sortsym, s)
  1077  	nsortsym++
  1078  	nkind[symkind(ldr, s)]++
  1079  	symtab := ldr.CreateSymForUpdate(".machosymtab", 0)
  1080  	symstr := ldr.CreateSymForUpdate(".machosymstr", 0)
  1081  	machosymtab1(ctxt, symtab, symstr, s)
  1082  }
  1083  
  1084  // machoShouldExport reports whether a symbol needs to be exported.
  1085  //
  1086  // When dynamically linking, all non-local variables and plugin-exported
  1087  // symbols need to be exported.
  1088  func machoShouldExport(ctxt *Link, ldr *loader.Loader, s loader.Sym) bool {
  1089  	if !ctxt.DynlinkingGo() || ldr.AttrLocal(s) || (ldr.IsContentHashed(s) && ldr.SymType(s).IsText()) {
  1090  		return false
  1091  	}
  1092  	if ctxt.BuildMode == BuildModePlugin && strings.HasPrefix(ldr.SymExtname(s), objabi.PathToPrefix(*flagPluginPath)) {
  1093  		return true
  1094  	}
  1095  	name := ldr.SymName(s)
  1096  	if strings.HasPrefix(name, "go:itab.") {
  1097  		return true
  1098  	}
  1099  	if strings.HasPrefix(name, "type:") && !strings.HasPrefix(name, "type:.") {
  1100  		// reduce runtime typemap pressure, but do not
  1101  		// export alg functions (type:.*), as these
  1102  		// appear in pclntable.
  1103  		return true
  1104  	}
  1105  	if strings.HasPrefix(name, "go:link.pkghash") {
  1106  		return true
  1107  	}
  1108  	return ldr.SymType(s) >= sym.SFirstWritable // only writable sections
  1109  }
  1110  
  1111  func machosymtab(ctxt *Link) {
  1112  	ldr := ctxt.loader
  1113  	symtab := ldr.CreateSymForUpdate(".machosymtab", 0)
  1114  	symstr := ldr.CreateSymForUpdate(".machosymstr", 0)
  1115  
  1116  	for _, s := range sortsym[:nsortsym] {
  1117  		machosymtab1(ctxt, symtab, symstr, s)
  1118  	}
  1119  }
  1120  
  1121  func machosymtab1(ctxt *Link, symtab, symstr *loader.SymbolBuilder, s loader.Sym) {
  1122  	ldr := ctxt.loader
  1123  	symtab.AddUint32(ctxt.Arch, uint32(symstr.Size()))
  1124  
  1125  	export := machoShouldExport(ctxt, ldr, s)
  1126  
  1127  	// Prefix symbol names with "_" to match the system toolchain.
  1128  	// (We used to only prefix C symbols, which is all required for the build.
  1129  	// But some tools don't recognize Go symbols as symbols, so we prefix them
  1130  	// as well.)
  1131  	symstr.AddUint8('_')
  1132  
  1133  	// replace "·" as ".", because DTrace cannot handle it.
  1134  	name := strings.ReplaceAll(ldr.SymExtname(s), "·", ".")
  1135  
  1136  	name = mangleABIName(ctxt, ldr, s, name)
  1137  	symstr.Addstring(name)
  1138  
  1139  	if t := ldr.SymType(s); t == sym.SDYNIMPORT || t == sym.SHOSTOBJ || t == sym.SUNDEFEXT {
  1140  		symtab.AddUint8(0x01)                             // type N_EXT, external symbol
  1141  		symtab.AddUint8(0)                                // no section
  1142  		symtab.AddUint16(ctxt.Arch, 0)                    // desc
  1143  		symtab.AddUintXX(ctxt.Arch, 0, ctxt.Arch.PtrSize) // no value
  1144  	} else {
  1145  		if export || ldr.AttrCgoExportDynamic(s) {
  1146  			symtab.AddUint8(0x0f) // N_SECT | N_EXT
  1147  		} else if ldr.AttrCgoExportStatic(s) {
  1148  			// Only export statically, not dynamically. (N_PEXT is like hidden visibility)
  1149  			symtab.AddUint8(0x1f) // N_SECT | N_EXT | N_PEXT
  1150  		} else {
  1151  			symtab.AddUint8(0x0e) // N_SECT
  1152  		}
  1153  		o := s
  1154  		if outer := ldr.OuterSym(o); outer != 0 {
  1155  			o = outer
  1156  		}
  1157  		if ldr.SymSect(o) == nil {
  1158  			ldr.Errorf(s, "missing section for symbol")
  1159  			symtab.AddUint8(0)
  1160  		} else {
  1161  			symtab.AddUint8(uint8(ldr.SymSect(o).Extnum))
  1162  		}
  1163  		symtab.AddUint16(ctxt.Arch, 0) // desc
  1164  		symtab.AddUintXX(ctxt.Arch, uint64(ldr.SymAddr(s)), ctxt.Arch.PtrSize)
  1165  	}
  1166  }
  1167  
  1168  func machodysymtab(ctxt *Link, base int64) {
  1169  	ml := newMachoLoad(ctxt.Arch, imacho.LC_DYSYMTAB, 18)
  1170  
  1171  	n := 0
  1172  	ml.data[0] = uint32(n)                   /* ilocalsym */
  1173  	ml.data[1] = uint32(nkind[SymKindLocal]) /* nlocalsym */
  1174  	n += nkind[SymKindLocal]
  1175  
  1176  	ml.data[2] = uint32(n)                    /* iextdefsym */
  1177  	ml.data[3] = uint32(nkind[SymKindExtdef]) /* nextdefsym */
  1178  	n += nkind[SymKindExtdef]
  1179  
  1180  	ml.data[4] = uint32(n)                   /* iundefsym */
  1181  	ml.data[5] = uint32(nkind[SymKindUndef]) /* nundefsym */
  1182  
  1183  	ml.data[6] = 0  /* tocoffset */
  1184  	ml.data[7] = 0  /* ntoc */
  1185  	ml.data[8] = 0  /* modtaboff */
  1186  	ml.data[9] = 0  /* nmodtab */
  1187  	ml.data[10] = 0 /* extrefsymoff */
  1188  	ml.data[11] = 0 /* nextrefsyms */
  1189  
  1190  	ldr := ctxt.loader
  1191  
  1192  	// must match domacholink below
  1193  	s1 := ldr.SymSize(ldr.Lookup(".machosymtab", 0))
  1194  	s2 := ldr.SymSize(ctxt.ArchSyms.LinkEditPLT)
  1195  	s3 := ldr.SymSize(ctxt.ArchSyms.LinkEditGOT)
  1196  	ml.data[12] = uint32(base + s1)     /* indirectsymoff */
  1197  	ml.data[13] = uint32((s2 + s3) / 4) /* nindirectsyms */
  1198  
  1199  	ml.data[14] = 0 /* extreloff */
  1200  	ml.data[15] = 0 /* nextrel */
  1201  	ml.data[16] = 0 /* locreloff */
  1202  	ml.data[17] = 0 /* nlocrel */
  1203  }
  1204  
  1205  func doMachoLink(ctxt *Link) int64 {
  1206  	machoDyldInfo(ctxt)
  1207  
  1208  	ldr := ctxt.loader
  1209  
  1210  	// write data that will be linkedit section
  1211  	s1 := ldr.Lookup(".machorebase", 0)
  1212  	s2 := ldr.Lookup(".machobind", 0)
  1213  	s3 := ldr.Lookup(".machosymtab", 0)
  1214  	s4 := ctxt.ArchSyms.LinkEditPLT
  1215  	s5 := ctxt.ArchSyms.LinkEditGOT
  1216  	s6 := ldr.Lookup(".machosymstr", 0)
  1217  
  1218  	size := ldr.SymSize(s1) + ldr.SymSize(s2) + ldr.SymSize(s3) + ldr.SymSize(s4) + ldr.SymSize(s5) + ldr.SymSize(s6)
  1219  
  1220  	if size > 0 {
  1221  		linkoff = Rnd(int64(uint64(HEADR)+Segtext.Length), *FlagRound) + Rnd(int64(Segrelrodata.Filelen), *FlagRound) + Rnd(int64(Segdata.Filelen), *FlagRound)
  1222  		if !(*FlagSplitDWARF && ctxt.IsInternal()) {
  1223  			linkoff += Rnd(int64(Segdwarf.Filelen), *FlagRound)
  1224  		}
  1225  		ctxt.Out.SeekSet(linkoff)
  1226  
  1227  		ctxt.Out.Write(ldr.Data(s1))
  1228  		ctxt.Out.Write(ldr.Data(s2))
  1229  		ctxt.Out.Write(ldr.Data(s3))
  1230  		ctxt.Out.Write(ldr.Data(s4))
  1231  		ctxt.Out.Write(ldr.Data(s5))
  1232  		ctxt.Out.Write(ldr.Data(s6))
  1233  
  1234  		// Force the linkedit section to end on a 16-byte
  1235  		// boundary. This allows pure (non-cgo) Go binaries
  1236  		// to be code signed correctly.
  1237  		//
  1238  		// Apple's codesign_allocate (a helper utility for
  1239  		// the codesign utility) can do this fine itself if
  1240  		// it is run on a dynamic Mach-O binary. However,
  1241  		// when it is run on a pure (non-cgo) Go binary, where
  1242  		// the linkedit section is mostly empty, it fails to
  1243  		// account for the extra padding that it itself adds
  1244  		// when adding the LC_CODE_SIGNATURE load command
  1245  		// (which must be aligned on a 16-byte boundary).
  1246  		//
  1247  		// By forcing the linkedit section to end on a 16-byte
  1248  		// boundary, codesign_allocate will not need to apply
  1249  		// any alignment padding itself, working around the
  1250  		// issue.
  1251  		if size%16 != 0 {
  1252  			n := 16 - size%16
  1253  			ctxt.Out.Write(zeros[:n])
  1254  			size += n
  1255  		}
  1256  
  1257  		// Add code signature if necessary. This must be the last.
  1258  		s7 := machoCodeSigSym(ctxt, linkoff+size)
  1259  		size += ldr.SymSize(s7)
  1260  	}
  1261  
  1262  	return Rnd(size, *FlagRound)
  1263  }
  1264  
  1265  func machorelocsect(ctxt *Link, out *OutBuf, sect *sym.Section, syms []loader.Sym) {
  1266  	// If main section has no bits, nothing to relocate.
  1267  	if sect.Vaddr >= sect.Seg.Vaddr+sect.Seg.Filelen {
  1268  		return
  1269  	}
  1270  	ldr := ctxt.loader
  1271  
  1272  	for i, s := range syms {
  1273  		if !ldr.AttrReachable(s) {
  1274  			continue
  1275  		}
  1276  		if uint64(ldr.SymValue(s)) >= sect.Vaddr {
  1277  			syms = syms[i:]
  1278  			break
  1279  		}
  1280  	}
  1281  
  1282  	eaddr := sect.Vaddr + sect.Length
  1283  	for _, s := range syms {
  1284  		if !ldr.AttrReachable(s) {
  1285  			continue
  1286  		}
  1287  		if ldr.SymValue(s) >= int64(eaddr) {
  1288  			break
  1289  		}
  1290  
  1291  		// Compute external relocations on the go, and pass to Machoreloc1
  1292  		// to stream out.
  1293  		relocs := ldr.Relocs(s)
  1294  		for ri := 0; ri < relocs.Count(); ri++ {
  1295  			r := relocs.At(ri)
  1296  			rr, ok := extreloc(ctxt, ldr, s, r)
  1297  			if !ok {
  1298  				continue
  1299  			}
  1300  			if rr.Xsym == 0 {
  1301  				ldr.Errorf(s, "missing xsym in relocation")
  1302  				continue
  1303  			}
  1304  			if !ldr.AttrReachable(rr.Xsym) {
  1305  				ldr.Errorf(s, "unreachable reloc %d (%s) target %v", r.Type(), sym.RelocName(ctxt.Arch, r.Type()), ldr.SymName(rr.Xsym))
  1306  			}
  1307  			if !thearch.Machoreloc1(ctxt.Arch, out, ldr, s, rr, int64(uint64(ldr.SymValue(s)+int64(r.Off()))-sect.Vaddr)) {
  1308  				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()))
  1309  			}
  1310  		}
  1311  	}
  1312  
  1313  	// sanity check
  1314  	if uint64(out.Offset()) != sect.Reloff+sect.Rellen {
  1315  		panic("machorelocsect: size mismatch")
  1316  	}
  1317  }
  1318  
  1319  func machoEmitReloc(ctxt *Link) {
  1320  	for ctxt.Out.Offset()&7 != 0 {
  1321  		ctxt.Out.Write8(0)
  1322  	}
  1323  
  1324  	sizeExtRelocs(ctxt, thearch.MachorelocSize)
  1325  	relocSect, wg := relocSectFn(ctxt, machorelocsect)
  1326  
  1327  	relocSect(ctxt, Segtext.Sections[0], ctxt.Textp)
  1328  	for _, sect := range Segtext.Sections[1:] {
  1329  		if sect.Name == ".text" {
  1330  			relocSect(ctxt, sect, ctxt.Textp)
  1331  		} else {
  1332  			relocSect(ctxt, sect, ctxt.datap)
  1333  		}
  1334  	}
  1335  	for _, sect := range Segrelrodata.Sections {
  1336  		relocSect(ctxt, sect, ctxt.datap)
  1337  	}
  1338  	for _, sect := range Segdata.Sections {
  1339  		relocSect(ctxt, sect, ctxt.datap)
  1340  	}
  1341  	for i := 0; i < len(Segdwarf.Sections); i++ {
  1342  		sect := Segdwarf.Sections[i]
  1343  		si := dwarfp[i]
  1344  		if si.secSym() != sect.Sym ||
  1345  			ctxt.loader.SymSect(si.secSym()) != sect {
  1346  			panic("inconsistency between dwarfp and Segdwarf")
  1347  		}
  1348  		relocSect(ctxt, sect, si.syms)
  1349  	}
  1350  	wg.Wait()
  1351  }
  1352  
  1353  // hostobjMachoPlatform returns the first platform load command found
  1354  // in the host object, if any.
  1355  func hostobjMachoPlatform(h *Hostobj) (*MachoPlatformLoad, error) {
  1356  	f, err := os.Open(h.file)
  1357  	if err != nil {
  1358  		return nil, fmt.Errorf("%s: failed to open host object: %v\n", h.file, err)
  1359  	}
  1360  	defer f.Close()
  1361  	sr := io.NewSectionReader(f, h.off, h.length)
  1362  	m, err := macho.NewFile(sr)
  1363  	if err != nil {
  1364  		// Not a valid Mach-O file.
  1365  		return nil, nil
  1366  	}
  1367  	return peekMachoPlatform(m)
  1368  }
  1369  
  1370  // peekMachoPlatform returns the first LC_VERSION_MIN_* or LC_BUILD_VERSION
  1371  // load command found in the Mach-O file, if any.
  1372  func peekMachoPlatform(m *macho.File) (*MachoPlatformLoad, error) {
  1373  	for _, cmd := range m.Loads {
  1374  		raw := cmd.Raw()
  1375  		ml := MachoLoad{
  1376  			type_: m.ByteOrder.Uint32(raw),
  1377  		}
  1378  		// Skip the type and command length.
  1379  		data := raw[8:]
  1380  		var p MachoPlatform
  1381  		switch ml.type_ {
  1382  		case imacho.LC_VERSION_MIN_IPHONEOS:
  1383  			p = PLATFORM_IOS
  1384  		case imacho.LC_VERSION_MIN_MACOSX:
  1385  			p = PLATFORM_MACOS
  1386  		case imacho.LC_VERSION_MIN_WATCHOS:
  1387  			p = PLATFORM_WATCHOS
  1388  		case imacho.LC_VERSION_MIN_TVOS:
  1389  			p = PLATFORM_TVOS
  1390  		case imacho.LC_BUILD_VERSION:
  1391  			p = MachoPlatform(m.ByteOrder.Uint32(data))
  1392  		default:
  1393  			continue
  1394  		}
  1395  		ml.data = make([]uint32, len(data)/4)
  1396  		r := bytes.NewReader(data)
  1397  		if err := binary.Read(r, m.ByteOrder, &ml.data); err != nil {
  1398  			return nil, err
  1399  		}
  1400  		return &MachoPlatformLoad{
  1401  			platform: p,
  1402  			cmd:      ml,
  1403  		}, nil
  1404  	}
  1405  	return nil, nil
  1406  }
  1407  
  1408  // A rebase entry tells the dynamic linker the data at sym+off needs to be
  1409  // relocated when the in-memory image moves. (This is somewhat like, say,
  1410  // ELF R_X86_64_RELATIVE).
  1411  // For now, the only kind of entry we support is that the data is an absolute
  1412  // address. That seems all we need.
  1413  // In the binary it uses a compact stateful bytecode encoding. So we record
  1414  // entries as we go and build the table at the end.
  1415  type machoRebaseRecord struct {
  1416  	sym loader.Sym
  1417  	off int64
  1418  }
  1419  
  1420  var machorebase []machoRebaseRecord
  1421  
  1422  func MachoAddRebase(s loader.Sym, off int64) {
  1423  	machorebase = append(machorebase, machoRebaseRecord{s, off})
  1424  }
  1425  
  1426  // A bind entry tells the dynamic linker the data at sym+off should be bound
  1427  // to the address of the target symbol, which is a dynamic import.
  1428  // sym is the symbol containing the pointer (e.g. the GOT or a data symbol),
  1429  // off is the offset within that symbol, and targ is the dynamic import target.
  1430  // For now, the only kind of entry we support is that the data is an absolute
  1431  // address. That seems all we need.
  1432  // In the binary it uses a compact stateful bytecode encoding. So we record
  1433  // entries as we go and build the table at the end.
  1434  type machoBindRecord struct {
  1435  	sym  loader.Sym
  1436  	off  int64
  1437  	targ loader.Sym
  1438  }
  1439  
  1440  var machobind []machoBindRecord
  1441  
  1442  func MachoAddBind(sym loader.Sym, off int64, targ loader.Sym) {
  1443  	machobind = append(machobind, machoBindRecord{sym, off, targ})
  1444  }
  1445  
  1446  // Generate data for the dynamic linker, used in LC_DYLD_INFO_ONLY load command.
  1447  // See mach-o/loader.h, struct dyld_info_command, for the encoding.
  1448  // e.g. https://opensource.apple.com/source/xnu/xnu-6153.81.5/EXTERNAL_HEADERS/mach-o/loader.h
  1449  func machoDyldInfo(ctxt *Link) {
  1450  	ldr := ctxt.loader
  1451  	rebase := ldr.CreateSymForUpdate(".machorebase", 0)
  1452  	bind := ldr.CreateSymForUpdate(".machobind", 0)
  1453  
  1454  	if !(ctxt.IsPIE() && ctxt.IsInternal()) {
  1455  		return
  1456  	}
  1457  
  1458  	segId := func(seg *sym.Segment) uint8 {
  1459  		switch seg {
  1460  		case &Segtext:
  1461  			return 1
  1462  		case &Segrelrodata:
  1463  			return 2
  1464  		case &Segdata:
  1465  			if Segrelrodata.Length > 0 {
  1466  				return 3
  1467  			}
  1468  			return 2
  1469  		}
  1470  		panic("unknown segment")
  1471  	}
  1472  
  1473  	dylibId := func(s loader.Sym) int {
  1474  		slib := ldr.SymDynimplib(s)
  1475  		for i, lib := range dylib {
  1476  			if lib == slib {
  1477  				return i + 1
  1478  			}
  1479  		}
  1480  		return BIND_SPECIAL_DYLIB_FLAT_LOOKUP // don't know where it is from
  1481  	}
  1482  
  1483  	// Rebase table.
  1484  	// TODO: use more compact encoding. The encoding is stateful, and
  1485  	// we can use delta encoding.
  1486  	rebase.AddUint8(REBASE_OPCODE_SET_TYPE_IMM | REBASE_TYPE_POINTER)
  1487  	for _, r := range machorebase {
  1488  		seg := ldr.SymSect(r.sym).Seg
  1489  		off := uint64(ldr.SymValue(r.sym)+r.off) - seg.Vaddr
  1490  		rebase.AddUint8(REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | segId(seg))
  1491  		rebase.AddUleb(off)
  1492  
  1493  		rebase.AddUint8(REBASE_OPCODE_DO_REBASE_IMM_TIMES | 1)
  1494  	}
  1495  	rebase.AddUint8(REBASE_OPCODE_DONE)
  1496  	sz := Rnd(rebase.Size(), 8)
  1497  	rebase.Grow(sz)
  1498  	rebase.SetSize(sz)
  1499  
  1500  	// Bind table.
  1501  	// TODO: compact encoding, as above.
  1502  	// TODO: lazy binding?
  1503  	bind.AddUint8(BIND_OPCODE_SET_TYPE_IMM | BIND_TYPE_POINTER)
  1504  	for _, r := range machobind {
  1505  		seg := ldr.SymSect(r.sym).Seg
  1506  		off := uint64(ldr.SymValue(r.sym)+r.off) - seg.Vaddr
  1507  		bind.AddUint8(BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | segId(seg))
  1508  		bind.AddUleb(off)
  1509  
  1510  		d := dylibId(r.targ)
  1511  		if d > 0 && d < 128 {
  1512  			bind.AddUint8(BIND_OPCODE_SET_DYLIB_ORDINAL_IMM | uint8(d)&0xf)
  1513  		} else if d >= 128 {
  1514  			bind.AddUint8(BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB)
  1515  			bind.AddUleb(uint64(d))
  1516  		} else { // d <= 0
  1517  			bind.AddUint8(BIND_OPCODE_SET_DYLIB_SPECIAL_IMM | uint8(d)&0xf)
  1518  		}
  1519  
  1520  		flags := uint8(0)
  1521  		if ldr.SymWeakBinding(r.targ) {
  1522  			flags |= BIND_SYMBOL_FLAGS_WEAK_IMPORT
  1523  		}
  1524  		bind.AddUint8(BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM | flags)
  1525  		// target symbol name as a C string, with _ prefix
  1526  		bind.AddUint8('_')
  1527  		bind.Addstring(ldr.SymExtname(r.targ))
  1528  
  1529  		bind.AddUint8(BIND_OPCODE_DO_BIND)
  1530  	}
  1531  	bind.AddUint8(BIND_OPCODE_DONE)
  1532  	sz = Rnd(bind.Size(), 16) // make it 16-byte aligned, see the comment in doMachoLink
  1533  	bind.Grow(sz)
  1534  	bind.SetSize(sz)
  1535  
  1536  	// TODO: export table.
  1537  	// The symbols names are encoded as a trie. I'm really too lazy to do that
  1538  	// for now.
  1539  	// Without it, the symbols are not dynamically exported, so they cannot be
  1540  	// e.g. dlsym'd. But internal linking is not the default in that case, so
  1541  	// it is fine.
  1542  }
  1543  
  1544  // machoCodeSigSym creates and returns a symbol for code signature.
  1545  // The symbol context is left as zeros, which will be generated at the end
  1546  // (as it depends on the rest of the file).
  1547  func machoCodeSigSym(ctxt *Link, codeSize int64) loader.Sym {
  1548  	ldr := ctxt.loader
  1549  	cs := ldr.CreateSymForUpdate(".machocodesig", 0)
  1550  	if !ctxt.NeedCodeSign() || ctxt.IsExternal() {
  1551  		return cs.Sym()
  1552  	}
  1553  	sz := codesign.Size(codeSize, "a.out")
  1554  	cs.Grow(sz)
  1555  	cs.SetSize(sz)
  1556  	return cs.Sym()
  1557  }
  1558  
  1559  // machoCodeSign code-signs Mach-O file fname with an ad-hoc signature.
  1560  // This is used for updating an external linker generated binary.
  1561  func machoCodeSign(ctxt *Link, fname string) error {
  1562  	f, err := os.OpenFile(fname, os.O_RDWR, 0)
  1563  	if err != nil {
  1564  		return err
  1565  	}
  1566  	defer f.Close()
  1567  
  1568  	mf, err := macho.NewFile(f)
  1569  	if err != nil {
  1570  		return err
  1571  	}
  1572  	if mf.Magic != macho.Magic64 {
  1573  		Exitf("not 64-bit Mach-O file: %s", fname)
  1574  	}
  1575  
  1576  	// Find existing LC_CODE_SIGNATURE and __LINKEDIT segment
  1577  	var sigOff, sigSz, csCmdOff, linkeditOff int64
  1578  	var linkeditSeg, textSeg *macho.Segment
  1579  	loadOff := int64(machoHeaderSize64)
  1580  	get32 := mf.ByteOrder.Uint32
  1581  	for _, l := range mf.Loads {
  1582  		data := l.Raw()
  1583  		cmd, sz := get32(data), get32(data[4:])
  1584  		if cmd == imacho.LC_CODE_SIGNATURE {
  1585  			sigOff = int64(get32(data[8:]))
  1586  			sigSz = int64(get32(data[12:]))
  1587  			csCmdOff = loadOff
  1588  		}
  1589  		if seg, ok := l.(*macho.Segment); ok {
  1590  			switch seg.Name {
  1591  			case "__LINKEDIT":
  1592  				linkeditSeg = seg
  1593  				linkeditOff = loadOff
  1594  			case "__TEXT":
  1595  				textSeg = seg
  1596  			}
  1597  		}
  1598  		loadOff += int64(sz)
  1599  	}
  1600  
  1601  	if sigOff == 0 {
  1602  		// The C linker doesn't generate a signed binary, for some reason.
  1603  		// Skip.
  1604  		return nil
  1605  	}
  1606  
  1607  	fi, err := f.Stat()
  1608  	if err != nil {
  1609  		return err
  1610  	}
  1611  	if sigOff+sigSz != fi.Size() {
  1612  		// We don't expect anything after the signature (this will invalidate
  1613  		// the signature anyway.)
  1614  		return fmt.Errorf("unexpected content after code signature")
  1615  	}
  1616  
  1617  	sz := codesign.Size(sigOff, "a.out")
  1618  	if sz != sigSz {
  1619  		// Update the load command,
  1620  		var tmp [8]byte
  1621  		mf.ByteOrder.PutUint32(tmp[:4], uint32(sz))
  1622  		_, err = f.WriteAt(tmp[:4], csCmdOff+12)
  1623  		if err != nil {
  1624  			return err
  1625  		}
  1626  
  1627  		// Uodate the __LINKEDIT segment.
  1628  		segSz := sigOff + sz - int64(linkeditSeg.Offset)
  1629  		mf.ByteOrder.PutUint64(tmp[:8], uint64(segSz))
  1630  		_, err = f.WriteAt(tmp[:8], linkeditOff+int64(unsafe.Offsetof(macho.Segment64{}.Memsz)))
  1631  		if err != nil {
  1632  			return err
  1633  		}
  1634  		_, err = f.WriteAt(tmp[:8], linkeditOff+int64(unsafe.Offsetof(macho.Segment64{}.Filesz)))
  1635  		if err != nil {
  1636  			return err
  1637  		}
  1638  	}
  1639  
  1640  	cs := make([]byte, sz)
  1641  	codesign.Sign(cs, f, "a.out", sigOff, int64(textSeg.Offset), int64(textSeg.Filesz), ctxt.IsExe() || ctxt.IsPIE())
  1642  	_, err = f.WriteAt(cs, sigOff)
  1643  	if err != nil {
  1644  		return err
  1645  	}
  1646  	err = f.Truncate(sigOff + sz)
  1647  	return err
  1648  }
  1649  

View as plain text