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

View as plain text