github.com/rsc/tmp@v0.0.0-20240517235954-6deaab19748b/bootstrap/internal/ld/macho.go (about)

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