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

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

View as plain text