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

View as plain text