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

View as plain text