...

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

Documentation: cmd/link/internal/ld

     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  	PLATFORM_MACCATALYST MachoPlatform = 6
   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  // Create a new Mach-O load command. ndata is the number of 32-bit words for
   301  // the data (not including the load command header).
   302  func newMachoLoad(arch *sys.Arch, type_ uint32, ndata uint32) *MachoLoad {
   303  	if arch.PtrSize == 8 && (ndata&1 != 0) {
   304  		ndata++
   305  	}
   306  
   307  	load = append(load, MachoLoad{})
   308  	l := &load[len(load)-1]
   309  	l.type_ = type_
   310  	l.data = make([]uint32, ndata)
   311  	return l
   312  }
   313  
   314  func newMachoSeg(name string, msect int) *MachoSeg {
   315  	if nseg >= len(seg) {
   316  		Exitf("too many segs")
   317  	}
   318  
   319  	s := &seg[nseg]
   320  	nseg++
   321  	s.name = name
   322  	s.msect = uint32(msect)
   323  	s.sect = make([]MachoSect, msect)
   324  	return s
   325  }
   326  
   327  func newMachoSect(seg *MachoSeg, name string, segname string) *MachoSect {
   328  	if seg.nsect >= seg.msect {
   329  		Exitf("too many sects in segment %s", seg.name)
   330  	}
   331  
   332  	s := &seg.sect[seg.nsect]
   333  	seg.nsect++
   334  	s.name = name
   335  	s.segname = segname
   336  	nsect++
   337  	return s
   338  }
   339  
   340  // Generic linking code.
   341  
   342  var dylib []string
   343  
   344  var linkoff int64
   345  
   346  func machowrite(ctxt *Link, arch *sys.Arch, out *OutBuf, linkmode LinkMode) int {
   347  	o1 := out.Offset()
   348  
   349  	loadsize := 4 * 4 * ndebug
   350  	for i := range load {
   351  		loadsize += 4 * (len(load[i].data) + 2)
   352  	}
   353  	if arch.PtrSize == 8 {
   354  		loadsize += 18 * 4 * nseg
   355  		loadsize += 20 * 4 * nsect
   356  	} else {
   357  		loadsize += 14 * 4 * nseg
   358  		loadsize += 17 * 4 * nsect
   359  	}
   360  
   361  	if arch.PtrSize == 8 {
   362  		out.Write32(MH_MAGIC_64)
   363  	} else {
   364  		out.Write32(MH_MAGIC)
   365  	}
   366  	out.Write32(machohdr.cpu)
   367  	out.Write32(machohdr.subcpu)
   368  	if linkmode == LinkExternal {
   369  		out.Write32(MH_OBJECT) /* file type - mach object */
   370  	} else {
   371  		out.Write32(MH_EXECUTE) /* file type - mach executable */
   372  	}
   373  	out.Write32(uint32(len(load)) + uint32(nseg) + uint32(ndebug))
   374  	out.Write32(uint32(loadsize))
   375  	flags := uint32(0)
   376  	if nkind[SymKindUndef] == 0 {
   377  		flags |= MH_NOUNDEFS
   378  	}
   379  	if ctxt.IsPIE() && linkmode == LinkInternal {
   380  		flags |= MH_PIE | MH_DYLDLINK
   381  	}
   382  	out.Write32(flags) /* flags */
   383  	if arch.PtrSize == 8 {
   384  		out.Write32(0) /* reserved */
   385  	}
   386  
   387  	for i := 0; i < nseg; i++ {
   388  		s := &seg[i]
   389  		if arch.PtrSize == 8 {
   390  			out.Write32(LC_SEGMENT_64)
   391  			out.Write32(72 + 80*s.nsect)
   392  			out.WriteStringN(s.name, 16)
   393  			out.Write64(s.vaddr)
   394  			out.Write64(s.vsize)
   395  			out.Write64(s.fileoffset)
   396  			out.Write64(s.filesize)
   397  			out.Write32(s.prot1)
   398  			out.Write32(s.prot2)
   399  			out.Write32(s.nsect)
   400  			out.Write32(s.flag)
   401  		} else {
   402  			out.Write32(LC_SEGMENT)
   403  			out.Write32(56 + 68*s.nsect)
   404  			out.WriteStringN(s.name, 16)
   405  			out.Write32(uint32(s.vaddr))
   406  			out.Write32(uint32(s.vsize))
   407  			out.Write32(uint32(s.fileoffset))
   408  			out.Write32(uint32(s.filesize))
   409  			out.Write32(s.prot1)
   410  			out.Write32(s.prot2)
   411  			out.Write32(s.nsect)
   412  			out.Write32(s.flag)
   413  		}
   414  
   415  		for j := uint32(0); j < s.nsect; j++ {
   416  			t := &s.sect[j]
   417  			if arch.PtrSize == 8 {
   418  				out.WriteStringN(t.name, 16)
   419  				out.WriteStringN(t.segname, 16)
   420  				out.Write64(t.addr)
   421  				out.Write64(t.size)
   422  				out.Write32(t.off)
   423  				out.Write32(t.align)
   424  				out.Write32(t.reloc)
   425  				out.Write32(t.nreloc)
   426  				out.Write32(t.flag)
   427  				out.Write32(t.res1) /* reserved */
   428  				out.Write32(t.res2) /* reserved */
   429  				out.Write32(0)      /* reserved */
   430  			} else {
   431  				out.WriteStringN(t.name, 16)
   432  				out.WriteStringN(t.segname, 16)
   433  				out.Write32(uint32(t.addr))
   434  				out.Write32(uint32(t.size))
   435  				out.Write32(t.off)
   436  				out.Write32(t.align)
   437  				out.Write32(t.reloc)
   438  				out.Write32(t.nreloc)
   439  				out.Write32(t.flag)
   440  				out.Write32(t.res1) /* reserved */
   441  				out.Write32(t.res2) /* reserved */
   442  			}
   443  		}
   444  	}
   445  
   446  	for i := range load {
   447  		l := &load[i]
   448  		out.Write32(l.type_)
   449  		out.Write32(4 * (uint32(len(l.data)) + 2))
   450  		for j := 0; j < len(l.data); j++ {
   451  			out.Write32(l.data[j])
   452  		}
   453  	}
   454  
   455  	return int(out.Offset() - o1)
   456  }
   457  
   458  func (ctxt *Link) domacho() {
   459  	if *FlagD {
   460  		return
   461  	}
   462  
   463  	// Copy platform load command.
   464  	for _, h := range hostobj {
   465  		load, err := hostobjMachoPlatform(&h)
   466  		if err != nil {
   467  			Exitf("%v", err)
   468  		}
   469  		if load != nil {
   470  			machoPlatform = load.platform
   471  			ml := newMachoLoad(ctxt.Arch, load.cmd.type_, uint32(len(load.cmd.data)))
   472  			copy(ml.data, load.cmd.data)
   473  			break
   474  		}
   475  	}
   476  	if machoPlatform == 0 {
   477  		machoPlatform = PLATFORM_MACOS
   478  		if buildcfg.GOOS == "ios" {
   479  			machoPlatform = PLATFORM_IOS
   480  		}
   481  		if ctxt.LinkMode == LinkInternal && machoPlatform == PLATFORM_MACOS {
   482  			var version uint32
   483  			switch ctxt.Arch.Family {
   484  			case sys.ARM64, sys.AMD64:
   485  				// This must be fairly recent for Apple signing (go.dev/issue/30488).
   486  				// Having too old a version here was also implicated in some problems
   487  				// calling into macOS libraries (go.dev/issue/56784).
   488  				// In general this can be the most recent supported macOS version.
   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() && len(buildinfo) > 0 {
   855  			ml := newMachoLoad(ctxt.Arch, LC_UUID, 4)
   856  			// Mach-O UUID is 16 bytes
   857  			if len(buildinfo) < 16 {
   858  				buildinfo = append(buildinfo, make([]byte, 16)...)
   859  			}
   860  			// By default, buildinfo is already in UUIDv3 format
   861  			// (see uuidFromGoBuildId).
   862  			ml.data[0] = ctxt.Arch.ByteOrder.Uint32(buildinfo)
   863  			ml.data[1] = ctxt.Arch.ByteOrder.Uint32(buildinfo[4:])
   864  			ml.data[2] = ctxt.Arch.ByteOrder.Uint32(buildinfo[8:])
   865  			ml.data[3] = ctxt.Arch.ByteOrder.Uint32(buildinfo[12:])
   866  		}
   867  
   868  		if ctxt.IsInternal() && ctxt.NeedCodeSign() {
   869  			ml := newMachoLoad(ctxt.Arch, LC_CODE_SIGNATURE, 2)
   870  			ml.data[0] = uint32(codesigOff)
   871  			ml.data[1] = uint32(s7)
   872  		}
   873  	}
   874  
   875  	a := machowrite(ctxt, ctxt.Arch, ctxt.Out, ctxt.LinkMode)
   876  	if int32(a) > HEADR {
   877  		Exitf("HEADR too small: %d > %d", a, HEADR)
   878  	}
   879  
   880  	// Now we have written everything. Compute the code signature (which
   881  	// is a hash of the file content, so it must be done at last.)
   882  	if ctxt.IsInternal() && ctxt.NeedCodeSign() {
   883  		cs := ldr.Lookup(".machocodesig", 0)
   884  		data := ctxt.Out.Data()
   885  		if int64(len(data)) != codesigOff {
   886  			panic("wrong size")
   887  		}
   888  		codesign.Sign(ldr.Data(cs), bytes.NewReader(data), "a.out", codesigOff, int64(mstext.fileoffset), int64(mstext.filesize), ctxt.IsExe() || ctxt.IsPIE())
   889  		ctxt.Out.SeekSet(codesigOff)
   890  		ctxt.Out.Write(ldr.Data(cs))
   891  	}
   892  }
   893  
   894  func symkind(ldr *loader.Loader, s loader.Sym) int {
   895  	if t := ldr.SymType(s); t == sym.SDYNIMPORT || t == sym.SHOSTOBJ || t == sym.SUNDEFEXT {
   896  		return SymKindUndef
   897  	}
   898  	if ldr.AttrCgoExport(s) {
   899  		return SymKindExtdef
   900  	}
   901  	return SymKindLocal
   902  }
   903  
   904  func collectmachosyms(ctxt *Link) {
   905  	ldr := ctxt.loader
   906  
   907  	addsym := func(s loader.Sym) {
   908  		sortsym = append(sortsym, s)
   909  		nkind[symkind(ldr, s)]++
   910  	}
   911  
   912  	// On Mach-O, even with -s, we still need to keep dynamically exported and
   913  	// referenced symbols. We can strip defined local text and data symbols.
   914  	// So *FlagS is applied based on symbol type.
   915  
   916  	// Add special runtime.text and runtime.etext symbols (which are local).
   917  	// We've already included this symbol in Textp on darwin if ctxt.DynlinkingGo().
   918  	// See data.go:/textaddress
   919  	// NOTE: runtime.text.N symbols (if we split text sections) are not added, though,
   920  	// so we handle them here.
   921  	if !*FlagS {
   922  		if !ctxt.DynlinkingGo() {
   923  			s := ldr.Lookup("runtime.text", 0)
   924  			if ldr.SymType(s) == sym.STEXT {
   925  				addsym(s)
   926  			}
   927  		}
   928  		for n := range Segtext.Sections[1:] {
   929  			s := ldr.Lookup(fmt.Sprintf("runtime.text.%d", n+1), 0)
   930  			if s != 0 {
   931  				addsym(s)
   932  			} else {
   933  				break
   934  			}
   935  		}
   936  		if !ctxt.DynlinkingGo() {
   937  			s := ldr.Lookup("runtime.etext", 0)
   938  			if ldr.SymType(s) == sym.STEXT {
   939  				addsym(s)
   940  			}
   941  		}
   942  	}
   943  
   944  	// Add text symbols.
   945  	for _, s := range ctxt.Textp {
   946  		if *FlagS && !ldr.AttrCgoExportDynamic(s) {
   947  			continue
   948  		}
   949  		addsym(s)
   950  	}
   951  
   952  	shouldBeInSymbolTable := func(s loader.Sym) bool {
   953  		if ldr.AttrNotInSymbolTable(s) {
   954  			return false
   955  		}
   956  		name := ldr.SymName(s) // TODO: try not to read the name
   957  		if name == "" || name[0] == '.' {
   958  			return false
   959  		}
   960  		return true
   961  	}
   962  
   963  	// Add data symbols and external references.
   964  	for s := loader.Sym(1); s < loader.Sym(ldr.NSym()); s++ {
   965  		if !ldr.AttrReachable(s) {
   966  			continue
   967  		}
   968  		t := ldr.SymType(s)
   969  		if t >= sym.SELFRXSECT && t < sym.SXREF { // data sections handled in dodata
   970  			if t == sym.STLSBSS {
   971  				// TLSBSS is not used on darwin. See data.go:allocateDataSections
   972  				continue
   973  			}
   974  			if !shouldBeInSymbolTable(s) {
   975  				continue
   976  			}
   977  			if *FlagS && !ldr.AttrCgoExportDynamic(s) {
   978  				continue
   979  			}
   980  			addsym(s)
   981  			continue
   982  		}
   983  
   984  		switch t {
   985  		case sym.SDYNIMPORT, sym.SHOSTOBJ, sym.SUNDEFEXT:
   986  			// Keep dynamic symbol references even if *FlagS.
   987  			addsym(s)
   988  		}
   989  
   990  		// Some 64-bit functions have a "$INODE64" or "$INODE64$UNIX2003" suffix.
   991  		if t == sym.SDYNIMPORT && ldr.SymDynimplib(s) == "/usr/lib/libSystem.B.dylib" {
   992  			// But only on macOS.
   993  			if machoPlatform == PLATFORM_MACOS || machoPlatform == PLATFORM_MACCATALYST {
   994  				switch n := ldr.SymExtname(s); n {
   995  				case "fdopendir":
   996  					switch buildcfg.GOARCH {
   997  					case "amd64":
   998  						ldr.SetSymExtname(s, n+"$INODE64")
   999  					}
  1000  				case "readdir_r", "getfsstat":
  1001  					switch buildcfg.GOARCH {
  1002  					case "amd64":
  1003  						ldr.SetSymExtname(s, n+"$INODE64")
  1004  					}
  1005  				}
  1006  			}
  1007  		}
  1008  	}
  1009  
  1010  	nsortsym = len(sortsym)
  1011  }
  1012  
  1013  func machosymorder(ctxt *Link) {
  1014  	ldr := ctxt.loader
  1015  
  1016  	// On Mac OS X Mountain Lion, we must sort exported symbols
  1017  	// So we sort them here and pre-allocate dynid for them
  1018  	// See https://golang.org/issue/4029
  1019  	for _, s := range ctxt.dynexp {
  1020  		if !ldr.AttrReachable(s) {
  1021  			panic("dynexp symbol is not reachable")
  1022  		}
  1023  	}
  1024  	collectmachosyms(ctxt)
  1025  	sort.Slice(sortsym[:nsortsym], func(i, j int) bool {
  1026  		s1 := sortsym[i]
  1027  		s2 := sortsym[j]
  1028  		k1 := symkind(ldr, s1)
  1029  		k2 := symkind(ldr, s2)
  1030  		if k1 != k2 {
  1031  			return k1 < k2
  1032  		}
  1033  		return ldr.SymExtname(s1) < ldr.SymExtname(s2) // Note: unnamed symbols are not added in collectmachosyms
  1034  	})
  1035  	for i, s := range sortsym {
  1036  		ldr.SetSymDynid(s, int32(i))
  1037  	}
  1038  }
  1039  
  1040  // AddMachoSym adds s to Mach-O symbol table, used in GenSymLate.
  1041  // Currently only used on ARM64 when external linking.
  1042  func AddMachoSym(ldr *loader.Loader, s loader.Sym) {
  1043  	ldr.SetSymDynid(s, int32(nsortsym))
  1044  	sortsym = append(sortsym, s)
  1045  	nsortsym++
  1046  	nkind[symkind(ldr, s)]++
  1047  }
  1048  
  1049  // machoShouldExport reports whether a symbol needs to be exported.
  1050  //
  1051  // When dynamically linking, all non-local variables and plugin-exported
  1052  // symbols need to be exported.
  1053  func machoShouldExport(ctxt *Link, ldr *loader.Loader, s loader.Sym) bool {
  1054  	if !ctxt.DynlinkingGo() || ldr.AttrLocal(s) {
  1055  		return false
  1056  	}
  1057  	if ctxt.BuildMode == BuildModePlugin && strings.HasPrefix(ldr.SymExtname(s), objabi.PathToPrefix(*flagPluginPath)) {
  1058  		return true
  1059  	}
  1060  	name := ldr.SymName(s)
  1061  	if strings.HasPrefix(name, "go:itab.") {
  1062  		return true
  1063  	}
  1064  	if strings.HasPrefix(name, "type:") && !strings.HasPrefix(name, "type:.") {
  1065  		// reduce runtime typemap pressure, but do not
  1066  		// export alg functions (type:.*), as these
  1067  		// appear in pclntable.
  1068  		return true
  1069  	}
  1070  	if strings.HasPrefix(name, "go:link.pkghash") {
  1071  		return true
  1072  	}
  1073  	return ldr.SymType(s) >= sym.SFirstWritable // only writable sections
  1074  }
  1075  
  1076  func machosymtab(ctxt *Link) {
  1077  	ldr := ctxt.loader
  1078  	symtab := ldr.CreateSymForUpdate(".machosymtab", 0)
  1079  	symstr := ldr.CreateSymForUpdate(".machosymstr", 0)
  1080  
  1081  	for _, s := range sortsym[:nsortsym] {
  1082  		symtab.AddUint32(ctxt.Arch, uint32(symstr.Size()))
  1083  
  1084  		export := machoShouldExport(ctxt, ldr, s)
  1085  
  1086  		// Prefix symbol names with "_" to match the system toolchain.
  1087  		// (We used to only prefix C symbols, which is all required for the build.
  1088  		// But some tools don't recognize Go symbols as symbols, so we prefix them
  1089  		// as well.)
  1090  		symstr.AddUint8('_')
  1091  
  1092  		// replace "·" as ".", because DTrace cannot handle it.
  1093  		name := strings.Replace(ldr.SymExtname(s), "·", ".", -1)
  1094  
  1095  		name = mangleABIName(ctxt, ldr, s, name)
  1096  		symstr.Addstring(name)
  1097  
  1098  		if t := ldr.SymType(s); t == sym.SDYNIMPORT || t == sym.SHOSTOBJ || t == sym.SUNDEFEXT {
  1099  			symtab.AddUint8(0x01)                             // type N_EXT, external symbol
  1100  			symtab.AddUint8(0)                                // no section
  1101  			symtab.AddUint16(ctxt.Arch, 0)                    // desc
  1102  			symtab.AddUintXX(ctxt.Arch, 0, ctxt.Arch.PtrSize) // no value
  1103  		} else {
  1104  			if export || ldr.AttrCgoExportDynamic(s) {
  1105  				symtab.AddUint8(0x0f) // N_SECT | N_EXT
  1106  			} else if ldr.AttrCgoExportStatic(s) {
  1107  				// Only export statically, not dynamically. (N_PEXT is like hidden visibility)
  1108  				symtab.AddUint8(0x1f) // N_SECT | N_EXT | N_PEXT
  1109  			} else {
  1110  				symtab.AddUint8(0x0e) // N_SECT
  1111  			}
  1112  			o := s
  1113  			if outer := ldr.OuterSym(o); outer != 0 {
  1114  				o = outer
  1115  			}
  1116  			if ldr.SymSect(o) == nil {
  1117  				ldr.Errorf(s, "missing section for symbol")
  1118  				symtab.AddUint8(0)
  1119  			} else {
  1120  				symtab.AddUint8(uint8(ldr.SymSect(o).Extnum))
  1121  			}
  1122  			symtab.AddUint16(ctxt.Arch, 0) // desc
  1123  			symtab.AddUintXX(ctxt.Arch, uint64(ldr.SymAddr(s)), ctxt.Arch.PtrSize)
  1124  		}
  1125  	}
  1126  }
  1127  
  1128  func machodysymtab(ctxt *Link, base int64) {
  1129  	ml := newMachoLoad(ctxt.Arch, LC_DYSYMTAB, 18)
  1130  
  1131  	n := 0
  1132  	ml.data[0] = uint32(n)                   /* ilocalsym */
  1133  	ml.data[1] = uint32(nkind[SymKindLocal]) /* nlocalsym */
  1134  	n += nkind[SymKindLocal]
  1135  
  1136  	ml.data[2] = uint32(n)                    /* iextdefsym */
  1137  	ml.data[3] = uint32(nkind[SymKindExtdef]) /* nextdefsym */
  1138  	n += nkind[SymKindExtdef]
  1139  
  1140  	ml.data[4] = uint32(n)                   /* iundefsym */
  1141  	ml.data[5] = uint32(nkind[SymKindUndef]) /* nundefsym */
  1142  
  1143  	ml.data[6] = 0  /* tocoffset */
  1144  	ml.data[7] = 0  /* ntoc */
  1145  	ml.data[8] = 0  /* modtaboff */
  1146  	ml.data[9] = 0  /* nmodtab */
  1147  	ml.data[10] = 0 /* extrefsymoff */
  1148  	ml.data[11] = 0 /* nextrefsyms */
  1149  
  1150  	ldr := ctxt.loader
  1151  
  1152  	// must match domacholink below
  1153  	s1 := ldr.SymSize(ldr.Lookup(".machosymtab", 0))
  1154  	s2 := ldr.SymSize(ctxt.ArchSyms.LinkEditPLT)
  1155  	s3 := ldr.SymSize(ctxt.ArchSyms.LinkEditGOT)
  1156  	ml.data[12] = uint32(base + s1)     /* indirectsymoff */
  1157  	ml.data[13] = uint32((s2 + s3) / 4) /* nindirectsyms */
  1158  
  1159  	ml.data[14] = 0 /* extreloff */
  1160  	ml.data[15] = 0 /* nextrel */
  1161  	ml.data[16] = 0 /* locreloff */
  1162  	ml.data[17] = 0 /* nlocrel */
  1163  }
  1164  
  1165  func doMachoLink(ctxt *Link) int64 {
  1166  	machosymtab(ctxt)
  1167  	machoDyldInfo(ctxt)
  1168  
  1169  	ldr := ctxt.loader
  1170  
  1171  	// write data that will be linkedit section
  1172  	s1 := ldr.Lookup(".machorebase", 0)
  1173  	s2 := ldr.Lookup(".machobind", 0)
  1174  	s3 := ldr.Lookup(".machosymtab", 0)
  1175  	s4 := ctxt.ArchSyms.LinkEditPLT
  1176  	s5 := ctxt.ArchSyms.LinkEditGOT
  1177  	s6 := ldr.Lookup(".machosymstr", 0)
  1178  
  1179  	size := ldr.SymSize(s1) + ldr.SymSize(s2) + ldr.SymSize(s3) + ldr.SymSize(s4) + ldr.SymSize(s5) + ldr.SymSize(s6)
  1180  
  1181  	// Force the linkedit section to end on a 16-byte
  1182  	// boundary. This allows pure (non-cgo) Go binaries
  1183  	// to be code signed correctly.
  1184  	//
  1185  	// Apple's codesign_allocate (a helper utility for
  1186  	// the codesign utility) can do this fine itself if
  1187  	// it is run on a dynamic Mach-O binary. However,
  1188  	// when it is run on a pure (non-cgo) Go binary, where
  1189  	// the linkedit section is mostly empty, it fails to
  1190  	// account for the extra padding that it itself adds
  1191  	// when adding the LC_CODE_SIGNATURE load command
  1192  	// (which must be aligned on a 16-byte boundary).
  1193  	//
  1194  	// By forcing the linkedit section to end on a 16-byte
  1195  	// boundary, codesign_allocate will not need to apply
  1196  	// any alignment padding itself, working around the
  1197  	// issue.
  1198  	if size%16 != 0 {
  1199  		n := 16 - size%16
  1200  		s6b := ldr.MakeSymbolUpdater(s6)
  1201  		s6b.Grow(s6b.Size() + n)
  1202  		s6b.SetSize(s6b.Size() + n)
  1203  		size += n
  1204  	}
  1205  
  1206  	if size > 0 {
  1207  		linkoff = Rnd(int64(uint64(HEADR)+Segtext.Length), *FlagRound) + Rnd(int64(Segrelrodata.Filelen), *FlagRound) + Rnd(int64(Segdata.Filelen), *FlagRound) + Rnd(int64(Segdwarf.Filelen), *FlagRound)
  1208  		ctxt.Out.SeekSet(linkoff)
  1209  
  1210  		ctxt.Out.Write(ldr.Data(s1))
  1211  		ctxt.Out.Write(ldr.Data(s2))
  1212  		ctxt.Out.Write(ldr.Data(s3))
  1213  		ctxt.Out.Write(ldr.Data(s4))
  1214  		ctxt.Out.Write(ldr.Data(s5))
  1215  		ctxt.Out.Write(ldr.Data(s6))
  1216  
  1217  		// Add code signature if necessary. This must be the last.
  1218  		s7 := machoCodeSigSym(ctxt, linkoff+size)
  1219  		size += ldr.SymSize(s7)
  1220  	}
  1221  
  1222  	return Rnd(size, *FlagRound)
  1223  }
  1224  
  1225  func machorelocsect(ctxt *Link, out *OutBuf, sect *sym.Section, syms []loader.Sym) {
  1226  	// If main section has no bits, nothing to relocate.
  1227  	if sect.Vaddr >= sect.Seg.Vaddr+sect.Seg.Filelen {
  1228  		return
  1229  	}
  1230  	ldr := ctxt.loader
  1231  
  1232  	for i, s := range syms {
  1233  		if !ldr.AttrReachable(s) {
  1234  			continue
  1235  		}
  1236  		if uint64(ldr.SymValue(s)) >= sect.Vaddr {
  1237  			syms = syms[i:]
  1238  			break
  1239  		}
  1240  	}
  1241  
  1242  	eaddr := sect.Vaddr + sect.Length
  1243  	for _, s := range syms {
  1244  		if !ldr.AttrReachable(s) {
  1245  			continue
  1246  		}
  1247  		if ldr.SymValue(s) >= int64(eaddr) {
  1248  			break
  1249  		}
  1250  
  1251  		// Compute external relocations on the go, and pass to Machoreloc1
  1252  		// to stream out.
  1253  		relocs := ldr.Relocs(s)
  1254  		for ri := 0; ri < relocs.Count(); ri++ {
  1255  			r := relocs.At(ri)
  1256  			rr, ok := extreloc(ctxt, ldr, s, r)
  1257  			if !ok {
  1258  				continue
  1259  			}
  1260  			if rr.Xsym == 0 {
  1261  				ldr.Errorf(s, "missing xsym in relocation")
  1262  				continue
  1263  			}
  1264  			if !ldr.AttrReachable(rr.Xsym) {
  1265  				ldr.Errorf(s, "unreachable reloc %d (%s) target %v", r.Type(), sym.RelocName(ctxt.Arch, r.Type()), ldr.SymName(rr.Xsym))
  1266  			}
  1267  			if !thearch.Machoreloc1(ctxt.Arch, out, ldr, s, rr, int64(uint64(ldr.SymValue(s)+int64(r.Off()))-sect.Vaddr)) {
  1268  				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()))
  1269  			}
  1270  		}
  1271  	}
  1272  
  1273  	// sanity check
  1274  	if uint64(out.Offset()) != sect.Reloff+sect.Rellen {
  1275  		panic("machorelocsect: size mismatch")
  1276  	}
  1277  }
  1278  
  1279  func machoEmitReloc(ctxt *Link) {
  1280  	for ctxt.Out.Offset()&7 != 0 {
  1281  		ctxt.Out.Write8(0)
  1282  	}
  1283  
  1284  	sizeExtRelocs(ctxt, thearch.MachorelocSize)
  1285  	relocSect, wg := relocSectFn(ctxt, machorelocsect)
  1286  
  1287  	relocSect(ctxt, Segtext.Sections[0], ctxt.Textp)
  1288  	for _, sect := range Segtext.Sections[1:] {
  1289  		if sect.Name == ".text" {
  1290  			relocSect(ctxt, sect, ctxt.Textp)
  1291  		} else {
  1292  			relocSect(ctxt, sect, ctxt.datap)
  1293  		}
  1294  	}
  1295  	for _, sect := range Segrelrodata.Sections {
  1296  		relocSect(ctxt, sect, ctxt.datap)
  1297  	}
  1298  	for _, sect := range Segdata.Sections {
  1299  		relocSect(ctxt, sect, ctxt.datap)
  1300  	}
  1301  	for i := 0; i < len(Segdwarf.Sections); i++ {
  1302  		sect := Segdwarf.Sections[i]
  1303  		si := dwarfp[i]
  1304  		if si.secSym() != loader.Sym(sect.Sym) ||
  1305  			ctxt.loader.SymSect(si.secSym()) != sect {
  1306  			panic("inconsistency between dwarfp and Segdwarf")
  1307  		}
  1308  		relocSect(ctxt, sect, si.syms)
  1309  	}
  1310  	wg.Wait()
  1311  }
  1312  
  1313  // hostobjMachoPlatform returns the first platform load command found
  1314  // in the host object, if any.
  1315  func hostobjMachoPlatform(h *Hostobj) (*MachoPlatformLoad, error) {
  1316  	f, err := os.Open(h.file)
  1317  	if err != nil {
  1318  		return nil, fmt.Errorf("%s: failed to open host object: %v\n", h.file, err)
  1319  	}
  1320  	defer f.Close()
  1321  	sr := io.NewSectionReader(f, h.off, h.length)
  1322  	m, err := macho.NewFile(sr)
  1323  	if err != nil {
  1324  		// Not a valid Mach-O file.
  1325  		return nil, nil
  1326  	}
  1327  	return peekMachoPlatform(m)
  1328  }
  1329  
  1330  // peekMachoPlatform returns the first LC_VERSION_MIN_* or LC_BUILD_VERSION
  1331  // load command found in the Mach-O file, if any.
  1332  func peekMachoPlatform(m *macho.File) (*MachoPlatformLoad, error) {
  1333  	for _, cmd := range m.Loads {
  1334  		raw := cmd.Raw()
  1335  		ml := MachoLoad{
  1336  			type_: m.ByteOrder.Uint32(raw),
  1337  		}
  1338  		// Skip the type and command length.
  1339  		data := raw[8:]
  1340  		var p MachoPlatform
  1341  		switch ml.type_ {
  1342  		case LC_VERSION_MIN_IPHONEOS:
  1343  			p = PLATFORM_IOS
  1344  		case LC_VERSION_MIN_MACOSX:
  1345  			p = PLATFORM_MACOS
  1346  		case LC_VERSION_MIN_WATCHOS:
  1347  			p = PLATFORM_WATCHOS
  1348  		case LC_VERSION_MIN_TVOS:
  1349  			p = PLATFORM_TVOS
  1350  		case LC_BUILD_VERSION:
  1351  			p = MachoPlatform(m.ByteOrder.Uint32(data))
  1352  		default:
  1353  			continue
  1354  		}
  1355  		ml.data = make([]uint32, len(data)/4)
  1356  		r := bytes.NewReader(data)
  1357  		if err := binary.Read(r, m.ByteOrder, &ml.data); err != nil {
  1358  			return nil, err
  1359  		}
  1360  		return &MachoPlatformLoad{
  1361  			platform: p,
  1362  			cmd:      ml,
  1363  		}, nil
  1364  	}
  1365  	return nil, nil
  1366  }
  1367  
  1368  // A rebase entry tells the dynamic linker the data at sym+off needs to be
  1369  // relocated when the in-memory image moves. (This is somewhat like, say,
  1370  // ELF R_X86_64_RELATIVE).
  1371  // For now, the only kind of entry we support is that the data is an absolute
  1372  // address. That seems all we need.
  1373  // In the binary it uses a compact stateful bytecode encoding. So we record
  1374  // entries as we go and build the table at the end.
  1375  type machoRebaseRecord struct {
  1376  	sym loader.Sym
  1377  	off int64
  1378  }
  1379  
  1380  var machorebase []machoRebaseRecord
  1381  
  1382  func MachoAddRebase(s loader.Sym, off int64) {
  1383  	machorebase = append(machorebase, machoRebaseRecord{s, off})
  1384  }
  1385  
  1386  // A bind entry tells the dynamic linker the data at GOT+off should be bound
  1387  // to the address of the target symbol, which is a dynamic import.
  1388  // For now, the only kind of entry we support is that the data is an absolute
  1389  // address, and the source symbol is always the GOT. That seems all we need.
  1390  // In the binary it uses a compact stateful bytecode encoding. So we record
  1391  // entries as we go and build the table at the end.
  1392  type machoBindRecord struct {
  1393  	off  int64
  1394  	targ loader.Sym
  1395  }
  1396  
  1397  var machobind []machoBindRecord
  1398  
  1399  func MachoAddBind(off int64, targ loader.Sym) {
  1400  	machobind = append(machobind, machoBindRecord{off, targ})
  1401  }
  1402  
  1403  // Generate data for the dynamic linker, used in LC_DYLD_INFO_ONLY load command.
  1404  // See mach-o/loader.h, struct dyld_info_command, for the encoding.
  1405  // e.g. https://opensource.apple.com/source/xnu/xnu-6153.81.5/EXTERNAL_HEADERS/mach-o/loader.h
  1406  func machoDyldInfo(ctxt *Link) {
  1407  	ldr := ctxt.loader
  1408  	rebase := ldr.CreateSymForUpdate(".machorebase", 0)
  1409  	bind := ldr.CreateSymForUpdate(".machobind", 0)
  1410  
  1411  	if !(ctxt.IsPIE() && ctxt.IsInternal()) {
  1412  		return
  1413  	}
  1414  
  1415  	segId := func(seg *sym.Segment) uint8 {
  1416  		switch seg {
  1417  		case &Segtext:
  1418  			return 1
  1419  		case &Segrelrodata:
  1420  			return 2
  1421  		case &Segdata:
  1422  			if Segrelrodata.Length > 0 {
  1423  				return 3
  1424  			}
  1425  			return 2
  1426  		}
  1427  		panic("unknown segment")
  1428  	}
  1429  
  1430  	dylibId := func(s loader.Sym) int {
  1431  		slib := ldr.SymDynimplib(s)
  1432  		for i, lib := range dylib {
  1433  			if lib == slib {
  1434  				return i + 1
  1435  			}
  1436  		}
  1437  		return BIND_SPECIAL_DYLIB_FLAT_LOOKUP // don't know where it is from
  1438  	}
  1439  
  1440  	// Rebase table.
  1441  	// TODO: use more compact encoding. The encoding is stateful, and
  1442  	// we can use delta encoding.
  1443  	rebase.AddUint8(REBASE_OPCODE_SET_TYPE_IMM | REBASE_TYPE_POINTER)
  1444  	for _, r := range machorebase {
  1445  		seg := ldr.SymSect(r.sym).Seg
  1446  		off := uint64(ldr.SymValue(r.sym)+r.off) - seg.Vaddr
  1447  		rebase.AddUint8(REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | segId(seg))
  1448  		rebase.AddUleb(off)
  1449  
  1450  		rebase.AddUint8(REBASE_OPCODE_DO_REBASE_IMM_TIMES | 1)
  1451  	}
  1452  	rebase.AddUint8(REBASE_OPCODE_DONE)
  1453  	sz := Rnd(rebase.Size(), 8)
  1454  	rebase.Grow(sz)
  1455  	rebase.SetSize(sz)
  1456  
  1457  	// Bind table.
  1458  	// TODO: compact encoding, as above.
  1459  	// TODO: lazy binding?
  1460  	got := ctxt.GOT
  1461  	seg := ldr.SymSect(got).Seg
  1462  	gotAddr := ldr.SymValue(got)
  1463  	bind.AddUint8(BIND_OPCODE_SET_TYPE_IMM | BIND_TYPE_POINTER)
  1464  	for _, r := range machobind {
  1465  		off := uint64(gotAddr+r.off) - seg.Vaddr
  1466  		bind.AddUint8(BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | segId(seg))
  1467  		bind.AddUleb(off)
  1468  
  1469  		d := dylibId(r.targ)
  1470  		if d > 0 && d < 128 {
  1471  			bind.AddUint8(BIND_OPCODE_SET_DYLIB_ORDINAL_IMM | uint8(d)&0xf)
  1472  		} else if d >= 128 {
  1473  			bind.AddUint8(BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB)
  1474  			bind.AddUleb(uint64(d))
  1475  		} else { // d <= 0
  1476  			bind.AddUint8(BIND_OPCODE_SET_DYLIB_SPECIAL_IMM | uint8(d)&0xf)
  1477  		}
  1478  
  1479  		bind.AddUint8(BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM)
  1480  		// target symbol name as a C string, with _ prefix
  1481  		bind.AddUint8('_')
  1482  		bind.Addstring(ldr.SymExtname(r.targ))
  1483  
  1484  		bind.AddUint8(BIND_OPCODE_DO_BIND)
  1485  	}
  1486  	bind.AddUint8(BIND_OPCODE_DONE)
  1487  	sz = Rnd(bind.Size(), 16) // make it 16-byte aligned, see the comment in doMachoLink
  1488  	bind.Grow(sz)
  1489  	bind.SetSize(sz)
  1490  
  1491  	// TODO: export table.
  1492  	// The symbols names are encoded as a trie. I'm really too lazy to do that
  1493  	// for now.
  1494  	// Without it, the symbols are not dynamically exported, so they cannot be
  1495  	// e.g. dlsym'd. But internal linking is not the default in that case, so
  1496  	// it is fine.
  1497  }
  1498  
  1499  // machoCodeSigSym creates and returns a symbol for code signature.
  1500  // The symbol context is left as zeros, which will be generated at the end
  1501  // (as it depends on the rest of the file).
  1502  func machoCodeSigSym(ctxt *Link, codeSize int64) loader.Sym {
  1503  	ldr := ctxt.loader
  1504  	cs := ldr.CreateSymForUpdate(".machocodesig", 0)
  1505  	if !ctxt.NeedCodeSign() || ctxt.IsExternal() {
  1506  		return cs.Sym()
  1507  	}
  1508  	sz := codesign.Size(codeSize, "a.out")
  1509  	cs.Grow(sz)
  1510  	cs.SetSize(sz)
  1511  	return cs.Sym()
  1512  }
  1513  
  1514  // machoCodeSign code-signs Mach-O file fname with an ad-hoc signature.
  1515  // This is used for updating an external linker generated binary.
  1516  func machoCodeSign(ctxt *Link, fname string) error {
  1517  	f, err := os.OpenFile(fname, os.O_RDWR, 0)
  1518  	if err != nil {
  1519  		return err
  1520  	}
  1521  	defer f.Close()
  1522  
  1523  	mf, err := macho.NewFile(f)
  1524  	if err != nil {
  1525  		return err
  1526  	}
  1527  	if mf.Magic != macho.Magic64 {
  1528  		Exitf("not 64-bit Mach-O file: %s", fname)
  1529  	}
  1530  
  1531  	// Find existing LC_CODE_SIGNATURE and __LINKEDIT segment
  1532  	var sigOff, sigSz, csCmdOff, linkeditOff int64
  1533  	var linkeditSeg, textSeg *macho.Segment
  1534  	loadOff := int64(machoHeaderSize64)
  1535  	get32 := mf.ByteOrder.Uint32
  1536  	for _, l := range mf.Loads {
  1537  		data := l.Raw()
  1538  		cmd, sz := get32(data), get32(data[4:])
  1539  		if cmd == LC_CODE_SIGNATURE {
  1540  			sigOff = int64(get32(data[8:]))
  1541  			sigSz = int64(get32(data[12:]))
  1542  			csCmdOff = loadOff
  1543  		}
  1544  		if seg, ok := l.(*macho.Segment); ok {
  1545  			switch seg.Name {
  1546  			case "__LINKEDIT":
  1547  				linkeditSeg = seg
  1548  				linkeditOff = loadOff
  1549  			case "__TEXT":
  1550  				textSeg = seg
  1551  			}
  1552  		}
  1553  		loadOff += int64(sz)
  1554  	}
  1555  
  1556  	if sigOff == 0 {
  1557  		// The C linker doesn't generate a signed binary, for some reason.
  1558  		// Skip.
  1559  		return nil
  1560  	}
  1561  
  1562  	fi, err := f.Stat()
  1563  	if err != nil {
  1564  		return err
  1565  	}
  1566  	if sigOff+sigSz != fi.Size() {
  1567  		// We don't expect anything after the signature (this will invalidate
  1568  		// the signature anyway.)
  1569  		return fmt.Errorf("unexpected content after code signature")
  1570  	}
  1571  
  1572  	sz := codesign.Size(sigOff, "a.out")
  1573  	if sz != sigSz {
  1574  		// Update the load command,
  1575  		var tmp [8]byte
  1576  		mf.ByteOrder.PutUint32(tmp[:4], uint32(sz))
  1577  		_, err = f.WriteAt(tmp[:4], csCmdOff+12)
  1578  		if err != nil {
  1579  			return err
  1580  		}
  1581  
  1582  		// Uodate the __LINKEDIT segment.
  1583  		segSz := sigOff + sz - int64(linkeditSeg.Offset)
  1584  		mf.ByteOrder.PutUint64(tmp[:8], uint64(segSz))
  1585  		_, err = f.WriteAt(tmp[:8], int64(linkeditOff)+int64(unsafe.Offsetof(macho.Segment64{}.Memsz)))
  1586  		if err != nil {
  1587  			return err
  1588  		}
  1589  		_, err = f.WriteAt(tmp[:8], int64(linkeditOff)+int64(unsafe.Offsetof(macho.Segment64{}.Filesz)))
  1590  		if err != nil {
  1591  			return err
  1592  		}
  1593  	}
  1594  
  1595  	cs := make([]byte, sz)
  1596  	codesign.Sign(cs, f, "a.out", sigOff, int64(textSeg.Offset), int64(textSeg.Filesz), ctxt.IsExe() || ctxt.IsPIE())
  1597  	_, err = f.WriteAt(cs, sigOff)
  1598  	if err != nil {
  1599  		return err
  1600  	}
  1601  	err = f.Truncate(sigOff + sz)
  1602  	return err
  1603  }
  1604  

View as plain text