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