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

View as plain text