Black Lives Matter. Support the Equal Justice Initiative.

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/obj"
    11  	"cmd/internal/objabi"
    12  	"cmd/internal/sys"
    13  	"cmd/link/internal/loader"
    14  	"cmd/link/internal/sym"
    15  	"debug/macho"
    16  	"encoding/binary"
    17  	"fmt"
    18  	"internal/buildcfg"
    19  	"io"
    20  	"os"
    21  	"sort"
    22  	"strings"
    23  	"unsafe"
    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  				// The version must be at least 10.9; see golang.org/issues/30488.
   484  				version = 10<<16 | 9<<8 | 0<<0 // 10.9.0
   485  			case sys.ARM64:
   486  				version = 11<<16 | 0<<8 | 0<<0 // 11.0.0
   487  			}
   488  			ml := newMachoLoad(ctxt.Arch, LC_BUILD_VERSION, 4)
   489  			ml.data[0] = uint32(machoPlatform)
   490  			ml.data[1] = version // OS version
   491  			ml.data[2] = version // SDK version
   492  			ml.data[3] = 0       // ntools
   493  		}
   494  	}
   495  
   496  	// empirically, string table must begin with " \x00".
   497  	s := ctxt.loader.LookupOrCreateSym(".machosymstr", 0)
   498  	sb := ctxt.loader.MakeSymbolUpdater(s)
   499  
   500  	sb.SetType(sym.SMACHOSYMSTR)
   501  	sb.SetReachable(true)
   502  	sb.AddUint8(' ')
   503  	sb.AddUint8('\x00')
   504  
   505  	s = ctxt.loader.LookupOrCreateSym(".machosymtab", 0)
   506  	sb = ctxt.loader.MakeSymbolUpdater(s)
   507  	sb.SetType(sym.SMACHOSYMTAB)
   508  	sb.SetReachable(true)
   509  
   510  	if ctxt.IsInternal() {
   511  		s = ctxt.loader.LookupOrCreateSym(".plt", 0) // will be __symbol_stub
   512  		sb = ctxt.loader.MakeSymbolUpdater(s)
   513  		sb.SetType(sym.SMACHOPLT)
   514  		sb.SetReachable(true)
   515  
   516  		s = ctxt.loader.LookupOrCreateSym(".got", 0) // will be __nl_symbol_ptr
   517  		sb = ctxt.loader.MakeSymbolUpdater(s)
   518  		sb.SetType(sym.SMACHOGOT)
   519  		sb.SetReachable(true)
   520  		sb.SetAlign(4)
   521  
   522  		s = ctxt.loader.LookupOrCreateSym(".linkedit.plt", 0) // indirect table for .plt
   523  		sb = ctxt.loader.MakeSymbolUpdater(s)
   524  		sb.SetType(sym.SMACHOINDIRECTPLT)
   525  		sb.SetReachable(true)
   526  
   527  		s = ctxt.loader.LookupOrCreateSym(".linkedit.got", 0) // indirect table for .got
   528  		sb = ctxt.loader.MakeSymbolUpdater(s)
   529  		sb.SetType(sym.SMACHOINDIRECTGOT)
   530  		sb.SetReachable(true)
   531  	}
   532  
   533  	// Add a dummy symbol that will become the __asm marker section.
   534  	if ctxt.IsExternal() {
   535  		s = ctxt.loader.LookupOrCreateSym(".llvmasm", 0)
   536  		sb = ctxt.loader.MakeSymbolUpdater(s)
   537  		sb.SetType(sym.SMACHO)
   538  		sb.SetReachable(true)
   539  		sb.AddUint8(0)
   540  	}
   541  
   542  	// Un-export runtime symbols from plugins. Since the runtime
   543  	// is included in both the main binary and each plugin, these
   544  	// symbols appear in both images. If we leave them exported in
   545  	// the plugin, then the dynamic linker will resolve
   546  	// relocations to these functions in the plugin's functab to
   547  	// point to the main image, causing the runtime to think the
   548  	// plugin's functab is corrupted. By unexporting them, these
   549  	// become static references, which are resolved to the
   550  	// plugin's text.
   551  	//
   552  	// It would be better to omit the runtime from plugins. (Using
   553  	// relative PCs in the functab instead of relocations would
   554  	// also address this.)
   555  	//
   556  	// See issue #18190.
   557  	if ctxt.BuildMode == BuildModePlugin {
   558  		for _, name := range []string{"_cgo_topofstack", "__cgo_topofstack", "_cgo_panic", "crosscall2"} {
   559  			// Most of these are data symbols or C
   560  			// symbols, so they have symbol version 0.
   561  			ver := 0
   562  			// _cgo_panic is a Go function, so it uses ABIInternal.
   563  			if name == "_cgo_panic" {
   564  				ver = sym.ABIToVersion(obj.ABIInternal)
   565  			}
   566  			s := ctxt.loader.Lookup(name, ver)
   567  			if s != 0 {
   568  				ctxt.loader.SetAttrCgoExportDynamic(s, false)
   569  			}
   570  		}
   571  	}
   572  }
   573  
   574  func machoadddynlib(lib string, linkmode LinkMode) {
   575  	if seenlib[lib] || linkmode == LinkExternal {
   576  		return
   577  	}
   578  	seenlib[lib] = true
   579  
   580  	// Will need to store the library name rounded up
   581  	// and 24 bytes of header metadata. If not enough
   582  	// space, grab another page of initial space at the
   583  	// beginning of the output file.
   584  	loadBudget -= (len(lib)+7)/8*8 + 24
   585  
   586  	if loadBudget < 0 {
   587  		HEADR += 4096
   588  		*FlagTextAddr += 4096
   589  		loadBudget += 4096
   590  	}
   591  
   592  	dylib = append(dylib, lib)
   593  }
   594  
   595  func machoshbits(ctxt *Link, mseg *MachoSeg, sect *sym.Section, segname string) {
   596  	buf := "__" + strings.Replace(sect.Name[1:], ".", "_", -1)
   597  
   598  	msect := newMachoSect(mseg, buf, segname)
   599  
   600  	if sect.Rellen > 0 {
   601  		msect.reloc = uint32(sect.Reloff)
   602  		msect.nreloc = uint32(sect.Rellen / 8)
   603  	}
   604  
   605  	for 1<<msect.align < sect.Align {
   606  		msect.align++
   607  	}
   608  	msect.addr = sect.Vaddr
   609  	msect.size = sect.Length
   610  
   611  	if sect.Vaddr < sect.Seg.Vaddr+sect.Seg.Filelen {
   612  		// data in file
   613  		if sect.Length > sect.Seg.Vaddr+sect.Seg.Filelen-sect.Vaddr {
   614  			Errorf(nil, "macho cannot represent section %s crossing data and bss", sect.Name)
   615  		}
   616  		msect.off = uint32(sect.Seg.Fileoff + sect.Vaddr - sect.Seg.Vaddr)
   617  	} else {
   618  		msect.off = 0
   619  		msect.flag |= S_ZEROFILL
   620  	}
   621  
   622  	if sect.Rwx&1 != 0 {
   623  		msect.flag |= S_ATTR_SOME_INSTRUCTIONS
   624  	}
   625  
   626  	if sect.Name == ".text" {
   627  		msect.flag |= S_ATTR_PURE_INSTRUCTIONS
   628  	}
   629  
   630  	if sect.Name == ".plt" {
   631  		msect.name = "__symbol_stub1"
   632  		msect.flag = S_ATTR_PURE_INSTRUCTIONS | S_ATTR_SOME_INSTRUCTIONS | S_SYMBOL_STUBS
   633  		msect.res1 = 0 //nkind[SymKindLocal];
   634  		msect.res2 = 6
   635  	}
   636  
   637  	if sect.Name == ".got" {
   638  		msect.name = "__nl_symbol_ptr"
   639  		msect.flag = S_NON_LAZY_SYMBOL_POINTERS
   640  		msect.res1 = uint32(ctxt.loader.SymSize(ctxt.ArchSyms.LinkEditPLT) / 4) /* offset into indirect symbol table */
   641  	}
   642  
   643  	if sect.Name == ".init_array" {
   644  		msect.name = "__mod_init_func"
   645  		msect.flag = S_MOD_INIT_FUNC_POINTERS
   646  	}
   647  
   648  	// Some platforms such as watchOS and tvOS require binaries with
   649  	// bitcode enabled. The Go toolchain can't output bitcode, so use
   650  	// a marker section in the __LLVM segment, "__asm", to tell the Apple
   651  	// toolchain that the Go text came from assembler and thus has no
   652  	// bitcode. This is not true, but Kotlin/Native, Rust and Flutter
   653  	// are also using this trick.
   654  	if sect.Name == ".llvmasm" {
   655  		msect.name = "__asm"
   656  		msect.segname = "__LLVM"
   657  	}
   658  
   659  	if segname == "__DWARF" {
   660  		msect.flag |= S_ATTR_DEBUG
   661  	}
   662  }
   663  
   664  func asmbMacho(ctxt *Link) {
   665  	machlink := doMachoLink(ctxt)
   666  	if !*FlagS && ctxt.IsExternal() {
   667  		symo := int64(Segdwarf.Fileoff + uint64(Rnd(int64(Segdwarf.Filelen), int64(*FlagRound))) + uint64(machlink))
   668  		ctxt.Out.SeekSet(symo)
   669  		machoEmitReloc(ctxt)
   670  	}
   671  	ctxt.Out.SeekSet(0)
   672  
   673  	ldr := ctxt.loader
   674  
   675  	/* apple MACH */
   676  	va := *FlagTextAddr - int64(HEADR)
   677  
   678  	mh := getMachoHdr()
   679  	switch ctxt.Arch.Family {
   680  	default:
   681  		Exitf("unknown macho architecture: %v", ctxt.Arch.Family)
   682  
   683  	case sys.AMD64:
   684  		mh.cpu = MACHO_CPU_AMD64
   685  		mh.subcpu = MACHO_SUBCPU_X86
   686  
   687  	case sys.ARM64:
   688  		mh.cpu = MACHO_CPU_ARM64
   689  		mh.subcpu = MACHO_SUBCPU_ARM64_ALL
   690  	}
   691  
   692  	var ms *MachoSeg
   693  	if ctxt.LinkMode == LinkExternal {
   694  		/* segment for entire file */
   695  		ms = newMachoSeg("", 40)
   696  
   697  		ms.fileoffset = Segtext.Fileoff
   698  		ms.filesize = Segdwarf.Fileoff + Segdwarf.Filelen - Segtext.Fileoff
   699  		ms.vsize = Segdwarf.Vaddr + Segdwarf.Length - Segtext.Vaddr
   700  	}
   701  
   702  	/* segment for zero page */
   703  	if ctxt.LinkMode != LinkExternal {
   704  		ms = newMachoSeg("__PAGEZERO", 0)
   705  		ms.vsize = uint64(va)
   706  	}
   707  
   708  	/* text */
   709  	v := Rnd(int64(uint64(HEADR)+Segtext.Length), int64(*FlagRound))
   710  
   711  	if ctxt.LinkMode != LinkExternal {
   712  		ms = newMachoSeg("__TEXT", 20)
   713  		ms.vaddr = uint64(va)
   714  		ms.vsize = uint64(v)
   715  		ms.fileoffset = 0
   716  		ms.filesize = uint64(v)
   717  		ms.prot1 = 7
   718  		ms.prot2 = 5
   719  	}
   720  
   721  	for _, sect := range Segtext.Sections {
   722  		machoshbits(ctxt, ms, sect, "__TEXT")
   723  	}
   724  
   725  	/* rodata */
   726  	if ctxt.LinkMode != LinkExternal && Segrelrodata.Length > 0 {
   727  		ms = newMachoSeg("__DATA_CONST", 20)
   728  		ms.vaddr = Segrelrodata.Vaddr
   729  		ms.vsize = Segrelrodata.Length
   730  		ms.fileoffset = Segrelrodata.Fileoff
   731  		ms.filesize = Segrelrodata.Filelen
   732  		ms.prot1 = 3
   733  		ms.prot2 = 3
   734  		ms.flag = 0x10 // SG_READ_ONLY
   735  	}
   736  
   737  	for _, sect := range Segrelrodata.Sections {
   738  		machoshbits(ctxt, ms, sect, "__DATA_CONST")
   739  	}
   740  
   741  	/* data */
   742  	if ctxt.LinkMode != LinkExternal {
   743  		ms = newMachoSeg("__DATA", 20)
   744  		ms.vaddr = Segdata.Vaddr
   745  		ms.vsize = Segdata.Length
   746  		ms.fileoffset = Segdata.Fileoff
   747  		ms.filesize = Segdata.Filelen
   748  		ms.prot1 = 3
   749  		ms.prot2 = 3
   750  	}
   751  
   752  	for _, sect := range Segdata.Sections {
   753  		machoshbits(ctxt, ms, sect, "__DATA")
   754  	}
   755  
   756  	/* dwarf */
   757  	if !*FlagW {
   758  		if ctxt.LinkMode != LinkExternal {
   759  			ms = newMachoSeg("__DWARF", 20)
   760  			ms.vaddr = Segdwarf.Vaddr
   761  			ms.vsize = 0
   762  			ms.fileoffset = Segdwarf.Fileoff
   763  			ms.filesize = Segdwarf.Filelen
   764  		}
   765  		for _, sect := range Segdwarf.Sections {
   766  			machoshbits(ctxt, ms, sect, "__DWARF")
   767  		}
   768  	}
   769  
   770  	if ctxt.LinkMode != LinkExternal {
   771  		switch ctxt.Arch.Family {
   772  		default:
   773  			Exitf("unknown macho architecture: %v", ctxt.Arch.Family)
   774  
   775  		case sys.AMD64:
   776  			ml := newMachoLoad(ctxt.Arch, LC_UNIXTHREAD, 42+2)
   777  			ml.data[0] = 4                           /* thread type */
   778  			ml.data[1] = 42                          /* word count */
   779  			ml.data[2+32] = uint32(Entryvalue(ctxt)) /* start pc */
   780  			ml.data[2+32+1] = uint32(Entryvalue(ctxt) >> 32)
   781  
   782  		case sys.ARM64:
   783  			ml := newMachoLoad(ctxt.Arch, LC_MAIN, 4)
   784  			ml.data[0] = uint32(uint64(Entryvalue(ctxt)) - (Segtext.Vaddr - uint64(HEADR)))
   785  			ml.data[1] = uint32((uint64(Entryvalue(ctxt)) - (Segtext.Vaddr - uint64(HEADR))) >> 32)
   786  		}
   787  	}
   788  
   789  	var codesigOff int64
   790  	if !*FlagD {
   791  		// must match doMachoLink below
   792  		s1 := ldr.SymSize(ldr.Lookup(".machorebase", 0))
   793  		s2 := ldr.SymSize(ldr.Lookup(".machobind", 0))
   794  		s3 := ldr.SymSize(ldr.Lookup(".machosymtab", 0))
   795  		s4 := ldr.SymSize(ctxt.ArchSyms.LinkEditPLT)
   796  		s5 := ldr.SymSize(ctxt.ArchSyms.LinkEditGOT)
   797  		s6 := ldr.SymSize(ldr.Lookup(".machosymstr", 0))
   798  		s7 := ldr.SymSize(ldr.Lookup(".machocodesig", 0))
   799  
   800  		if ctxt.LinkMode != LinkExternal {
   801  			ms := newMachoSeg("__LINKEDIT", 0)
   802  			ms.vaddr = uint64(Rnd(int64(Segdata.Vaddr+Segdata.Length), int64(*FlagRound)))
   803  			ms.vsize = uint64(s1 + s2 + s3 + s4 + s5 + s6 + s7)
   804  			ms.fileoffset = uint64(linkoff)
   805  			ms.filesize = ms.vsize
   806  			ms.prot1 = 1
   807  			ms.prot2 = 1
   808  
   809  			codesigOff = linkoff + s1 + s2 + s3 + s4 + s5 + s6
   810  		}
   811  
   812  		if ctxt.LinkMode != LinkExternal && ctxt.IsPIE() {
   813  			ml := newMachoLoad(ctxt.Arch, LC_DYLD_INFO_ONLY, 10)
   814  			ml.data[0] = uint32(linkoff)      // rebase off
   815  			ml.data[1] = uint32(s1)           // rebase size
   816  			ml.data[2] = uint32(linkoff + s1) // bind off
   817  			ml.data[3] = uint32(s2)           // bind size
   818  			ml.data[4] = 0                    // weak bind off
   819  			ml.data[5] = 0                    // weak bind size
   820  			ml.data[6] = 0                    // lazy bind off
   821  			ml.data[7] = 0                    // lazy bind size
   822  			ml.data[8] = 0                    // export
   823  			ml.data[9] = 0                    // export size
   824  		}
   825  
   826  		ml := newMachoLoad(ctxt.Arch, LC_SYMTAB, 4)
   827  		ml.data[0] = uint32(linkoff + s1 + s2)                /* symoff */
   828  		ml.data[1] = uint32(nsortsym)                         /* nsyms */
   829  		ml.data[2] = uint32(linkoff + s1 + s2 + s3 + s4 + s5) /* stroff */
   830  		ml.data[3] = uint32(s6)                               /* strsize */
   831  
   832  		machodysymtab(ctxt, linkoff+s1+s2)
   833  
   834  		if ctxt.LinkMode != LinkExternal {
   835  			ml := newMachoLoad(ctxt.Arch, LC_LOAD_DYLINKER, 6)
   836  			ml.data[0] = 12 /* offset to string */
   837  			stringtouint32(ml.data[1:], "/usr/lib/dyld")
   838  
   839  			for _, lib := range dylib {
   840  				ml = newMachoLoad(ctxt.Arch, LC_LOAD_DYLIB, 4+(uint32(len(lib))+1+7)/8*2)
   841  				ml.data[0] = 24 /* offset of string from beginning of load */
   842  				ml.data[1] = 0  /* time stamp */
   843  				ml.data[2] = 0  /* version */
   844  				ml.data[3] = 0  /* compatibility version */
   845  				stringtouint32(ml.data[4:], lib)
   846  			}
   847  		}
   848  
   849  		if ctxt.IsInternal() && ctxt.NeedCodeSign() {
   850  			ml := newMachoLoad(ctxt.Arch, LC_CODE_SIGNATURE, 2)
   851  			ml.data[0] = uint32(codesigOff)
   852  			ml.data[1] = uint32(s7)
   853  		}
   854  	}
   855  
   856  	a := machowrite(ctxt, ctxt.Arch, ctxt.Out, ctxt.LinkMode)
   857  	if int32(a) > HEADR {
   858  		Exitf("HEADR too small: %d > %d", a, HEADR)
   859  	}
   860  
   861  	// Now we have written everything. Compute the code signature (which
   862  	// is a hash of the file content, so it must be done at last.)
   863  	if ctxt.IsInternal() && ctxt.NeedCodeSign() {
   864  		cs := ldr.Lookup(".machocodesig", 0)
   865  		data := ctxt.Out.Data()
   866  		if int64(len(data)) != codesigOff {
   867  			panic("wrong size")
   868  		}
   869  		codesign.Sign(ldr.Data(cs), bytes.NewReader(data), "a.out", codesigOff, int64(Segtext.Fileoff), int64(Segtext.Filelen), ctxt.IsExe() || ctxt.IsPIE())
   870  		ctxt.Out.SeekSet(codesigOff)
   871  		ctxt.Out.Write(ldr.Data(cs))
   872  	}
   873  }
   874  
   875  func symkind(ldr *loader.Loader, s loader.Sym) int {
   876  	if ldr.SymType(s) == sym.SDYNIMPORT {
   877  		return SymKindUndef
   878  	}
   879  	if ldr.AttrCgoExport(s) {
   880  		return SymKindExtdef
   881  	}
   882  	return SymKindLocal
   883  }
   884  
   885  func collectmachosyms(ctxt *Link) {
   886  	ldr := ctxt.loader
   887  
   888  	addsym := func(s loader.Sym) {
   889  		sortsym = append(sortsym, s)
   890  		nkind[symkind(ldr, s)]++
   891  	}
   892  
   893  	// Add special runtime.text and runtime.etext symbols.
   894  	// We've already included this symbol in Textp on darwin if ctxt.DynlinkingGo().
   895  	// See data.go:/textaddress
   896  	if !ctxt.DynlinkingGo() {
   897  		s := ldr.Lookup("runtime.text", 0)
   898  		if ldr.SymType(s) == sym.STEXT {
   899  			addsym(s)
   900  		}
   901  		s = ldr.Lookup("runtime.etext", 0)
   902  		if ldr.SymType(s) == sym.STEXT {
   903  			addsym(s)
   904  		}
   905  	}
   906  
   907  	// Add text symbols.
   908  	for _, s := range ctxt.Textp {
   909  		addsym(s)
   910  	}
   911  
   912  	shouldBeInSymbolTable := func(s loader.Sym) bool {
   913  		if ldr.AttrNotInSymbolTable(s) {
   914  			return false
   915  		}
   916  		name := ldr.RawSymName(s) // TODO: try not to read the name
   917  		if name == "" || name[0] == '.' {
   918  			return false
   919  		}
   920  		return true
   921  	}
   922  
   923  	// Add data symbols and external references.
   924  	for s := loader.Sym(1); s < loader.Sym(ldr.NSym()); s++ {
   925  		if !ldr.AttrReachable(s) {
   926  			continue
   927  		}
   928  		t := ldr.SymType(s)
   929  		if t >= sym.SELFRXSECT && t < sym.SXREF { // data sections handled in dodata
   930  			if t == sym.STLSBSS {
   931  				// TLSBSS is not used on darwin. See data.go:allocateDataSections
   932  				continue
   933  			}
   934  			if !shouldBeInSymbolTable(s) {
   935  				continue
   936  			}
   937  			addsym(s)
   938  		}
   939  
   940  		switch t {
   941  		case sym.SDYNIMPORT, sym.SHOSTOBJ, sym.SUNDEFEXT:
   942  			addsym(s)
   943  		}
   944  
   945  		// Some 64-bit functions have a "$INODE64" or "$INODE64$UNIX2003" suffix.
   946  		if t == sym.SDYNIMPORT && ldr.SymDynimplib(s) == "/usr/lib/libSystem.B.dylib" {
   947  			// But only on macOS.
   948  			if machoPlatform == PLATFORM_MACOS {
   949  				switch n := ldr.SymExtname(s); n {
   950  				case "fdopendir":
   951  					switch buildcfg.GOARCH {
   952  					case "amd64":
   953  						ldr.SetSymExtname(s, n+"$INODE64")
   954  					}
   955  				case "readdir_r", "getfsstat":
   956  					switch buildcfg.GOARCH {
   957  					case "amd64":
   958  						ldr.SetSymExtname(s, n+"$INODE64")
   959  					}
   960  				}
   961  			}
   962  		}
   963  	}
   964  
   965  	nsortsym = len(sortsym)
   966  }
   967  
   968  func machosymorder(ctxt *Link) {
   969  	ldr := ctxt.loader
   970  
   971  	// On Mac OS X Mountain Lion, we must sort exported symbols
   972  	// So we sort them here and pre-allocate dynid for them
   973  	// See https://golang.org/issue/4029
   974  	for _, s := range ctxt.dynexp {
   975  		if !ldr.AttrReachable(s) {
   976  			panic("dynexp symbol is not reachable")
   977  		}
   978  	}
   979  	collectmachosyms(ctxt)
   980  	sort.Slice(sortsym[:nsortsym], func(i, j int) bool {
   981  		s1 := sortsym[i]
   982  		s2 := sortsym[j]
   983  		k1 := symkind(ldr, s1)
   984  		k2 := symkind(ldr, s2)
   985  		if k1 != k2 {
   986  			return k1 < k2
   987  		}
   988  		return ldr.SymExtname(s1) < ldr.SymExtname(s2) // Note: unnamed symbols are not added in collectmachosyms
   989  	})
   990  	for i, s := range sortsym {
   991  		ldr.SetSymDynid(s, int32(i))
   992  	}
   993  }
   994  
   995  // AddMachoSym adds s to Mach-O symbol table, used in GenSymLate.
   996  // Currently only used on ARM64 when external linking.
   997  func AddMachoSym(ldr *loader.Loader, s loader.Sym) {
   998  	ldr.SetSymDynid(s, int32(nsortsym))
   999  	sortsym = append(sortsym, s)
  1000  	nsortsym++
  1001  	nkind[symkind(ldr, s)]++
  1002  }
  1003  
  1004  // machoShouldExport reports whether a symbol needs to be exported.
  1005  //
  1006  // When dynamically linking, all non-local variables and plugin-exported
  1007  // symbols need to be exported.
  1008  func machoShouldExport(ctxt *Link, ldr *loader.Loader, s loader.Sym) bool {
  1009  	if !ctxt.DynlinkingGo() || ldr.AttrLocal(s) {
  1010  		return false
  1011  	}
  1012  	if ctxt.BuildMode == BuildModePlugin && strings.HasPrefix(ldr.SymExtname(s), objabi.PathToPrefix(*flagPluginPath)) {
  1013  		return true
  1014  	}
  1015  	name := ldr.RawSymName(s)
  1016  	if strings.HasPrefix(name, "go.itab.") {
  1017  		return true
  1018  	}
  1019  	if strings.HasPrefix(name, "type.") && !strings.HasPrefix(name, "type..") {
  1020  		// reduce runtime typemap pressure, but do not
  1021  		// export alg functions (type..*), as these
  1022  		// appear in pclntable.
  1023  		return true
  1024  	}
  1025  	if strings.HasPrefix(name, "go.link.pkghash") {
  1026  		return true
  1027  	}
  1028  	return ldr.SymType(s) >= sym.SFirstWritable // only writable sections
  1029  }
  1030  
  1031  func machosymtab(ctxt *Link) {
  1032  	ldr := ctxt.loader
  1033  	symtab := ldr.CreateSymForUpdate(".machosymtab", 0)
  1034  	symstr := ldr.CreateSymForUpdate(".machosymstr", 0)
  1035  
  1036  	for _, s := range sortsym[:nsortsym] {
  1037  		symtab.AddUint32(ctxt.Arch, uint32(symstr.Size()))
  1038  
  1039  		export := machoShouldExport(ctxt, ldr, s)
  1040  
  1041  		// Prefix symbol names with "_" to match the system toolchain.
  1042  		// (We used to only prefix C symbols, which is all required for the build.
  1043  		// But some tools don't recognize Go symbols as symbols, so we prefix them
  1044  		// as well.)
  1045  		symstr.AddUint8('_')
  1046  
  1047  		// replace "·" as ".", because DTrace cannot handle it.
  1048  		name := strings.Replace(ldr.SymExtname(s), "·", ".", -1)
  1049  
  1050  		name = mangleABIName(ctxt, ldr, s, name)
  1051  		symstr.Addstring(name)
  1052  
  1053  		if t := ldr.SymType(s); t == sym.SDYNIMPORT || t == sym.SHOSTOBJ || t == sym.SUNDEFEXT {
  1054  			symtab.AddUint8(0x01)                             // type N_EXT, external symbol
  1055  			symtab.AddUint8(0)                                // no section
  1056  			symtab.AddUint16(ctxt.Arch, 0)                    // desc
  1057  			symtab.AddUintXX(ctxt.Arch, 0, ctxt.Arch.PtrSize) // no value
  1058  		} else {
  1059  			if export || ldr.AttrCgoExportDynamic(s) {
  1060  				symtab.AddUint8(0x0f) // N_SECT | N_EXT
  1061  			} else if ldr.AttrCgoExportStatic(s) {
  1062  				// Only export statically, not dynamically. (N_PEXT is like hidden visibility)
  1063  				symtab.AddUint8(0x1f) // N_SECT | N_EXT | N_PEXT
  1064  			} else {
  1065  				symtab.AddUint8(0x0e) // N_SECT
  1066  			}
  1067  			o := s
  1068  			if outer := ldr.OuterSym(o); outer != 0 {
  1069  				o = outer
  1070  			}
  1071  			if ldr.SymSect(o) == nil {
  1072  				ldr.Errorf(s, "missing section for symbol")
  1073  				symtab.AddUint8(0)
  1074  			} else {
  1075  				symtab.AddUint8(uint8(ldr.SymSect(o).Extnum))
  1076  			}
  1077  			symtab.AddUint16(ctxt.Arch, 0) // desc
  1078  			symtab.AddUintXX(ctxt.Arch, uint64(ldr.SymAddr(s)), ctxt.Arch.PtrSize)
  1079  		}
  1080  	}
  1081  }
  1082  
  1083  func machodysymtab(ctxt *Link, base int64) {
  1084  	ml := newMachoLoad(ctxt.Arch, LC_DYSYMTAB, 18)
  1085  
  1086  	n := 0
  1087  	ml.data[0] = uint32(n)                   /* ilocalsym */
  1088  	ml.data[1] = uint32(nkind[SymKindLocal]) /* nlocalsym */
  1089  	n += nkind[SymKindLocal]
  1090  
  1091  	ml.data[2] = uint32(n)                    /* iextdefsym */
  1092  	ml.data[3] = uint32(nkind[SymKindExtdef]) /* nextdefsym */
  1093  	n += nkind[SymKindExtdef]
  1094  
  1095  	ml.data[4] = uint32(n)                   /* iundefsym */
  1096  	ml.data[5] = uint32(nkind[SymKindUndef]) /* nundefsym */
  1097  
  1098  	ml.data[6] = 0  /* tocoffset */
  1099  	ml.data[7] = 0  /* ntoc */
  1100  	ml.data[8] = 0  /* modtaboff */
  1101  	ml.data[9] = 0  /* nmodtab */
  1102  	ml.data[10] = 0 /* extrefsymoff */
  1103  	ml.data[11] = 0 /* nextrefsyms */
  1104  
  1105  	ldr := ctxt.loader
  1106  
  1107  	// must match domacholink below
  1108  	s1 := ldr.SymSize(ldr.Lookup(".machosymtab", 0))
  1109  	s2 := ldr.SymSize(ctxt.ArchSyms.LinkEditPLT)
  1110  	s3 := ldr.SymSize(ctxt.ArchSyms.LinkEditGOT)
  1111  	ml.data[12] = uint32(base + s1)     /* indirectsymoff */
  1112  	ml.data[13] = uint32((s2 + s3) / 4) /* nindirectsyms */
  1113  
  1114  	ml.data[14] = 0 /* extreloff */
  1115  	ml.data[15] = 0 /* nextrel */
  1116  	ml.data[16] = 0 /* locreloff */
  1117  	ml.data[17] = 0 /* nlocrel */
  1118  }
  1119  
  1120  func doMachoLink(ctxt *Link) int64 {
  1121  	machosymtab(ctxt)
  1122  	machoDyldInfo(ctxt)
  1123  
  1124  	ldr := ctxt.loader
  1125  
  1126  	// write data that will be linkedit section
  1127  	s1 := ldr.Lookup(".machorebase", 0)
  1128  	s2 := ldr.Lookup(".machobind", 0)
  1129  	s3 := ldr.Lookup(".machosymtab", 0)
  1130  	s4 := ctxt.ArchSyms.LinkEditPLT
  1131  	s5 := ctxt.ArchSyms.LinkEditGOT
  1132  	s6 := ldr.Lookup(".machosymstr", 0)
  1133  
  1134  	size := ldr.SymSize(s1) + ldr.SymSize(s2) + ldr.SymSize(s3) + ldr.SymSize(s4) + ldr.SymSize(s5) + ldr.SymSize(s6)
  1135  
  1136  	// Force the linkedit section to end on a 16-byte
  1137  	// boundary. This allows pure (non-cgo) Go binaries
  1138  	// to be code signed correctly.
  1139  	//
  1140  	// Apple's codesign_allocate (a helper utility for
  1141  	// the codesign utility) can do this fine itself if
  1142  	// it is run on a dynamic Mach-O binary. However,
  1143  	// when it is run on a pure (non-cgo) Go binary, where
  1144  	// the linkedit section is mostly empty, it fails to
  1145  	// account for the extra padding that it itself adds
  1146  	// when adding the LC_CODE_SIGNATURE load command
  1147  	// (which must be aligned on a 16-byte boundary).
  1148  	//
  1149  	// By forcing the linkedit section to end on a 16-byte
  1150  	// boundary, codesign_allocate will not need to apply
  1151  	// any alignment padding itself, working around the
  1152  	// issue.
  1153  	if size%16 != 0 {
  1154  		n := 16 - size%16
  1155  		s6b := ldr.MakeSymbolUpdater(s6)
  1156  		s6b.Grow(s6b.Size() + n)
  1157  		s6b.SetSize(s6b.Size() + n)
  1158  		size += n
  1159  	}
  1160  
  1161  	if size > 0 {
  1162  		linkoff = Rnd(int64(uint64(HEADR)+Segtext.Length), int64(*FlagRound)) + Rnd(int64(Segrelrodata.Filelen), int64(*FlagRound)) + Rnd(int64(Segdata.Filelen), int64(*FlagRound)) + Rnd(int64(Segdwarf.Filelen), int64(*FlagRound))
  1163  		ctxt.Out.SeekSet(linkoff)
  1164  
  1165  		ctxt.Out.Write(ldr.Data(s1))
  1166  		ctxt.Out.Write(ldr.Data(s2))
  1167  		ctxt.Out.Write(ldr.Data(s3))
  1168  		ctxt.Out.Write(ldr.Data(s4))
  1169  		ctxt.Out.Write(ldr.Data(s5))
  1170  		ctxt.Out.Write(ldr.Data(s6))
  1171  
  1172  		// Add code signature if necessary. This must be the last.
  1173  		s7 := machoCodeSigSym(ctxt, linkoff+size)
  1174  		size += ldr.SymSize(s7)
  1175  	}
  1176  
  1177  	return Rnd(size, int64(*FlagRound))
  1178  }
  1179  
  1180  func machorelocsect(ctxt *Link, out *OutBuf, sect *sym.Section, syms []loader.Sym) {
  1181  	// If main section has no bits, nothing to relocate.
  1182  	if sect.Vaddr >= sect.Seg.Vaddr+sect.Seg.Filelen {
  1183  		return
  1184  	}
  1185  	ldr := ctxt.loader
  1186  
  1187  	for i, s := range syms {
  1188  		if !ldr.AttrReachable(s) {
  1189  			continue
  1190  		}
  1191  		if uint64(ldr.SymValue(s)) >= sect.Vaddr {
  1192  			syms = syms[i:]
  1193  			break
  1194  		}
  1195  	}
  1196  
  1197  	eaddr := sect.Vaddr + sect.Length
  1198  	for _, s := range syms {
  1199  		if !ldr.AttrReachable(s) {
  1200  			continue
  1201  		}
  1202  		if ldr.SymValue(s) >= int64(eaddr) {
  1203  			break
  1204  		}
  1205  
  1206  		// Compute external relocations on the go, and pass to Machoreloc1
  1207  		// to stream out.
  1208  		relocs := ldr.Relocs(s)
  1209  		for ri := 0; ri < relocs.Count(); ri++ {
  1210  			r := relocs.At(ri)
  1211  			rr, ok := extreloc(ctxt, ldr, s, r)
  1212  			if !ok {
  1213  				continue
  1214  			}
  1215  			if rr.Xsym == 0 {
  1216  				ldr.Errorf(s, "missing xsym in relocation")
  1217  				continue
  1218  			}
  1219  			if !ldr.AttrReachable(rr.Xsym) {
  1220  				ldr.Errorf(s, "unreachable reloc %d (%s) target %v", r.Type(), sym.RelocName(ctxt.Arch, r.Type()), ldr.SymName(rr.Xsym))
  1221  			}
  1222  			if !thearch.Machoreloc1(ctxt.Arch, out, ldr, s, rr, int64(uint64(ldr.SymValue(s)+int64(r.Off()))-sect.Vaddr)) {
  1223  				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()))
  1224  			}
  1225  		}
  1226  	}
  1227  
  1228  	// sanity check
  1229  	if uint64(out.Offset()) != sect.Reloff+sect.Rellen {
  1230  		panic("machorelocsect: size mismatch")
  1231  	}
  1232  }
  1233  
  1234  func machoEmitReloc(ctxt *Link) {
  1235  	for ctxt.Out.Offset()&7 != 0 {
  1236  		ctxt.Out.Write8(0)
  1237  	}
  1238  
  1239  	sizeExtRelocs(ctxt, thearch.MachorelocSize)
  1240  	relocSect, wg := relocSectFn(ctxt, machorelocsect)
  1241  
  1242  	relocSect(ctxt, Segtext.Sections[0], ctxt.Textp)
  1243  	for _, sect := range Segtext.Sections[1:] {
  1244  		if sect.Name == ".text" {
  1245  			relocSect(ctxt, sect, ctxt.Textp)
  1246  		} else {
  1247  			relocSect(ctxt, sect, ctxt.datap)
  1248  		}
  1249  	}
  1250  	for _, sect := range Segrelrodata.Sections {
  1251  		relocSect(ctxt, sect, ctxt.datap)
  1252  	}
  1253  	for _, sect := range Segdata.Sections {
  1254  		relocSect(ctxt, sect, ctxt.datap)
  1255  	}
  1256  	for i := 0; i < len(Segdwarf.Sections); i++ {
  1257  		sect := Segdwarf.Sections[i]
  1258  		si := dwarfp[i]
  1259  		if si.secSym() != loader.Sym(sect.Sym) ||
  1260  			ctxt.loader.SymSect(si.secSym()) != sect {
  1261  			panic("inconsistency between dwarfp and Segdwarf")
  1262  		}
  1263  		relocSect(ctxt, sect, si.syms)
  1264  	}
  1265  	wg.Wait()
  1266  }
  1267  
  1268  // hostobjMachoPlatform returns the first platform load command found
  1269  // in the host object, if any.
  1270  func hostobjMachoPlatform(h *Hostobj) (*MachoPlatformLoad, error) {
  1271  	f, err := os.Open(h.file)
  1272  	if err != nil {
  1273  		return nil, fmt.Errorf("%s: failed to open host object: %v\n", h.file, err)
  1274  	}
  1275  	defer f.Close()
  1276  	sr := io.NewSectionReader(f, h.off, h.length)
  1277  	m, err := macho.NewFile(sr)
  1278  	if err != nil {
  1279  		// Not a valid Mach-O file.
  1280  		return nil, nil
  1281  	}
  1282  	return peekMachoPlatform(m)
  1283  }
  1284  
  1285  // peekMachoPlatform returns the first LC_VERSION_MIN_* or LC_BUILD_VERSION
  1286  // load command found in the Mach-O file, if any.
  1287  func peekMachoPlatform(m *macho.File) (*MachoPlatformLoad, error) {
  1288  	for _, cmd := range m.Loads {
  1289  		raw := cmd.Raw()
  1290  		ml := MachoLoad{
  1291  			type_: m.ByteOrder.Uint32(raw),
  1292  		}
  1293  		// Skip the type and command length.
  1294  		data := raw[8:]
  1295  		var p MachoPlatform
  1296  		switch ml.type_ {
  1297  		case LC_VERSION_MIN_IPHONEOS:
  1298  			p = PLATFORM_IOS
  1299  		case LC_VERSION_MIN_MACOSX:
  1300  			p = PLATFORM_MACOS
  1301  		case LC_VERSION_MIN_WATCHOS:
  1302  			p = PLATFORM_WATCHOS
  1303  		case LC_VERSION_MIN_TVOS:
  1304  			p = PLATFORM_TVOS
  1305  		case LC_BUILD_VERSION:
  1306  			p = MachoPlatform(m.ByteOrder.Uint32(data))
  1307  		default:
  1308  			continue
  1309  		}
  1310  		ml.data = make([]uint32, len(data)/4)
  1311  		r := bytes.NewReader(data)
  1312  		if err := binary.Read(r, m.ByteOrder, &ml.data); err != nil {
  1313  			return nil, err
  1314  		}
  1315  		return &MachoPlatformLoad{
  1316  			platform: p,
  1317  			cmd:      ml,
  1318  		}, nil
  1319  	}
  1320  	return nil, nil
  1321  }
  1322  
  1323  // A rebase entry tells the dynamic linker the data at sym+off needs to be
  1324  // relocated when the in-memory image moves. (This is somewhat like, say,
  1325  // ELF R_X86_64_RELATIVE).
  1326  // For now, the only kind of entry we support is that the data is an absolute
  1327  // address. That seems all we need.
  1328  // In the binary it uses a compact stateful bytecode encoding. So we record
  1329  // entries as we go and build the table at the end.
  1330  type machoRebaseRecord struct {
  1331  	sym loader.Sym
  1332  	off int64
  1333  }
  1334  
  1335  var machorebase []machoRebaseRecord
  1336  
  1337  func MachoAddRebase(s loader.Sym, off int64) {
  1338  	machorebase = append(machorebase, machoRebaseRecord{s, off})
  1339  }
  1340  
  1341  // A bind entry tells the dynamic linker the data at GOT+off should be bound
  1342  // to the address of the target symbol, which is a dynamic import.
  1343  // For now, the only kind of entry we support is that the data is an absolute
  1344  // address, and the source symbol is always the GOT. That seems all we need.
  1345  // In the binary it uses a compact stateful bytecode encoding. So we record
  1346  // entries as we go and build the table at the end.
  1347  type machoBindRecord struct {
  1348  	off  int64
  1349  	targ loader.Sym
  1350  }
  1351  
  1352  var machobind []machoBindRecord
  1353  
  1354  func MachoAddBind(off int64, targ loader.Sym) {
  1355  	machobind = append(machobind, machoBindRecord{off, targ})
  1356  }
  1357  
  1358  // Generate data for the dynamic linker, used in LC_DYLD_INFO_ONLY load command.
  1359  // See mach-o/loader.h, struct dyld_info_command, for the encoding.
  1360  // e.g. https://opensource.apple.com/source/xnu/xnu-6153.81.5/EXTERNAL_HEADERS/mach-o/loader.h
  1361  func machoDyldInfo(ctxt *Link) {
  1362  	ldr := ctxt.loader
  1363  	rebase := ldr.CreateSymForUpdate(".machorebase", 0)
  1364  	bind := ldr.CreateSymForUpdate(".machobind", 0)
  1365  
  1366  	if !(ctxt.IsPIE() && ctxt.IsInternal()) {
  1367  		return
  1368  	}
  1369  
  1370  	segId := func(seg *sym.Segment) uint8 {
  1371  		switch seg {
  1372  		case &Segtext:
  1373  			return 1
  1374  		case &Segrelrodata:
  1375  			return 2
  1376  		case &Segdata:
  1377  			if Segrelrodata.Length > 0 {
  1378  				return 3
  1379  			}
  1380  			return 2
  1381  		}
  1382  		panic("unknown segment")
  1383  	}
  1384  
  1385  	dylibId := func(s loader.Sym) int {
  1386  		slib := ldr.SymDynimplib(s)
  1387  		for i, lib := range dylib {
  1388  			if lib == slib {
  1389  				return i + 1
  1390  			}
  1391  		}
  1392  		return BIND_SPECIAL_DYLIB_FLAT_LOOKUP // don't know where it is from
  1393  	}
  1394  
  1395  	// Rebase table.
  1396  	// TODO: use more compact encoding. The encoding is stateful, and
  1397  	// we can use delta encoding.
  1398  	rebase.AddUint8(REBASE_OPCODE_SET_TYPE_IMM | REBASE_TYPE_POINTER)
  1399  	for _, r := range machorebase {
  1400  		seg := ldr.SymSect(r.sym).Seg
  1401  		off := uint64(ldr.SymValue(r.sym)+r.off) - seg.Vaddr
  1402  		rebase.AddUint8(REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | segId(seg))
  1403  		rebase.AddUleb(off)
  1404  
  1405  		rebase.AddUint8(REBASE_OPCODE_DO_REBASE_IMM_TIMES | 1)
  1406  	}
  1407  	rebase.AddUint8(REBASE_OPCODE_DONE)
  1408  	sz := Rnd(rebase.Size(), 8)
  1409  	rebase.Grow(sz)
  1410  	rebase.SetSize(sz)
  1411  
  1412  	// Bind table.
  1413  	// TODO: compact encoding, as above.
  1414  	// TODO: lazy binding?
  1415  	got := ctxt.GOT
  1416  	seg := ldr.SymSect(got).Seg
  1417  	gotAddr := ldr.SymValue(got)
  1418  	bind.AddUint8(BIND_OPCODE_SET_TYPE_IMM | BIND_TYPE_POINTER)
  1419  	for _, r := range machobind {
  1420  		off := uint64(gotAddr+r.off) - seg.Vaddr
  1421  		bind.AddUint8(BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | segId(seg))
  1422  		bind.AddUleb(off)
  1423  
  1424  		d := dylibId(r.targ)
  1425  		if d > 0 && d < 128 {
  1426  			bind.AddUint8(BIND_OPCODE_SET_DYLIB_ORDINAL_IMM | uint8(d)&0xf)
  1427  		} else if d >= 128 {
  1428  			bind.AddUint8(BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB)
  1429  			bind.AddUleb(uint64(d))
  1430  		} else { // d <= 0
  1431  			bind.AddUint8(BIND_OPCODE_SET_DYLIB_SPECIAL_IMM | uint8(d)&0xf)
  1432  		}
  1433  
  1434  		bind.AddUint8(BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM)
  1435  		// target symbol name as a C string, with _ prefix
  1436  		bind.AddUint8('_')
  1437  		bind.Addstring(ldr.SymExtname(r.targ))
  1438  
  1439  		bind.AddUint8(BIND_OPCODE_DO_BIND)
  1440  	}
  1441  	bind.AddUint8(BIND_OPCODE_DONE)
  1442  	sz = Rnd(bind.Size(), 16) // make it 16-byte aligned, see the comment in doMachoLink
  1443  	bind.Grow(sz)
  1444  	bind.SetSize(sz)
  1445  
  1446  	// TODO: export table.
  1447  	// The symbols names are encoded as a trie. I'm really too lazy to do that
  1448  	// for now.
  1449  	// Without it, the symbols are not dynamically exported, so they cannot be
  1450  	// e.g. dlsym'd. But internal linking is not the default in that case, so
  1451  	// it is fine.
  1452  }
  1453  
  1454  // machoCodeSigSym creates and returns a symbol for code signature.
  1455  // The symbol context is left as zeros, which will be generated at the end
  1456  // (as it depends on the rest of the file).
  1457  func machoCodeSigSym(ctxt *Link, codeSize int64) loader.Sym {
  1458  	ldr := ctxt.loader
  1459  	cs := ldr.CreateSymForUpdate(".machocodesig", 0)
  1460  	if !ctxt.NeedCodeSign() || ctxt.IsExternal() {
  1461  		return cs.Sym()
  1462  	}
  1463  	sz := codesign.Size(codeSize, "a.out")
  1464  	cs.Grow(sz)
  1465  	cs.SetSize(sz)
  1466  	return cs.Sym()
  1467  }
  1468  
  1469  // machoCodeSign code-signs Mach-O file fname with an ad-hoc signature.
  1470  // This is used for updating an external linker generated binary.
  1471  func machoCodeSign(ctxt *Link, fname string) error {
  1472  	f, err := os.OpenFile(fname, os.O_RDWR, 0)
  1473  	if err != nil {
  1474  		return err
  1475  	}
  1476  	defer f.Close()
  1477  
  1478  	mf, err := macho.NewFile(f)
  1479  	if err != nil {
  1480  		return err
  1481  	}
  1482  	if mf.Magic != macho.Magic64 {
  1483  		Exitf("not 64-bit Mach-O file: %s", fname)
  1484  	}
  1485  
  1486  	// Find existing LC_CODE_SIGNATURE and __LINKEDIT segment
  1487  	var sigOff, sigSz, csCmdOff, linkeditOff int64
  1488  	var linkeditSeg, textSeg *macho.Segment
  1489  	loadOff := int64(machoHeaderSize64)
  1490  	get32 := mf.ByteOrder.Uint32
  1491  	for _, l := range mf.Loads {
  1492  		data := l.Raw()
  1493  		cmd, sz := get32(data), get32(data[4:])
  1494  		if cmd == LC_CODE_SIGNATURE {
  1495  			sigOff = int64(get32(data[8:]))
  1496  			sigSz = int64(get32(data[12:]))
  1497  			csCmdOff = loadOff
  1498  		}
  1499  		if seg, ok := l.(*macho.Segment); ok {
  1500  			switch seg.Name {
  1501  			case "__LINKEDIT":
  1502  				linkeditSeg = seg
  1503  				linkeditOff = loadOff
  1504  			case "__TEXT":
  1505  				textSeg = seg
  1506  			}
  1507  		}
  1508  		loadOff += int64(sz)
  1509  	}
  1510  
  1511  	if sigOff == 0 {
  1512  		// The C linker doesn't generate a signed binary, for some reason.
  1513  		// Skip.
  1514  		return nil
  1515  	}
  1516  
  1517  	fi, err := f.Stat()
  1518  	if err != nil {
  1519  		return err
  1520  	}
  1521  	if sigOff+sigSz != fi.Size() {
  1522  		// We don't expect anything after the signature (this will invalidate
  1523  		// the signature anyway.)
  1524  		return fmt.Errorf("unexpected content after code signature")
  1525  	}
  1526  
  1527  	sz := codesign.Size(sigOff, "a.out")
  1528  	if sz != sigSz {
  1529  		// Update the load command,
  1530  		var tmp [8]byte
  1531  		mf.ByteOrder.PutUint32(tmp[:4], uint32(sz))
  1532  		_, err = f.WriteAt(tmp[:4], csCmdOff+12)
  1533  		if err != nil {
  1534  			return err
  1535  		}
  1536  
  1537  		// Uodate the __LINKEDIT segment.
  1538  		segSz := sigOff + sz - int64(linkeditSeg.Offset)
  1539  		mf.ByteOrder.PutUint64(tmp[:8], uint64(segSz))
  1540  		_, err = f.WriteAt(tmp[:8], int64(linkeditOff)+int64(unsafe.Offsetof(macho.Segment64{}.Memsz)))
  1541  		if err != nil {
  1542  			return err
  1543  		}
  1544  		_, err = f.WriteAt(tmp[:8], int64(linkeditOff)+int64(unsafe.Offsetof(macho.Segment64{}.Filesz)))
  1545  		if err != nil {
  1546  			return err
  1547  		}
  1548  	}
  1549  
  1550  	cs := make([]byte, sz)
  1551  	codesign.Sign(cs, f, "a.out", sigOff, int64(textSeg.Offset), int64(textSeg.Filesz), ctxt.IsExe() || ctxt.IsPIE())
  1552  	_, err = f.WriteAt(cs, sigOff)
  1553  	if err != nil {
  1554  		return err
  1555  	}
  1556  	err = f.Truncate(sigOff + sz)
  1557  	return err
  1558  }
  1559  

View as plain text