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