github.com/ltltlt/go-source-code@v0.0.0-20190830023027-95be009773aa/cmd/link/internal/ld/macho.go (about)

     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  	"cmd/internal/objabi"
     9  	"cmd/internal/sys"
    10  	"cmd/link/internal/sym"
    11  	"sort"
    12  	"strings"
    13  )
    14  
    15  type MachoHdr struct {
    16  	cpu    uint32
    17  	subcpu uint32
    18  }
    19  
    20  type MachoSect struct {
    21  	name    string
    22  	segname string
    23  	addr    uint64
    24  	size    uint64
    25  	off     uint32
    26  	align   uint32
    27  	reloc   uint32
    28  	nreloc  uint32
    29  	flag    uint32
    30  	res1    uint32
    31  	res2    uint32
    32  }
    33  
    34  type MachoSeg struct {
    35  	name       string
    36  	vsize      uint64
    37  	vaddr      uint64
    38  	fileoffset uint64
    39  	filesize   uint64
    40  	prot1      uint32
    41  	prot2      uint32
    42  	nsect      uint32
    43  	msect      uint32
    44  	sect       []MachoSect
    45  	flag       uint32
    46  }
    47  
    48  type MachoLoad struct {
    49  	type_ uint32
    50  	data  []uint32
    51  }
    52  
    53  /*
    54   * Total amount of space to reserve at the start of the file
    55   * for Header, PHeaders, and SHeaders.
    56   * May waste some.
    57   */
    58  const (
    59  	INITIAL_MACHO_HEADR = 4 * 1024
    60  )
    61  
    62  const (
    63  	MACHO_CPU_AMD64               = 1<<24 | 7
    64  	MACHO_CPU_386                 = 7
    65  	MACHO_SUBCPU_X86              = 3
    66  	MACHO_CPU_ARM                 = 12
    67  	MACHO_SUBCPU_ARM              = 0
    68  	MACHO_SUBCPU_ARMV7            = 9
    69  	MACHO_CPU_ARM64               = 1<<24 | 12
    70  	MACHO_SUBCPU_ARM64_ALL        = 0
    71  	MACHO32SYMSIZE                = 12
    72  	MACHO64SYMSIZE                = 16
    73  	MACHO_X86_64_RELOC_UNSIGNED   = 0
    74  	MACHO_X86_64_RELOC_SIGNED     = 1
    75  	MACHO_X86_64_RELOC_BRANCH     = 2
    76  	MACHO_X86_64_RELOC_GOT_LOAD   = 3
    77  	MACHO_X86_64_RELOC_GOT        = 4
    78  	MACHO_X86_64_RELOC_SUBTRACTOR = 5
    79  	MACHO_X86_64_RELOC_SIGNED_1   = 6
    80  	MACHO_X86_64_RELOC_SIGNED_2   = 7
    81  	MACHO_X86_64_RELOC_SIGNED_4   = 8
    82  	MACHO_ARM_RELOC_VANILLA       = 0
    83  	MACHO_ARM_RELOC_PAIR          = 1
    84  	MACHO_ARM_RELOC_SECTDIFF      = 2
    85  	MACHO_ARM_RELOC_BR24          = 5
    86  	MACHO_ARM64_RELOC_UNSIGNED    = 0
    87  	MACHO_ARM64_RELOC_BRANCH26    = 2
    88  	MACHO_ARM64_RELOC_PAGE21      = 3
    89  	MACHO_ARM64_RELOC_PAGEOFF12   = 4
    90  	MACHO_ARM64_RELOC_ADDEND      = 10
    91  	MACHO_GENERIC_RELOC_VANILLA   = 0
    92  	MACHO_FAKE_GOTPCREL           = 100
    93  )
    94  
    95  const (
    96  	MH_MAGIC    = 0xfeedface
    97  	MH_MAGIC_64 = 0xfeedfacf
    98  
    99  	MH_OBJECT  = 0x1
   100  	MH_EXECUTE = 0x2
   101  
   102  	MH_NOUNDEFS = 0x1
   103  )
   104  
   105  const (
   106  	LC_SEGMENT              = 0x1
   107  	LC_SYMTAB               = 0x2
   108  	LC_UNIXTHREAD           = 0x5
   109  	LC_DYSYMTAB             = 0xb
   110  	LC_LOAD_DYLIB           = 0xc
   111  	LC_ID_DYLIB             = 0xd
   112  	LC_LOAD_DYLINKER        = 0xe
   113  	LC_PREBOUND_DYLIB       = 0x10
   114  	LC_LOAD_WEAK_DYLIB      = 0x18
   115  	LC_SEGMENT_64           = 0x19
   116  	LC_UUID                 = 0x1b
   117  	LC_RPATH                = 0x8000001c
   118  	LC_CODE_SIGNATURE       = 0x1d
   119  	LC_SEGMENT_SPLIT_INFO   = 0x1e
   120  	LC_REEXPORT_DYLIB       = 0x8000001f
   121  	LC_ENCRYPTION_INFO      = 0x21
   122  	LC_DYLD_INFO            = 0x22
   123  	LC_DYLD_INFO_ONLY       = 0x80000022
   124  	LC_VERSION_MIN_MACOSX   = 0x24
   125  	LC_VERSION_MIN_IPHONEOS = 0x25
   126  	LC_FUNCTION_STARTS      = 0x26
   127  	LC_MAIN                 = 0x80000028
   128  	LC_DATA_IN_CODE         = 0x29
   129  	LC_SOURCE_VERSION       = 0x2A
   130  	LC_DYLIB_CODE_SIGN_DRS  = 0x2B
   131  	LC_ENCRYPTION_INFO_64   = 0x2C
   132  )
   133  
   134  const (
   135  	S_REGULAR                  = 0x0
   136  	S_ZEROFILL                 = 0x1
   137  	S_NON_LAZY_SYMBOL_POINTERS = 0x6
   138  	S_SYMBOL_STUBS             = 0x8
   139  	S_MOD_INIT_FUNC_POINTERS   = 0x9
   140  	S_ATTR_PURE_INSTRUCTIONS   = 0x80000000
   141  	S_ATTR_DEBUG               = 0x02000000
   142  	S_ATTR_SOME_INSTRUCTIONS   = 0x00000400
   143  )
   144  
   145  // Copyright 2009 The Go Authors. All rights reserved.
   146  // Use of this source code is governed by a BSD-style
   147  // license that can be found in the LICENSE file.
   148  
   149  // Mach-O file writing
   150  // http://developer.apple.com/mac/library/DOCUMENTATION/DeveloperTools/Conceptual/MachORuntime/Reference/reference.html
   151  
   152  var machohdr MachoHdr
   153  
   154  var load []MachoLoad
   155  
   156  var seg [16]MachoSeg
   157  
   158  var nseg int
   159  
   160  var ndebug int
   161  
   162  var nsect int
   163  
   164  const (
   165  	SymKindLocal = 0 + iota
   166  	SymKindExtdef
   167  	SymKindUndef
   168  	NumSymKind
   169  )
   170  
   171  var nkind [NumSymKind]int
   172  
   173  var sortsym []*sym.Symbol
   174  
   175  var nsortsym int
   176  
   177  // Amount of space left for adding load commands
   178  // that refer to dynamic libraries. Because these have
   179  // to go in the Mach-O header, we can't just pick a
   180  // "big enough" header size. The initial header is
   181  // one page, the non-dynamic library stuff takes
   182  // up about 1300 bytes; we overestimate that as 2k.
   183  var loadBudget = INITIAL_MACHO_HEADR - 2*1024
   184  
   185  func getMachoHdr() *MachoHdr {
   186  	return &machohdr
   187  }
   188  
   189  func newMachoLoad(arch *sys.Arch, type_ uint32, ndata uint32) *MachoLoad {
   190  	if arch.PtrSize == 8 && (ndata&1 != 0) {
   191  		ndata++
   192  	}
   193  
   194  	load = append(load, MachoLoad{})
   195  	l := &load[len(load)-1]
   196  	l.type_ = type_
   197  	l.data = make([]uint32, ndata)
   198  	return l
   199  }
   200  
   201  func newMachoSeg(name string, msect int) *MachoSeg {
   202  	if nseg >= len(seg) {
   203  		Exitf("too many segs")
   204  	}
   205  
   206  	s := &seg[nseg]
   207  	nseg++
   208  	s.name = name
   209  	s.msect = uint32(msect)
   210  	s.sect = make([]MachoSect, msect)
   211  	return s
   212  }
   213  
   214  func newMachoSect(seg *MachoSeg, name string, segname string) *MachoSect {
   215  	if seg.nsect >= seg.msect {
   216  		Exitf("too many sects in segment %s", seg.name)
   217  	}
   218  
   219  	s := &seg.sect[seg.nsect]
   220  	seg.nsect++
   221  	s.name = name
   222  	s.segname = segname
   223  	nsect++
   224  	return s
   225  }
   226  
   227  // Generic linking code.
   228  
   229  var dylib []string
   230  
   231  var linkoff int64
   232  
   233  func machowrite(arch *sys.Arch, out *OutBuf, linkmode LinkMode) int {
   234  	o1 := out.Offset()
   235  
   236  	loadsize := 4 * 4 * ndebug
   237  	for i := 0; i < len(load); i++ {
   238  		loadsize += 4 * (len(load[i].data) + 2)
   239  	}
   240  	if arch.PtrSize == 8 {
   241  		loadsize += 18 * 4 * nseg
   242  		loadsize += 20 * 4 * nsect
   243  	} else {
   244  		loadsize += 14 * 4 * nseg
   245  		loadsize += 17 * 4 * nsect
   246  	}
   247  
   248  	if arch.PtrSize == 8 {
   249  		out.Write32(MH_MAGIC_64)
   250  	} else {
   251  		out.Write32(MH_MAGIC)
   252  	}
   253  	out.Write32(machohdr.cpu)
   254  	out.Write32(machohdr.subcpu)
   255  	if linkmode == LinkExternal {
   256  		out.Write32(MH_OBJECT) /* file type - mach object */
   257  	} else {
   258  		out.Write32(MH_EXECUTE) /* file type - mach executable */
   259  	}
   260  	out.Write32(uint32(len(load)) + uint32(nseg) + uint32(ndebug))
   261  	out.Write32(uint32(loadsize))
   262  	if nkind[SymKindUndef] == 0 {
   263  		out.Write32(MH_NOUNDEFS) /* flags - no undefines */
   264  	} else {
   265  		out.Write32(0) /* flags */
   266  	}
   267  	if arch.PtrSize == 8 {
   268  		out.Write32(0) /* reserved */
   269  	}
   270  
   271  	for i := 0; i < nseg; i++ {
   272  		s := &seg[i]
   273  		if arch.PtrSize == 8 {
   274  			out.Write32(LC_SEGMENT_64)
   275  			out.Write32(72 + 80*s.nsect)
   276  			out.WriteStringN(s.name, 16)
   277  			out.Write64(s.vaddr)
   278  			out.Write64(s.vsize)
   279  			out.Write64(s.fileoffset)
   280  			out.Write64(s.filesize)
   281  			out.Write32(s.prot1)
   282  			out.Write32(s.prot2)
   283  			out.Write32(s.nsect)
   284  			out.Write32(s.flag)
   285  		} else {
   286  			out.Write32(LC_SEGMENT)
   287  			out.Write32(56 + 68*s.nsect)
   288  			out.WriteStringN(s.name, 16)
   289  			out.Write32(uint32(s.vaddr))
   290  			out.Write32(uint32(s.vsize))
   291  			out.Write32(uint32(s.fileoffset))
   292  			out.Write32(uint32(s.filesize))
   293  			out.Write32(s.prot1)
   294  			out.Write32(s.prot2)
   295  			out.Write32(s.nsect)
   296  			out.Write32(s.flag)
   297  		}
   298  
   299  		for j := uint32(0); j < s.nsect; j++ {
   300  			t := &s.sect[j]
   301  			if arch.PtrSize == 8 {
   302  				out.WriteStringN(t.name, 16)
   303  				out.WriteStringN(t.segname, 16)
   304  				out.Write64(t.addr)
   305  				out.Write64(t.size)
   306  				out.Write32(t.off)
   307  				out.Write32(t.align)
   308  				out.Write32(t.reloc)
   309  				out.Write32(t.nreloc)
   310  				out.Write32(t.flag)
   311  				out.Write32(t.res1) /* reserved */
   312  				out.Write32(t.res2) /* reserved */
   313  				out.Write32(0)      /* reserved */
   314  			} else {
   315  				out.WriteStringN(t.name, 16)
   316  				out.WriteStringN(t.segname, 16)
   317  				out.Write32(uint32(t.addr))
   318  				out.Write32(uint32(t.size))
   319  				out.Write32(t.off)
   320  				out.Write32(t.align)
   321  				out.Write32(t.reloc)
   322  				out.Write32(t.nreloc)
   323  				out.Write32(t.flag)
   324  				out.Write32(t.res1) /* reserved */
   325  				out.Write32(t.res2) /* reserved */
   326  			}
   327  		}
   328  	}
   329  
   330  	for i := 0; i < len(load); i++ {
   331  		l := &load[i]
   332  		out.Write32(l.type_)
   333  		out.Write32(4 * (uint32(len(l.data)) + 2))
   334  		for j := 0; j < len(l.data); j++ {
   335  			out.Write32(l.data[j])
   336  		}
   337  	}
   338  
   339  	return int(out.Offset() - o1)
   340  }
   341  
   342  func (ctxt *Link) domacho() {
   343  	if *FlagD {
   344  		return
   345  	}
   346  
   347  	// empirically, string table must begin with " \x00".
   348  	s := ctxt.Syms.Lookup(".machosymstr", 0)
   349  
   350  	s.Type = sym.SMACHOSYMSTR
   351  	s.Attr |= sym.AttrReachable
   352  	s.AddUint8(' ')
   353  	s.AddUint8('\x00')
   354  
   355  	s = ctxt.Syms.Lookup(".machosymtab", 0)
   356  	s.Type = sym.SMACHOSYMTAB
   357  	s.Attr |= sym.AttrReachable
   358  
   359  	if ctxt.LinkMode != LinkExternal {
   360  		s := ctxt.Syms.Lookup(".plt", 0) // will be __symbol_stub
   361  		s.Type = sym.SMACHOPLT
   362  		s.Attr |= sym.AttrReachable
   363  
   364  		s = ctxt.Syms.Lookup(".got", 0) // will be __nl_symbol_ptr
   365  		s.Type = sym.SMACHOGOT
   366  		s.Attr |= sym.AttrReachable
   367  		s.Align = 4
   368  
   369  		s = ctxt.Syms.Lookup(".linkedit.plt", 0) // indirect table for .plt
   370  		s.Type = sym.SMACHOINDIRECTPLT
   371  		s.Attr |= sym.AttrReachable
   372  
   373  		s = ctxt.Syms.Lookup(".linkedit.got", 0) // indirect table for .got
   374  		s.Type = sym.SMACHOINDIRECTGOT
   375  		s.Attr |= sym.AttrReachable
   376  	}
   377  }
   378  
   379  func machoadddynlib(lib string, linkmode LinkMode) {
   380  	if seenlib[lib] || linkmode == LinkExternal {
   381  		return
   382  	}
   383  	seenlib[lib] = true
   384  
   385  	// Will need to store the library name rounded up
   386  	// and 24 bytes of header metadata. If not enough
   387  	// space, grab another page of initial space at the
   388  	// beginning of the output file.
   389  	loadBudget -= (len(lib)+7)/8*8 + 24
   390  
   391  	if loadBudget < 0 {
   392  		HEADR += 4096
   393  		*FlagTextAddr += 4096
   394  		loadBudget += 4096
   395  	}
   396  
   397  	dylib = append(dylib, lib)
   398  }
   399  
   400  func machoshbits(ctxt *Link, mseg *MachoSeg, sect *sym.Section, segname string) {
   401  	buf := "__" + strings.Replace(sect.Name[1:], ".", "_", -1)
   402  
   403  	var msect *MachoSect
   404  	if sect.Rwx&1 == 0 && segname != "__DWARF" && (ctxt.Arch.Family == sys.ARM64 ||
   405  		(ctxt.Arch.Family == sys.AMD64 && ctxt.BuildMode != BuildModeExe) ||
   406  		(ctxt.Arch.Family == sys.ARM && ctxt.BuildMode != BuildModeExe)) {
   407  		// Darwin external linker on arm64 and on amd64 and arm in c-shared/c-archive buildmode
   408  		// complains about absolute relocs in __TEXT, so if the section is not
   409  		// executable, put it in __DATA segment.
   410  		msect = newMachoSect(mseg, buf, "__DATA")
   411  	} else {
   412  		msect = newMachoSect(mseg, buf, segname)
   413  	}
   414  
   415  	if sect.Rellen > 0 {
   416  		msect.reloc = uint32(sect.Reloff)
   417  		msect.nreloc = uint32(sect.Rellen / 8)
   418  	}
   419  
   420  	for 1<<msect.align < sect.Align {
   421  		msect.align++
   422  	}
   423  	msect.addr = sect.Vaddr
   424  	msect.size = sect.Length
   425  
   426  	if sect.Vaddr < sect.Seg.Vaddr+sect.Seg.Filelen {
   427  		// data in file
   428  		if sect.Length > sect.Seg.Vaddr+sect.Seg.Filelen-sect.Vaddr {
   429  			Errorf(nil, "macho cannot represent section %s crossing data and bss", sect.Name)
   430  		}
   431  		msect.off = uint32(sect.Seg.Fileoff + sect.Vaddr - sect.Seg.Vaddr)
   432  	} else {
   433  		msect.off = 0
   434  		msect.flag |= S_ZEROFILL
   435  	}
   436  
   437  	if sect.Rwx&1 != 0 {
   438  		msect.flag |= S_ATTR_SOME_INSTRUCTIONS
   439  	}
   440  
   441  	if sect.Name == ".plt" {
   442  		msect.name = "__symbol_stub1"
   443  		msect.flag = S_ATTR_PURE_INSTRUCTIONS | S_ATTR_SOME_INSTRUCTIONS | S_SYMBOL_STUBS
   444  		msect.res1 = 0 //nkind[SymKindLocal];
   445  		msect.res2 = 6
   446  	}
   447  
   448  	if sect.Name == ".got" {
   449  		msect.name = "__nl_symbol_ptr"
   450  		msect.flag = S_NON_LAZY_SYMBOL_POINTERS
   451  		msect.res1 = uint32(ctxt.Syms.Lookup(".linkedit.plt", 0).Size / 4) /* offset into indirect symbol table */
   452  	}
   453  
   454  	if sect.Name == ".init_array" {
   455  		msect.name = "__mod_init_func"
   456  		msect.flag = S_MOD_INIT_FUNC_POINTERS
   457  	}
   458  
   459  	if segname == "__DWARF" {
   460  		msect.flag |= S_ATTR_DEBUG
   461  	}
   462  }
   463  
   464  func Asmbmacho(ctxt *Link) {
   465  	/* apple MACH */
   466  	va := *FlagTextAddr - int64(HEADR)
   467  
   468  	mh := getMachoHdr()
   469  	switch ctxt.Arch.Family {
   470  	default:
   471  		Exitf("unknown macho architecture: %v", ctxt.Arch.Family)
   472  
   473  	case sys.ARM:
   474  		mh.cpu = MACHO_CPU_ARM
   475  		mh.subcpu = MACHO_SUBCPU_ARMV7
   476  
   477  	case sys.AMD64:
   478  		mh.cpu = MACHO_CPU_AMD64
   479  		mh.subcpu = MACHO_SUBCPU_X86
   480  
   481  	case sys.ARM64:
   482  		mh.cpu = MACHO_CPU_ARM64
   483  		mh.subcpu = MACHO_SUBCPU_ARM64_ALL
   484  
   485  	case sys.I386:
   486  		mh.cpu = MACHO_CPU_386
   487  		mh.subcpu = MACHO_SUBCPU_X86
   488  	}
   489  
   490  	var ms *MachoSeg
   491  	if ctxt.LinkMode == LinkExternal {
   492  		/* segment for entire file */
   493  		ms = newMachoSeg("", 40)
   494  
   495  		ms.fileoffset = Segtext.Fileoff
   496  		if ctxt.Arch.Family == sys.ARM || ctxt.BuildMode == BuildModeCArchive {
   497  			ms.filesize = Segdata.Fileoff + Segdata.Filelen - Segtext.Fileoff
   498  		} else {
   499  			ms.filesize = Segdwarf.Fileoff + Segdwarf.Filelen - Segtext.Fileoff
   500  			ms.vsize = Segdwarf.Vaddr + Segdwarf.Length - Segtext.Vaddr
   501  		}
   502  	}
   503  
   504  	/* segment for zero page */
   505  	if ctxt.LinkMode != LinkExternal {
   506  		ms = newMachoSeg("__PAGEZERO", 0)
   507  		ms.vsize = uint64(va)
   508  	}
   509  
   510  	/* text */
   511  	v := Rnd(int64(uint64(HEADR)+Segtext.Length), int64(*FlagRound))
   512  
   513  	if ctxt.LinkMode != LinkExternal {
   514  		ms = newMachoSeg("__TEXT", 20)
   515  		ms.vaddr = uint64(va)
   516  		ms.vsize = uint64(v)
   517  		ms.fileoffset = 0
   518  		ms.filesize = uint64(v)
   519  		ms.prot1 = 7
   520  		ms.prot2 = 5
   521  	}
   522  
   523  	for _, sect := range Segtext.Sections {
   524  		machoshbits(ctxt, ms, sect, "__TEXT")
   525  	}
   526  
   527  	/* data */
   528  	if ctxt.LinkMode != LinkExternal {
   529  		w := int64(Segdata.Length)
   530  		ms = newMachoSeg("__DATA", 20)
   531  		ms.vaddr = uint64(va) + uint64(v)
   532  		ms.vsize = uint64(w)
   533  		ms.fileoffset = uint64(v)
   534  		ms.filesize = Segdata.Filelen
   535  		ms.prot1 = 3
   536  		ms.prot2 = 3
   537  	}
   538  
   539  	for _, sect := range Segdata.Sections {
   540  		machoshbits(ctxt, ms, sect, "__DATA")
   541  	}
   542  
   543  	/* dwarf */
   544  	if !*FlagW {
   545  		if ctxt.LinkMode != LinkExternal {
   546  			ms = newMachoSeg("__DWARF", 20)
   547  			ms.vaddr = Segdwarf.Vaddr
   548  			ms.vsize = 0
   549  			ms.fileoffset = Segdwarf.Fileoff
   550  			ms.filesize = Segdwarf.Filelen
   551  		}
   552  		for _, sect := range Segdwarf.Sections {
   553  			machoshbits(ctxt, ms, sect, "__DWARF")
   554  		}
   555  	}
   556  
   557  	if ctxt.LinkMode != LinkExternal {
   558  		switch ctxt.Arch.Family {
   559  		default:
   560  			Exitf("unknown macho architecture: %v", ctxt.Arch.Family)
   561  
   562  		case sys.ARM:
   563  			ml := newMachoLoad(ctxt.Arch, LC_UNIXTHREAD, 17+2)
   564  			ml.data[0] = 1                           /* thread type */
   565  			ml.data[1] = 17                          /* word count */
   566  			ml.data[2+15] = uint32(Entryvalue(ctxt)) /* start pc */
   567  
   568  		case sys.AMD64:
   569  			ml := newMachoLoad(ctxt.Arch, LC_UNIXTHREAD, 42+2)
   570  			ml.data[0] = 4                           /* thread type */
   571  			ml.data[1] = 42                          /* word count */
   572  			ml.data[2+32] = uint32(Entryvalue(ctxt)) /* start pc */
   573  			ml.data[2+32+1] = uint32(Entryvalue(ctxt) >> 32)
   574  
   575  		case sys.ARM64:
   576  			ml := newMachoLoad(ctxt.Arch, LC_UNIXTHREAD, 68+2)
   577  			ml.data[0] = 6                           /* thread type */
   578  			ml.data[1] = 68                          /* word count */
   579  			ml.data[2+64] = uint32(Entryvalue(ctxt)) /* start pc */
   580  			ml.data[2+64+1] = uint32(Entryvalue(ctxt) >> 32)
   581  
   582  		case sys.I386:
   583  			ml := newMachoLoad(ctxt.Arch, LC_UNIXTHREAD, 16+2)
   584  			ml.data[0] = 1                           /* thread type */
   585  			ml.data[1] = 16                          /* word count */
   586  			ml.data[2+10] = uint32(Entryvalue(ctxt)) /* start pc */
   587  		}
   588  	}
   589  
   590  	if !*FlagD {
   591  		// must match domacholink below
   592  		s1 := ctxt.Syms.Lookup(".machosymtab", 0)
   593  		s2 := ctxt.Syms.Lookup(".linkedit.plt", 0)
   594  		s3 := ctxt.Syms.Lookup(".linkedit.got", 0)
   595  		s4 := ctxt.Syms.Lookup(".machosymstr", 0)
   596  
   597  		if ctxt.LinkMode != LinkExternal {
   598  			ms := newMachoSeg("__LINKEDIT", 0)
   599  			ms.vaddr = uint64(va) + uint64(v) + uint64(Rnd(int64(Segdata.Length), int64(*FlagRound)))
   600  			ms.vsize = uint64(s1.Size) + uint64(s2.Size) + uint64(s3.Size) + uint64(s4.Size)
   601  			ms.fileoffset = uint64(linkoff)
   602  			ms.filesize = ms.vsize
   603  			ms.prot1 = 7
   604  			ms.prot2 = 3
   605  		}
   606  
   607  		ml := newMachoLoad(ctxt.Arch, LC_SYMTAB, 4)
   608  		ml.data[0] = uint32(linkoff)                               /* symoff */
   609  		ml.data[1] = uint32(nsortsym)                              /* nsyms */
   610  		ml.data[2] = uint32(linkoff + s1.Size + s2.Size + s3.Size) /* stroff */
   611  		ml.data[3] = uint32(s4.Size)                               /* strsize */
   612  
   613  		machodysymtab(ctxt)
   614  
   615  		if ctxt.LinkMode != LinkExternal {
   616  			ml := newMachoLoad(ctxt.Arch, LC_LOAD_DYLINKER, 6)
   617  			ml.data[0] = 12 /* offset to string */
   618  			stringtouint32(ml.data[1:], "/usr/lib/dyld")
   619  
   620  			for i := 0; i < len(dylib); i++ {
   621  				ml = newMachoLoad(ctxt.Arch, LC_LOAD_DYLIB, 4+(uint32(len(dylib[i]))+1+7)/8*2)
   622  				ml.data[0] = 24 /* offset of string from beginning of load */
   623  				ml.data[1] = 0  /* time stamp */
   624  				ml.data[2] = 0  /* version */
   625  				ml.data[3] = 0  /* compatibility version */
   626  				stringtouint32(ml.data[4:], dylib[i])
   627  			}
   628  		}
   629  	}
   630  
   631  	if ctxt.LinkMode == LinkInternal {
   632  		// For lldb, must say LC_VERSION_MIN_MACOSX or else
   633  		// it won't know that this Mach-O binary is from OS X
   634  		// (could be iOS or WatchOS instead).
   635  		// Go on iOS uses linkmode=external, and linkmode=external
   636  		// adds this itself. So we only need this code for linkmode=internal
   637  		// and we can assume OS X.
   638  		//
   639  		// See golang.org/issues/12941.
   640  		ml := newMachoLoad(ctxt.Arch, LC_VERSION_MIN_MACOSX, 2)
   641  		ml.data[0] = 10<<16 | 7<<8 | 0<<0 // OS X version 10.7.0
   642  		ml.data[1] = 10<<16 | 7<<8 | 0<<0 // SDK 10.7.0
   643  	}
   644  
   645  	a := machowrite(ctxt.Arch, ctxt.Out, ctxt.LinkMode)
   646  	if int32(a) > HEADR {
   647  		Exitf("HEADR too small: %d > %d", a, HEADR)
   648  	}
   649  }
   650  
   651  func symkind(s *sym.Symbol) int {
   652  	if s.Type == sym.SDYNIMPORT {
   653  		return SymKindUndef
   654  	}
   655  	if s.Attr.CgoExport() {
   656  		return SymKindExtdef
   657  	}
   658  	return SymKindLocal
   659  }
   660  
   661  func addsym(ctxt *Link, s *sym.Symbol, name string, type_ SymbolType, addr int64, gotype *sym.Symbol) {
   662  	if s == nil {
   663  		return
   664  	}
   665  
   666  	switch type_ {
   667  	default:
   668  		return
   669  
   670  	case DataSym, BSSSym, TextSym:
   671  		break
   672  	}
   673  
   674  	if sortsym != nil {
   675  		sortsym[nsortsym] = s
   676  		nkind[symkind(s)]++
   677  	}
   678  
   679  	nsortsym++
   680  }
   681  
   682  type machoscmp []*sym.Symbol
   683  
   684  func (x machoscmp) Len() int {
   685  	return len(x)
   686  }
   687  
   688  func (x machoscmp) Swap(i, j int) {
   689  	x[i], x[j] = x[j], x[i]
   690  }
   691  
   692  func (x machoscmp) Less(i, j int) bool {
   693  	s1 := x[i]
   694  	s2 := x[j]
   695  
   696  	k1 := symkind(s1)
   697  	k2 := symkind(s2)
   698  	if k1 != k2 {
   699  		return k1 < k2
   700  	}
   701  
   702  	return s1.Extname < s2.Extname
   703  }
   704  
   705  func machogenasmsym(ctxt *Link) {
   706  	genasmsym(ctxt, addsym)
   707  	for _, s := range ctxt.Syms.Allsym {
   708  		if s.Type == sym.SDYNIMPORT || s.Type == sym.SHOSTOBJ {
   709  			if s.Attr.Reachable() {
   710  				addsym(ctxt, s, "", DataSym, 0, nil)
   711  			}
   712  		}
   713  	}
   714  }
   715  
   716  func machosymorder(ctxt *Link) {
   717  	// On Mac OS X Mountain Lion, we must sort exported symbols
   718  	// So we sort them here and pre-allocate dynid for them
   719  	// See https://golang.org/issue/4029
   720  	for i := 0; i < len(dynexp); i++ {
   721  		dynexp[i].Attr |= sym.AttrReachable
   722  	}
   723  	machogenasmsym(ctxt)
   724  	sortsym = make([]*sym.Symbol, nsortsym)
   725  	nsortsym = 0
   726  	machogenasmsym(ctxt)
   727  	sort.Sort(machoscmp(sortsym[:nsortsym]))
   728  	for i := 0; i < nsortsym; i++ {
   729  		sortsym[i].Dynid = int32(i)
   730  	}
   731  }
   732  
   733  // machoShouldExport reports whether a symbol needs to be exported.
   734  //
   735  // When dynamically linking, all non-local variables and plugin-exported
   736  // symbols need to be exported.
   737  func machoShouldExport(ctxt *Link, s *sym.Symbol) bool {
   738  	if !ctxt.DynlinkingGo() || s.Attr.Local() {
   739  		return false
   740  	}
   741  	if ctxt.BuildMode == BuildModePlugin && strings.HasPrefix(s.Extname, objabi.PathToPrefix(*flagPluginPath)) {
   742  		return true
   743  	}
   744  	if strings.HasPrefix(s.Name, "go.itab.") {
   745  		return true
   746  	}
   747  	if strings.HasPrefix(s.Name, "type.") && !strings.HasPrefix(s.Name, "type..") {
   748  		// reduce runtime typemap pressure, but do not
   749  		// export alg functions (type..*), as these
   750  		// appear in pclntable.
   751  		return true
   752  	}
   753  	if strings.HasPrefix(s.Name, "go.link.pkghash") {
   754  		return true
   755  	}
   756  	return s.Type >= sym.SELFSECT // only writable sections
   757  }
   758  
   759  func machosymtab(ctxt *Link) {
   760  	symtab := ctxt.Syms.Lookup(".machosymtab", 0)
   761  	symstr := ctxt.Syms.Lookup(".machosymstr", 0)
   762  
   763  	for i := 0; i < nsortsym; i++ {
   764  		s := sortsym[i]
   765  		symtab.AddUint32(ctxt.Arch, uint32(symstr.Size))
   766  
   767  		export := machoShouldExport(ctxt, s)
   768  
   769  		// In normal buildmodes, only add _ to C symbols, as
   770  		// Go symbols have dot in the name.
   771  		//
   772  		// Do not export C symbols in plugins, as runtime C
   773  		// symbols like crosscall2 are in pclntab and end up
   774  		// pointing at the host binary, breaking unwinding.
   775  		// See Issue #18190.
   776  		cexport := !strings.Contains(s.Extname, ".") && (ctxt.BuildMode != BuildModePlugin || onlycsymbol(s))
   777  		if cexport || export {
   778  			symstr.AddUint8('_')
   779  		}
   780  
   781  		// replace "·" as ".", because DTrace cannot handle it.
   782  		Addstring(symstr, strings.Replace(s.Extname, "·", ".", -1))
   783  
   784  		if s.Type == sym.SDYNIMPORT || s.Type == sym.SHOSTOBJ {
   785  			symtab.AddUint8(0x01)                             // type N_EXT, external symbol
   786  			symtab.AddUint8(0)                                // no section
   787  			symtab.AddUint16(ctxt.Arch, 0)                    // desc
   788  			symtab.AddUintXX(ctxt.Arch, 0, ctxt.Arch.PtrSize) // no value
   789  		} else {
   790  			if s.Attr.CgoExport() || export {
   791  				symtab.AddUint8(0x0f)
   792  			} else {
   793  				symtab.AddUint8(0x0e)
   794  			}
   795  			o := s
   796  			for o.Outer != nil {
   797  				o = o.Outer
   798  			}
   799  			if o.Sect == nil {
   800  				Errorf(s, "missing section for symbol")
   801  				symtab.AddUint8(0)
   802  			} else {
   803  				symtab.AddUint8(uint8(o.Sect.Extnum))
   804  			}
   805  			symtab.AddUint16(ctxt.Arch, 0) // desc
   806  			symtab.AddUintXX(ctxt.Arch, uint64(Symaddr(s)), ctxt.Arch.PtrSize)
   807  		}
   808  	}
   809  }
   810  
   811  func machodysymtab(ctxt *Link) {
   812  	ml := newMachoLoad(ctxt.Arch, LC_DYSYMTAB, 18)
   813  
   814  	n := 0
   815  	ml.data[0] = uint32(n)                   /* ilocalsym */
   816  	ml.data[1] = uint32(nkind[SymKindLocal]) /* nlocalsym */
   817  	n += nkind[SymKindLocal]
   818  
   819  	ml.data[2] = uint32(n)                    /* iextdefsym */
   820  	ml.data[3] = uint32(nkind[SymKindExtdef]) /* nextdefsym */
   821  	n += nkind[SymKindExtdef]
   822  
   823  	ml.data[4] = uint32(n)                   /* iundefsym */
   824  	ml.data[5] = uint32(nkind[SymKindUndef]) /* nundefsym */
   825  
   826  	ml.data[6] = 0  /* tocoffset */
   827  	ml.data[7] = 0  /* ntoc */
   828  	ml.data[8] = 0  /* modtaboff */
   829  	ml.data[9] = 0  /* nmodtab */
   830  	ml.data[10] = 0 /* extrefsymoff */
   831  	ml.data[11] = 0 /* nextrefsyms */
   832  
   833  	// must match domacholink below
   834  	s1 := ctxt.Syms.Lookup(".machosymtab", 0)
   835  
   836  	s2 := ctxt.Syms.Lookup(".linkedit.plt", 0)
   837  	s3 := ctxt.Syms.Lookup(".linkedit.got", 0)
   838  	ml.data[12] = uint32(linkoff + s1.Size)       /* indirectsymoff */
   839  	ml.data[13] = uint32((s2.Size + s3.Size) / 4) /* nindirectsyms */
   840  
   841  	ml.data[14] = 0 /* extreloff */
   842  	ml.data[15] = 0 /* nextrel */
   843  	ml.data[16] = 0 /* locreloff */
   844  	ml.data[17] = 0 /* nlocrel */
   845  }
   846  
   847  func Domacholink(ctxt *Link) int64 {
   848  	machosymtab(ctxt)
   849  
   850  	// write data that will be linkedit section
   851  	s1 := ctxt.Syms.Lookup(".machosymtab", 0)
   852  
   853  	s2 := ctxt.Syms.Lookup(".linkedit.plt", 0)
   854  	s3 := ctxt.Syms.Lookup(".linkedit.got", 0)
   855  	s4 := ctxt.Syms.Lookup(".machosymstr", 0)
   856  
   857  	// Force the linkedit section to end on a 16-byte
   858  	// boundary. This allows pure (non-cgo) Go binaries
   859  	// to be code signed correctly.
   860  	//
   861  	// Apple's codesign_allocate (a helper utility for
   862  	// the codesign utility) can do this fine itself if
   863  	// it is run on a dynamic Mach-O binary. However,
   864  	// when it is run on a pure (non-cgo) Go binary, where
   865  	// the linkedit section is mostly empty, it fails to
   866  	// account for the extra padding that it itself adds
   867  	// when adding the LC_CODE_SIGNATURE load command
   868  	// (which must be aligned on a 16-byte boundary).
   869  	//
   870  	// By forcing the linkedit section to end on a 16-byte
   871  	// boundary, codesign_allocate will not need to apply
   872  	// any alignment padding itself, working around the
   873  	// issue.
   874  	for s4.Size%16 != 0 {
   875  		s4.AddUint8(0)
   876  	}
   877  
   878  	size := int(s1.Size + s2.Size + s3.Size + s4.Size)
   879  
   880  	if size > 0 {
   881  		linkoff = Rnd(int64(uint64(HEADR)+Segtext.Length), int64(*FlagRound)) + Rnd(int64(Segdata.Filelen), int64(*FlagRound)) + Rnd(int64(Segdwarf.Filelen), int64(*FlagRound))
   882  		ctxt.Out.SeekSet(linkoff)
   883  
   884  		ctxt.Out.Write(s1.P[:s1.Size])
   885  		ctxt.Out.Write(s2.P[:s2.Size])
   886  		ctxt.Out.Write(s3.P[:s3.Size])
   887  		ctxt.Out.Write(s4.P[:s4.Size])
   888  	}
   889  
   890  	return Rnd(int64(size), int64(*FlagRound))
   891  }
   892  
   893  func machorelocsect(ctxt *Link, sect *sym.Section, syms []*sym.Symbol) {
   894  	// If main section has no bits, nothing to relocate.
   895  	if sect.Vaddr >= sect.Seg.Vaddr+sect.Seg.Filelen {
   896  		return
   897  	}
   898  
   899  	sect.Reloff = uint64(ctxt.Out.Offset())
   900  	for i, s := range syms {
   901  		if !s.Attr.Reachable() {
   902  			continue
   903  		}
   904  		if uint64(s.Value) >= sect.Vaddr {
   905  			syms = syms[i:]
   906  			break
   907  		}
   908  	}
   909  
   910  	eaddr := int32(sect.Vaddr + sect.Length)
   911  	for _, s := range syms {
   912  		if !s.Attr.Reachable() {
   913  			continue
   914  		}
   915  		if s.Value >= int64(eaddr) {
   916  			break
   917  		}
   918  		for ri := 0; ri < len(s.R); ri++ {
   919  			r := &s.R[ri]
   920  			if r.Done {
   921  				continue
   922  			}
   923  			if r.Xsym == nil {
   924  				Errorf(s, "missing xsym in relocation")
   925  				continue
   926  			}
   927  			if !r.Xsym.Attr.Reachable() {
   928  				Errorf(s, "unreachable reloc %d (%s) target %v", r.Type, sym.RelocName(ctxt.Arch, r.Type), r.Xsym.Name)
   929  			}
   930  			if !Thearch.Machoreloc1(ctxt.Arch, ctxt.Out, s, r, int64(uint64(s.Value+int64(r.Off))-sect.Vaddr)) {
   931  				Errorf(s, "unsupported obj reloc %d (%s)/%d to %s", r.Type, sym.RelocName(ctxt.Arch, r.Type), r.Siz, r.Sym.Name)
   932  			}
   933  		}
   934  	}
   935  
   936  	sect.Rellen = uint64(ctxt.Out.Offset()) - sect.Reloff
   937  }
   938  
   939  func Machoemitreloc(ctxt *Link) {
   940  	for ctxt.Out.Offset()&7 != 0 {
   941  		ctxt.Out.Write8(0)
   942  	}
   943  
   944  	machorelocsect(ctxt, Segtext.Sections[0], ctxt.Textp)
   945  	for _, sect := range Segtext.Sections[1:] {
   946  		machorelocsect(ctxt, sect, datap)
   947  	}
   948  	for _, sect := range Segdata.Sections {
   949  		machorelocsect(ctxt, sect, datap)
   950  	}
   951  	for _, sect := range Segdwarf.Sections {
   952  		machorelocsect(ctxt, sect, dwarfp)
   953  	}
   954  }