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