github.com/go-asm/go@v1.21.1-0.20240213172139-40c5ead50c48/cmd/link/ld/macho.go (about)

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