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

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

View as plain text