github.com/aloncn/graphics-go@v0.0.1/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' || // arm64
   360  		(Thearch.Thechar == '6' && (Buildmode == BuildmodeCShared || Buildmode == BuildmodeCArchive))) { // amd64
   361  		// Darwin external linker on arm64 and on amd64 in c-shared/c-archive buildmode
   362  		// complains about absolute relocs in __TEXT, so if the section is not
   363  		// executable, put it in __DATA segment.
   364  		msect = newMachoSect(mseg, buf, "__DATA")
   365  	} else {
   366  		msect = newMachoSect(mseg, buf, segname)
   367  	}
   368  
   369  	if sect.Rellen > 0 {
   370  		msect.reloc = uint32(sect.Reloff)
   371  		msect.nreloc = uint32(sect.Rellen / 8)
   372  	}
   373  
   374  	for 1<<msect.align < sect.Align {
   375  		msect.align++
   376  	}
   377  	msect.addr = sect.Vaddr
   378  	msect.size = sect.Length
   379  
   380  	if sect.Vaddr < sect.Seg.Vaddr+sect.Seg.Filelen {
   381  		// data in file
   382  		if sect.Length > sect.Seg.Vaddr+sect.Seg.Filelen-sect.Vaddr {
   383  			Diag("macho cannot represent section %s crossing data and bss", sect.Name)
   384  		}
   385  		msect.off = uint32(sect.Seg.Fileoff + sect.Vaddr - sect.Seg.Vaddr)
   386  	} else {
   387  		// zero fill
   388  		msect.off = 0
   389  
   390  		msect.flag |= 1
   391  	}
   392  
   393  	if sect.Rwx&1 != 0 {
   394  		msect.flag |= 0x400 /* has instructions */
   395  	}
   396  
   397  	if sect.Name == ".plt" {
   398  		msect.name = "__symbol_stub1"
   399  		msect.flag = 0x80000408 /* only instructions, code, symbol stubs */
   400  		msect.res1 = 0          //nkind[SymKindLocal];
   401  		msect.res2 = 6
   402  	}
   403  
   404  	if sect.Name == ".got" {
   405  		msect.name = "__nl_symbol_ptr"
   406  		msect.flag = 6                                                     /* section with nonlazy symbol pointers */
   407  		msect.res1 = uint32(Linklookup(Ctxt, ".linkedit.plt", 0).Size / 4) /* offset into indirect symbol table */
   408  	}
   409  
   410  	if sect.Name == ".init_array" {
   411  		msect.name = "__mod_init_func"
   412  		msect.flag = 9 // S_MOD_INIT_FUNC_POINTERS
   413  	}
   414  }
   415  
   416  func Asmbmacho() {
   417  	/* apple MACH */
   418  	va := INITTEXT - int64(HEADR)
   419  
   420  	mh := getMachoHdr()
   421  	switch Thearch.Thechar {
   422  	default:
   423  		Exitf("unknown macho architecture: %v", Thearch.Thechar)
   424  
   425  	case '5':
   426  		mh.cpu = MACHO_CPU_ARM
   427  		mh.subcpu = MACHO_SUBCPU_ARMV7
   428  
   429  	case '6':
   430  		mh.cpu = MACHO_CPU_AMD64
   431  		mh.subcpu = MACHO_SUBCPU_X86
   432  
   433  	case '7':
   434  		mh.cpu = MACHO_CPU_ARM64
   435  		mh.subcpu = MACHO_SUBCPU_ARM64_ALL
   436  
   437  	case '8':
   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 Thearch.Thechar == '5' || 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(INITRND))
   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(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(ms, sect, "__DATA")
   493  	}
   494  
   495  	if Linkmode != LinkExternal {
   496  		switch Thearch.Thechar {
   497  		default:
   498  			Exitf("unknown macho architecture: %v", Thearch.Thechar)
   499  
   500  		case '5':
   501  			ml := newMachoLoad(5, 17+2)          /* unix thread */
   502  			ml.data[0] = 1                       /* thread type */
   503  			ml.data[1] = 17                      /* word count */
   504  			ml.data[2+15] = uint32(Entryvalue()) /* start pc */
   505  
   506  		case '6':
   507  			ml := newMachoLoad(5, 42+2)          /* unix thread */
   508  			ml.data[0] = 4                       /* thread type */
   509  			ml.data[1] = 42                      /* word count */
   510  			ml.data[2+32] = uint32(Entryvalue()) /* start pc */
   511  			ml.data[2+32+1] = uint32(Entryvalue() >> 32)
   512  
   513  		case '7':
   514  			ml := newMachoLoad(5, 68+2)          /* unix thread */
   515  			ml.data[0] = 6                       /* thread type */
   516  			ml.data[1] = 68                      /* word count */
   517  			ml.data[2+64] = uint32(Entryvalue()) /* start pc */
   518  			ml.data[2+64+1] = uint32(Entryvalue() >> 32)
   519  
   520  		case '8':
   521  			ml := newMachoLoad(5, 16+2)          /* unix thread */
   522  			ml.data[0] = 1                       /* thread type */
   523  			ml.data[1] = 16                      /* word count */
   524  			ml.data[2+10] = uint32(Entryvalue()) /* start pc */
   525  		}
   526  	}
   527  
   528  	if Debug['d'] == 0 {
   529  		// must match domacholink below
   530  		s1 := Linklookup(Ctxt, ".machosymtab", 0)
   531  
   532  		s2 := Linklookup(Ctxt, ".linkedit.plt", 0)
   533  		s3 := Linklookup(Ctxt, ".linkedit.got", 0)
   534  		s4 := Linklookup(Ctxt, ".machosymstr", 0)
   535  
   536  		if Linkmode != LinkExternal {
   537  			ms := newMachoSeg("__LINKEDIT", 0)
   538  			ms.vaddr = uint64(va) + uint64(v) + uint64(Rnd(int64(Segdata.Length), int64(INITRND)))
   539  			ms.vsize = uint64(s1.Size) + uint64(s2.Size) + uint64(s3.Size) + uint64(s4.Size)
   540  			ms.fileoffset = uint64(linkoff)
   541  			ms.filesize = ms.vsize
   542  			ms.prot1 = 7
   543  			ms.prot2 = 3
   544  		}
   545  
   546  		ml := newMachoLoad(2, 4)                                   /* LC_SYMTAB */
   547  		ml.data[0] = uint32(linkoff)                               /* symoff */
   548  		ml.data[1] = uint32(nsortsym)                              /* nsyms */
   549  		ml.data[2] = uint32(linkoff + s1.Size + s2.Size + s3.Size) /* stroff */
   550  		ml.data[3] = uint32(s4.Size)                               /* strsize */
   551  
   552  		machodysymtab()
   553  
   554  		if Linkmode != LinkExternal {
   555  			ml := newMachoLoad(14, 6) /* LC_LOAD_DYLINKER */
   556  			ml.data[0] = 12           /* offset to string */
   557  			stringtouint32(ml.data[1:], "/usr/lib/dyld")
   558  
   559  			for i := 0; i < len(dylib); i++ {
   560  				ml = newMachoLoad(12, 4+(uint32(len(dylib[i]))+1+7)/8*2) /* LC_LOAD_DYLIB */
   561  				ml.data[0] = 24                                          /* offset of string from beginning of load */
   562  				ml.data[1] = 0                                           /* time stamp */
   563  				ml.data[2] = 0                                           /* version */
   564  				ml.data[3] = 0                                           /* compatibility version */
   565  				stringtouint32(ml.data[4:], dylib[i])
   566  			}
   567  		}
   568  	}
   569  
   570  	if Linkmode == LinkInternal {
   571  		// For lldb, must say LC_VERSION_MIN_MACOSX or else
   572  		// it won't know that this Mach-O binary is from OS X
   573  		// (could be iOS or WatchOS intead).
   574  		// Go on iOS uses linkmode=external, and linkmode=external
   575  		// adds this itself. So we only need this code for linkmode=internal
   576  		// and we can assume OS X.
   577  		//
   578  		// See golang.org/issues/12941.
   579  		const (
   580  			LC_VERSION_MIN_MACOSX   = 0x24
   581  			LC_VERSION_MIN_IPHONEOS = 0x25
   582  			LC_VERSION_MIN_WATCHOS  = 0x30
   583  		)
   584  		ml := newMachoLoad(LC_VERSION_MIN_MACOSX, 2)
   585  		ml.data[0] = 10<<16 | 7<<8 | 0<<0 // OS X version 10.7.0
   586  		ml.data[1] = 10<<16 | 7<<8 | 0<<0 // SDK 10.7.0
   587  	}
   588  
   589  	// TODO: dwarf headers go in ms too
   590  	if Debug['s'] == 0 {
   591  		dwarfaddmachoheaders(ms)
   592  	}
   593  
   594  	a := machowrite()
   595  	if int32(a) > HEADR {
   596  		Exitf("HEADR too small: %d > %d", a, HEADR)
   597  	}
   598  }
   599  
   600  func symkind(s *LSym) int {
   601  	if s.Type == obj.SDYNIMPORT {
   602  		return SymKindUndef
   603  	}
   604  	if s.Cgoexport != 0 {
   605  		return SymKindExtdef
   606  	}
   607  	return SymKindLocal
   608  }
   609  
   610  func addsym(s *LSym, name string, type_ int, addr int64, size int64, ver int, gotype *LSym) {
   611  	if s == nil {
   612  		return
   613  	}
   614  
   615  	switch type_ {
   616  	default:
   617  		return
   618  
   619  	case 'D', 'B', 'T':
   620  		break
   621  	}
   622  
   623  	if sortsym != nil {
   624  		sortsym[nsortsym] = s
   625  		nkind[symkind(s)]++
   626  	}
   627  
   628  	nsortsym++
   629  }
   630  
   631  type machoscmp []*LSym
   632  
   633  func (x machoscmp) Len() int {
   634  	return len(x)
   635  }
   636  
   637  func (x machoscmp) Swap(i, j int) {
   638  	x[i], x[j] = x[j], x[i]
   639  }
   640  
   641  func (x machoscmp) Less(i, j int) bool {
   642  	s1 := x[i]
   643  	s2 := x[j]
   644  
   645  	k1 := symkind(s1)
   646  	k2 := symkind(s2)
   647  	if k1 != k2 {
   648  		return k1 < k2
   649  	}
   650  
   651  	return s1.Extname < s2.Extname
   652  }
   653  
   654  func machogenasmsym(put func(*LSym, string, int, int64, int64, int, *LSym)) {
   655  	genasmsym(put)
   656  	for s := Ctxt.Allsym; s != nil; s = s.Allsym {
   657  		if s.Type == obj.SDYNIMPORT || s.Type == obj.SHOSTOBJ {
   658  			if s.Reachable {
   659  				put(s, "", 'D', 0, 0, 0, nil)
   660  			}
   661  		}
   662  	}
   663  }
   664  
   665  func machosymorder() {
   666  	// On Mac OS X Mountain Lion, we must sort exported symbols
   667  	// So we sort them here and pre-allocate dynid for them
   668  	// See https://golang.org/issue/4029
   669  	for i := 0; i < len(dynexp); i++ {
   670  		dynexp[i].Reachable = true
   671  	}
   672  	machogenasmsym(addsym)
   673  	sortsym = make([]*LSym, nsortsym)
   674  	nsortsym = 0
   675  	machogenasmsym(addsym)
   676  	sort.Sort(machoscmp(sortsym[:nsortsym]))
   677  	for i := 0; i < nsortsym; i++ {
   678  		sortsym[i].Dynid = int32(i)
   679  	}
   680  }
   681  
   682  func machosymtab() {
   683  	var s *LSym
   684  	var o *LSym
   685  	var p string
   686  
   687  	symtab := Linklookup(Ctxt, ".machosymtab", 0)
   688  	symstr := Linklookup(Ctxt, ".machosymstr", 0)
   689  
   690  	for i := 0; i < nsortsym; i++ {
   691  		s = sortsym[i]
   692  		Adduint32(Ctxt, symtab, uint32(symstr.Size))
   693  
   694  		// Only add _ to C symbols. Go symbols have dot in the name.
   695  		if !strings.Contains(s.Extname, ".") {
   696  			Adduint8(Ctxt, symstr, '_')
   697  		}
   698  
   699  		// replace "·" as ".", because DTrace cannot handle it.
   700  		if !strings.Contains(s.Extname, "·") {
   701  			Addstring(symstr, s.Extname)
   702  		} else {
   703  			for p = s.Extname; p != ""; p = p[1:] {
   704  				if uint8(p[0]) == 0xc2 && uint8((p[1:])[0]) == 0xb7 {
   705  					Adduint8(Ctxt, symstr, '.')
   706  					p = p[1:]
   707  				} else {
   708  					Adduint8(Ctxt, symstr, uint8(p[0]))
   709  				}
   710  			}
   711  
   712  			Adduint8(Ctxt, symstr, '\x00')
   713  		}
   714  
   715  		if s.Type == obj.SDYNIMPORT || s.Type == obj.SHOSTOBJ {
   716  			Adduint8(Ctxt, symtab, 0x01)                // type N_EXT, external symbol
   717  			Adduint8(Ctxt, symtab, 0)                   // no section
   718  			Adduint16(Ctxt, symtab, 0)                  // desc
   719  			adduintxx(Ctxt, symtab, 0, Thearch.Ptrsize) // no value
   720  		} else {
   721  			if s.Cgoexport != 0 {
   722  				Adduint8(Ctxt, symtab, 0x0f)
   723  			} else {
   724  				Adduint8(Ctxt, symtab, 0x0e)
   725  			}
   726  			o = s
   727  			for o.Outer != nil {
   728  				o = o.Outer
   729  			}
   730  			if o.Sect == nil {
   731  				Diag("missing section for %s", s.Name)
   732  				Adduint8(Ctxt, symtab, 0)
   733  			} else {
   734  				Adduint8(Ctxt, symtab, uint8(o.Sect.Extnum))
   735  			}
   736  			Adduint16(Ctxt, symtab, 0) // desc
   737  			adduintxx(Ctxt, symtab, uint64(Symaddr(s)), Thearch.Ptrsize)
   738  		}
   739  	}
   740  }
   741  
   742  func machodysymtab() {
   743  	ml := newMachoLoad(11, 18) /* LC_DYSYMTAB */
   744  
   745  	n := 0
   746  	ml.data[0] = uint32(n)                   /* ilocalsym */
   747  	ml.data[1] = uint32(nkind[SymKindLocal]) /* nlocalsym */
   748  	n += nkind[SymKindLocal]
   749  
   750  	ml.data[2] = uint32(n)                    /* iextdefsym */
   751  	ml.data[3] = uint32(nkind[SymKindExtdef]) /* nextdefsym */
   752  	n += nkind[SymKindExtdef]
   753  
   754  	ml.data[4] = uint32(n)                   /* iundefsym */
   755  	ml.data[5] = uint32(nkind[SymKindUndef]) /* nundefsym */
   756  
   757  	ml.data[6] = 0  /* tocoffset */
   758  	ml.data[7] = 0  /* ntoc */
   759  	ml.data[8] = 0  /* modtaboff */
   760  	ml.data[9] = 0  /* nmodtab */
   761  	ml.data[10] = 0 /* extrefsymoff */
   762  	ml.data[11] = 0 /* nextrefsyms */
   763  
   764  	// must match domacholink below
   765  	s1 := Linklookup(Ctxt, ".machosymtab", 0)
   766  
   767  	s2 := Linklookup(Ctxt, ".linkedit.plt", 0)
   768  	s3 := Linklookup(Ctxt, ".linkedit.got", 0)
   769  	ml.data[12] = uint32(linkoff + s1.Size)       /* indirectsymoff */
   770  	ml.data[13] = uint32((s2.Size + s3.Size) / 4) /* nindirectsyms */
   771  
   772  	ml.data[14] = 0 /* extreloff */
   773  	ml.data[15] = 0 /* nextrel */
   774  	ml.data[16] = 0 /* locreloff */
   775  	ml.data[17] = 0 /* nlocrel */
   776  }
   777  
   778  func Domacholink() int64 {
   779  	machosymtab()
   780  
   781  	// write data that will be linkedit section
   782  	s1 := Linklookup(Ctxt, ".machosymtab", 0)
   783  
   784  	s2 := Linklookup(Ctxt, ".linkedit.plt", 0)
   785  	s3 := Linklookup(Ctxt, ".linkedit.got", 0)
   786  	s4 := Linklookup(Ctxt, ".machosymstr", 0)
   787  
   788  	// Force the linkedit section to end on a 16-byte
   789  	// boundary.  This allows pure (non-cgo) Go binaries
   790  	// to be code signed correctly.
   791  	//
   792  	// Apple's codesign_allocate (a helper utility for
   793  	// the codesign utility) can do this fine itself if
   794  	// it is run on a dynamic Mach-O binary.  However,
   795  	// when it is run on a pure (non-cgo) Go binary, where
   796  	// the linkedit section is mostly empty, it fails to
   797  	// account for the extra padding that it itself adds
   798  	// when adding the LC_CODE_SIGNATURE load command
   799  	// (which must be aligned on a 16-byte boundary).
   800  	//
   801  	// By forcing the linkedit section to end on a 16-byte
   802  	// boundary, codesign_allocate will not need to apply
   803  	// any alignment padding itself, working around the
   804  	// issue.
   805  	for s4.Size%16 != 0 {
   806  		Adduint8(Ctxt, s4, 0)
   807  	}
   808  
   809  	size := int(s1.Size + s2.Size + s3.Size + s4.Size)
   810  
   811  	if size > 0 {
   812  		linkoff = Rnd(int64(uint64(HEADR)+Segtext.Length), int64(INITRND)) + Rnd(int64(Segdata.Filelen), int64(INITRND)) + Rnd(int64(Segdwarf.Filelen), int64(INITRND))
   813  		Cseek(linkoff)
   814  
   815  		Cwrite(s1.P[:s1.Size])
   816  		Cwrite(s2.P[:s2.Size])
   817  		Cwrite(s3.P[:s3.Size])
   818  		Cwrite(s4.P[:s4.Size])
   819  	}
   820  
   821  	return Rnd(int64(size), int64(INITRND))
   822  }
   823  
   824  func machorelocsect(sect *Section, first *LSym) {
   825  	// If main section has no bits, nothing to relocate.
   826  	if sect.Vaddr >= sect.Seg.Vaddr+sect.Seg.Filelen {
   827  		return
   828  	}
   829  
   830  	sect.Reloff = uint64(Cpos())
   831  	var sym *LSym
   832  	for sym = first; sym != nil; sym = sym.Next {
   833  		if !sym.Reachable {
   834  			continue
   835  		}
   836  		if uint64(sym.Value) >= sect.Vaddr {
   837  			break
   838  		}
   839  	}
   840  
   841  	eaddr := int32(sect.Vaddr + sect.Length)
   842  	var r *Reloc
   843  	var ri int
   844  	for ; sym != nil; sym = sym.Next {
   845  		if !sym.Reachable {
   846  			continue
   847  		}
   848  		if sym.Value >= int64(eaddr) {
   849  			break
   850  		}
   851  		Ctxt.Cursym = sym
   852  
   853  		for ri = 0; ri < len(sym.R); ri++ {
   854  			r = &sym.R[ri]
   855  			if r.Done != 0 {
   856  				continue
   857  			}
   858  			if Thearch.Machoreloc1(r, int64(uint64(sym.Value+int64(r.Off))-sect.Vaddr)) < 0 {
   859  				Diag("unsupported obj reloc %d/%d to %s", r.Type, r.Siz, r.Sym.Name)
   860  			}
   861  		}
   862  	}
   863  
   864  	sect.Rellen = uint64(Cpos()) - sect.Reloff
   865  }
   866  
   867  func Machoemitreloc() {
   868  	for Cpos()&7 != 0 {
   869  		Cput(0)
   870  	}
   871  
   872  	machorelocsect(Segtext.Sect, Ctxt.Textp)
   873  	for sect := Segtext.Sect.Next; sect != nil; sect = sect.Next {
   874  		machorelocsect(sect, datap)
   875  	}
   876  	for sect := Segdata.Sect; sect != nil; sect = sect.Next {
   877  		machorelocsect(sect, datap)
   878  	}
   879  	dwarfemitreloc()
   880  }