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