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