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

View as plain text